5 * This work is licensed under the terms of 3-clause BSD license.
6 * See COPYING file in the top-level directory.
8 * recognized asm hint comments:
9 * sctattr - function attributes (see code)
10 * sctend - force end of function/chunk
11 * sctpatch: <p> - replace current asm line with <p>
12 * sctproto: <p> - prototype of ref'd function or struct
13 * sctref - variable is referenced, make global
14 * sctskip_start - start of skipped code chunk (inclusive)
15 * sctskip_end - end of skipped code chunk (inclusive)
25 #include "my_assert.h"
29 #include "protoparse.h"
31 static const char *asmfn;
35 #define anote(fmt, ...) \
36 printf("%s:%d: note: " fmt, asmfn, asmln, ##__VA_ARGS__)
37 #define awarn(fmt, ...) \
38 printf("%s:%d: warning: " fmt, asmfn, asmln, ##__VA_ARGS__)
39 #define aerr(fmt, ...) do { \
40 printf("%s:%d: error: " fmt, asmfn, asmln, ##__VA_ARGS__); \
45 #include "masm_tools.h"
48 OPF_RMD = (1 << 0), /* removed from code generation */
49 OPF_DATA = (1 << 1), /* data processing - writes to dst opr */
50 OPF_FLAGS = (1 << 2), /* sets flags */
51 OPF_JMP = (1 << 3), /* branch, call */
52 OPF_CJMP = (1 << 4), /* cond. branch (cc or jecxz/loop) */
53 OPF_CC = (1 << 5), /* uses flags */
54 OPF_TAIL = (1 << 6), /* ret or tail call */
55 OPF_RSAVE = (1 << 7), /* push/pop is local reg save/load */
56 OPF_REP = (1 << 8), /* prefixed by rep */
57 OPF_REPZ = (1 << 9), /* rep is repe/repz */
58 OPF_REPNZ = (1 << 10), /* rep is repne/repnz */
59 OPF_FARG = (1 << 11), /* push collected as func arg */
60 OPF_FARGNR = (1 << 12), /* push collected as func arg (no reuse) */
61 OPF_EBP_S = (1 << 13), /* ebp used as scratch here, not BP */
62 OPF_DF = (1 << 14), /* DF flag set */
63 OPF_ATAIL = (1 << 15), /* tail call with reused arg frame */
64 OPF_32BIT = (1 << 16), /* enough to do 32bit for this op */
65 OPF_LOCK = (1 << 17), /* op has lock prefix */
66 OPF_VAPUSH = (1 << 18), /* vararg ptr push (as call arg) */
67 OPF_DONE = (1 << 19), /* already fully handled by analysis */
68 OPF_PPUSH = (1 << 20), /* part of complex push-pop graph */
69 OPF_NOREGS = (1 << 21), /* don't track regs of this op */
70 OPF_FPUSH = (1 << 22), /* pushes x87 stack */
71 OPF_FPOP = (1 << 23), /* pops x87 stack */
72 OPF_FPOPP = (1 << 24), /* pops x87 stack twice */
73 OPF_FSHIFT = (1 << 25), /* x87 stack shift is actually needed */
74 OPF_FINT = (1 << 26), /* integer float op arg */
167 // pseudo-ops for lib calls
186 // must be sorted (larger len must be further in enum)
195 #define MAX_EXITS 128
197 #define MAX_OPERANDS 3
200 #define OPR_INIT(type_, lmod_, reg_) \
201 { type_, lmod_, reg_, }
205 enum opr_lenmod lmod;
207 unsigned int is_ptr:1; // pointer in C
208 unsigned int is_array:1; // array in C
209 unsigned int type_from_var:1; // .. in header, sometimes wrong
210 unsigned int size_mismatch:1; // type override differs from C
211 unsigned int size_lt:1; // type override is larger than C
212 unsigned int segment:7; // had segment override (enum segment)
213 const struct parsed_proto *pp; // for OPT_LABEL
220 struct parsed_opr operand[MAX_OPERANDS];
223 unsigned char pfo_inv;
224 unsigned char operand_cnt;
225 unsigned char p_argnum; // arg push: altered before call arg #
226 unsigned char p_arggrp; // arg push: arg group # for above
227 unsigned char p_argpass;// arg push: arg of host func
228 short p_argnext;// arg push: same arg pushed elsewhere or -1
229 int regmask_src; // all referensed regs
231 int pfomask; // flagop: parsed_flag_op that can't be delayed
232 int cc_scratch; // scratch storage during analysis
233 int bt_i; // branch target for branches
234 struct parsed_data *btj;// branch targets for jumptables
235 struct parsed_proto *pp;// parsed_proto for OP_CALL
241 // on start: function/data type hint (sctproto)
243 // (OPF_CC) - points to one of (OPF_FLAGS) that affects cc op
244 // OP_PUSH - points to OP_POP in complex push/pop graph
245 // OP_POP - points to OP_PUSH in simple push/pop pair
246 // OP_FCOM - needed_status_word_bits | (is_z_check << 16)
250 enum opr_lenmod lmod;
257 enum opr_lenmod lmod;
271 struct label_ref *next;
275 IDAFA_BP_FRAME = (1 << 0),
276 IDAFA_LIB_FUNC = (1 << 1),
277 IDAFA_STATIC = (1 << 2),
278 IDAFA_NORETURN = (1 << 3),
279 IDAFA_THUNK = (1 << 4),
280 IDAFA_FPD = (1 << 5),
285 SCTFA_CLEAR_SF = (1 << 0), // clear stack frame
286 SCTFA_CLEAR_REGS = (1 << 1), // clear registers (mask)
287 SCTFA_RM_REGS = (1 << 2), // don't emit regs (mask)
288 SCTFA_NOWARN = (1 << 3), // don't try to detect problems
289 SCTFA_ARGFRAME = (1 << 4), // copy all args to a struct, in order
311 // note: limited to 32k due to p_argnext
313 #define MAX_ARG_GRP 2
315 static struct parsed_op ops[MAX_OPS];
316 static struct parsed_equ *g_eqs;
318 static char *g_labels[MAX_OPS];
319 static struct label_ref g_label_refs[MAX_OPS];
320 static const struct parsed_proto *g_func_pp;
321 static struct parsed_data *g_func_pd;
322 static int g_func_pd_cnt;
323 static int g_func_lmods;
324 static char g_func[256];
325 static char g_comment[256];
326 static int g_bp_frame;
327 static int g_sp_frame;
328 static int g_stack_frame_used;
329 static int g_stack_fsz;
330 static int g_seh_found;
331 static int g_seh_size;
332 static int g_ida_func_attr;
333 static int g_sct_func_attr;
334 static int g_stack_clear_start; // in dwords
335 static int g_stack_clear_len;
336 static int g_regmask_init;
337 static int g_regmask_rm;
338 static int g_skip_func;
339 static int g_allow_regfunc;
340 static int g_allow_user_icall;
341 static int g_nowarn_reguse;
342 static int g_quiet_pp;
343 static int g_header_mode;
345 #define ferr(op_, fmt, ...) do { \
346 printf("%s:%d: error %u: [%s] '%s': " fmt, asmfn, (op_)->asmln, \
347 __LINE__, g_func, dump_op(op_), ##__VA_ARGS__); \
351 #define fnote(op_, fmt, ...) \
352 printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
353 dump_op(op_), ##__VA_ARGS__)
355 #define ferr_assert(op_, cond) do { \
356 if (!(cond)) ferr(op_, "assertion '%s' failed\n", #cond); \
359 #define IS_OP_INDIRECT_CALL(op_) \
360 ((op_)->op == OP_CALL && (op_)->operand[0].type != OPT_LABEL)
362 const char *regs_r32[] = {
363 "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
364 // not r32, but list here for easy parsing and printing
365 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
366 "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"
368 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
369 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
370 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
376 xMM0, xMM1, xMM2, xMM3, // mmx
377 xMM4, xMM5, xMM6, xMM7,
378 xST0, xST1, xST2, xST3, // x87
379 xST4, xST5, xST6, xST7,
382 #define mxAX (1 << xAX)
383 #define mxBX (1 << xBX)
384 #define mxCX (1 << xCX)
385 #define mxDX (1 << xDX)
386 #define mxSP (1 << xSP)
387 #define mxST0 (1 << xST0)
388 #define mxST1 (1 << xST1)
389 #define mxST1_0 (mxST1 | mxST0)
390 #define mxST7_2 (0xfc << xST0)
391 #define mxSTa (0xff << xST0)
393 // possible basic comparison types (without inversion)
394 enum parsed_flag_op {
398 PFO_BE, // 6 CF=1||ZF=1
402 PFO_LE, // e ZF=1||SF!=OF
405 #define PFOB_O (1 << PFO_O)
406 #define PFOB_C (1 << PFO_C)
407 #define PFOB_Z (1 << PFO_Z)
408 #define PFOB_S (1 << PFO_S)
410 static const char *parsed_flag_op_names[] = {
411 "o", "c", "z", "be", "s", "p", "l", "le"
414 static int char_array_i(const char *array[], size_t len, const char *s)
418 for (i = 0; i < len; i++)
425 static void printf_number(char *buf, size_t buf_size,
426 unsigned long number)
428 // output in C-friendly form
429 snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
432 static int check_segment_prefix(const char *s)
434 if (s[0] == 0 || s[1] != 's' || s[2] != ':')
438 case 'c': return SEG_CS;
439 case 'd': return SEG_DS;
440 case 's': return SEG_SS;
441 case 'e': return SEG_ES;
442 case 'f': return SEG_FS;
443 case 'g': return SEG_GS;
448 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
452 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
454 *reg_lmod = OPLM_QWORD;
458 *reg_lmod = OPLM_DWORD;
461 reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
463 *reg_lmod = OPLM_WORD;
466 reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
468 *reg_lmod = OPLM_BYTE;
471 reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
473 *reg_lmod = OPLM_BYTE;
480 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
482 enum opr_lenmod lmod;
495 while (my_isblank(*s))
497 for (; my_issep(*s); d++, s++)
499 while (my_isblank(*s))
503 // skip '?s:' prefixes
504 if (check_segment_prefix(s))
507 s = next_idt(w, sizeof(w), s);
512 reg = parse_reg(&lmod, w);
514 *regmask |= 1 << reg;
518 if ('0' <= w[0] && w[0] <= '9') {
519 number = parse_number(w, 0);
520 printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
524 // probably some label/identifier - pass
527 snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
531 strcpy(name, cvtbuf);
536 static int is_reg_in_str(const char *s)
540 if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
543 for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
544 if (!strncmp(s, regs_r32[i], 3))
550 static const char *parse_stack_el(const char *name, char *extra_reg,
551 int *base_val, int early_try)
553 const char *p, *p2, *s;
559 if (g_bp_frame || early_try)
562 if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
564 if (extra_reg != NULL) {
565 strncpy(extra_reg, name, 3);
570 if (IS_START(p, "ebp+")) {
574 if (p2 != NULL && is_reg_in_str(p)) {
575 if (extra_reg != NULL) {
576 strncpy(extra_reg, p, p2 - p);
577 extra_reg[p2 - p] = 0;
582 if (!('0' <= *p && *p <= '9'))
589 if (!IS_START(name, "esp+"))
595 if (is_reg_in_str(s)) {
596 if (extra_reg != NULL) {
597 strncpy(extra_reg, s, p - s);
598 extra_reg[p - s] = 0;
603 aerr("%s IDA stackvar not set?\n", __func__);
605 if ('0' <= *s && *s <= '9') {
606 if (s[0] == '0' && s[1] == 'x')
609 if (len < sizeof(buf) - 1) {
610 strncpy(buf, s, len);
613 val = strtol(buf, &endp, 16);
614 if (val == 0 || *endp != 0 || errno != 0) {
615 aerr("%s num parse fail for '%s'\n", __func__, buf);
622 // probably something like [esp+arg_4+2]
630 if ('0' <= *p && *p <= '9')
633 if (base_val != NULL)
638 static int guess_lmod_from_name(struct parsed_opr *opr)
640 if (IS_START(opr->name, "dword_") || IS_START(opr->name, "off_")) {
641 opr->lmod = OPLM_DWORD;
644 if (IS_START(opr->name, "word_")) {
645 opr->lmod = OPLM_WORD;
648 if (IS_START(opr->name, "byte_")) {
649 opr->lmod = OPLM_BYTE;
652 if (IS_START(opr->name, "qword_")) {
653 opr->lmod = OPLM_QWORD;
659 static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
660 const struct parsed_type *c_type)
662 static const char *qword_types[] = {
663 "uint64_t", "int64_t", "__int64",
665 static const char *dword_types[] = {
666 "uint32_t", "int", "_DWORD", "UINT_PTR", "DWORD",
667 "WPARAM", "LPARAM", "UINT", "__int32",
668 "LONG", "HIMC", "BOOL", "size_t",
671 static const char *word_types[] = {
672 "uint16_t", "int16_t", "_WORD", "WORD",
673 "unsigned __int16", "__int16",
675 static const char *byte_types[] = {
676 "uint8_t", "int8_t", "char",
677 "unsigned __int8", "__int8", "BYTE", "_BYTE",
679 // structures.. deal the same as with _UNKNOWN for now
685 if (c_type->is_ptr) {
690 n = skip_type_mod(c_type->name);
692 for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
693 if (IS(n, dword_types[i])) {
699 for (i = 0; i < ARRAY_SIZE(word_types); i++) {
700 if (IS(n, word_types[i])) {
706 for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
707 if (IS(n, byte_types[i])) {
713 for (i = 0; i < ARRAY_SIZE(qword_types); i++) {
714 if (IS(n, qword_types[i])) {
723 static char *default_cast_to(char *buf, size_t buf_size,
724 struct parsed_opr *opr)
728 if (!opr->is_ptr || strchr(opr->name, '['))
730 if (opr->pp == NULL || opr->pp->type.name == NULL
733 snprintf(buf, buf_size, "%s", "(void *)");
737 snprintf(buf, buf_size, "(%s)", opr->pp->type.name);
741 static enum opr_type lmod_from_directive(const char *d)
745 else if (IS(d, "dw"))
747 else if (IS(d, "db"))
750 aerr("unhandled directive: '%s'\n", d);
754 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
760 *regmask |= 1 << reg;
763 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
766 static int parse_operand(struct parsed_opr *opr,
767 int *regmask, int *regmask_indirect,
768 char words[16][256], int wordc, int w, unsigned int op_flags)
770 const struct parsed_proto *pp = NULL;
771 enum opr_lenmod tmplmod;
772 unsigned long number;
780 aerr("parse_operand w %d, wordc %d\n", w, wordc);
784 for (i = w; i < wordc; i++) {
785 len = strlen(words[i]);
786 if (words[i][len - 1] == ',') {
787 words[i][len - 1] = 0;
793 wordc_in = wordc - w;
795 if ((op_flags & OPF_JMP) && wordc_in > 0
796 && !('0' <= words[w][0] && words[w][0] <= '9'))
798 const char *label = NULL;
800 if (wordc_in == 3 && !strncmp(words[w], "near", 4)
801 && IS(words[w + 1], "ptr"))
802 label = words[w + 2];
803 else if (wordc_in == 2 && IS(words[w], "short"))
804 label = words[w + 1];
805 else if (wordc_in == 1
806 && strchr(words[w], '[') == NULL
807 && parse_reg(&tmplmod, words[w]) < 0)
811 opr->type = OPT_LABEL;
812 ret = check_segment_prefix(label);
817 strcpy(opr->name, label);
823 if (IS(words[w + 1], "ptr")) {
824 if (IS(words[w], "dword"))
825 opr->lmod = OPLM_DWORD;
826 else if (IS(words[w], "word"))
827 opr->lmod = OPLM_WORD;
828 else if (IS(words[w], "byte"))
829 opr->lmod = OPLM_BYTE;
830 else if (IS(words[w], "qword"))
831 opr->lmod = OPLM_QWORD;
833 aerr("type parsing failed\n");
835 wordc_in = wordc - w;
840 if (IS(words[w], "offset")) {
841 opr->type = OPT_OFFSET;
842 opr->lmod = OPLM_DWORD;
843 strcpy(opr->name, words[w + 1]);
844 pp = proto_parse(g_fhdr, opr->name, 1);
847 if (IS(words[w], "(offset")) {
848 p = strchr(words[w + 1], ')');
850 aerr("parse of bracketed offset failed\n");
852 opr->type = OPT_OFFSET;
853 strcpy(opr->name, words[w + 1]);
859 aerr("parse_operand 1 word expected\n");
861 ret = check_segment_prefix(words[w]);
864 memmove(words[w], words[w] + 3, strlen(words[w]) - 2);
865 if (ret == SEG_FS && IS(words[w], "0"))
868 strcpy(opr->name, words[w]);
870 if (words[w][0] == '[') {
871 opr->type = OPT_REGMEM;
872 ret = sscanf(words[w], "[%[^]]]", opr->name);
874 aerr("[] parse failure\n");
876 parse_indmode(opr->name, regmask_indirect, 1);
877 if (opr->lmod == OPLM_UNSPEC
878 && parse_stack_el(opr->name, NULL, NULL, 1))
881 struct parsed_equ *eq =
882 equ_find(NULL, parse_stack_el(opr->name, NULL, NULL, 1), &i);
884 opr->lmod = eq->lmod;
886 // might be unaligned access
887 g_func_lmods |= 1 << OPLM_BYTE;
891 else if (strchr(words[w], '[')) {
893 p = strchr(words[w], '[');
894 opr->type = OPT_REGMEM;
895 parse_indmode(p, regmask_indirect, 0);
896 strncpy(buf, words[w], p - words[w]);
897 buf[p - words[w]] = 0;
898 pp = proto_parse(g_fhdr, buf, 1);
901 else if (('0' <= words[w][0] && words[w][0] <= '9')
902 || words[w][0] == '-')
904 number = parse_number(words[w], 0);
905 opr->type = OPT_CONST;
907 printf_number(opr->name, sizeof(opr->name), number);
911 ret = parse_reg(&tmplmod, opr->name);
913 setup_reg_opr(opr, ret, tmplmod, regmask);
917 // most likely var in data segment
918 opr->type = OPT_LABEL;
919 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
923 if (pp->is_fptr || pp->is_func) {
924 opr->lmod = OPLM_DWORD;
928 tmplmod = OPLM_UNSPEC;
929 if (!guess_lmod_from_c_type(&tmplmod, &pp->type))
930 anote("unhandled C type '%s' for '%s'\n",
931 pp->type.name, opr->name);
933 if (opr->lmod == OPLM_UNSPEC) {
935 opr->type_from_var = 1;
937 else if (opr->lmod != tmplmod) {
938 opr->size_mismatch = 1;
939 if (tmplmod < opr->lmod)
942 opr->is_ptr = pp->type.is_ptr;
944 opr->is_array = pp->type.is_array;
948 if (opr->lmod == OPLM_UNSPEC)
949 guess_lmod_from_name(opr);
953 static const struct {
958 { "repe", OPF_REP|OPF_REPZ },
959 { "repz", OPF_REP|OPF_REPZ },
960 { "repne", OPF_REP|OPF_REPNZ },
961 { "repnz", OPF_REP|OPF_REPNZ },
962 { "lock", OPF_LOCK },
965 #define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
967 static const struct {
970 unsigned short minopr;
971 unsigned short maxopr;
974 unsigned char pfo_inv;
976 { "nop", OP_NOP, 0, 0, 0 },
977 { "push", OP_PUSH, 1, 1, 0 },
978 { "pop", OP_POP, 1, 1, OPF_DATA },
979 { "pusha",OP_PUSHA, 0, 0, 0 },
980 { "popa", OP_POPA, 0, 0, OPF_DATA },
981 { "leave",OP_LEAVE, 0, 0, OPF_DATA },
982 { "mov" , OP_MOV, 2, 2, OPF_DATA },
983 { "lea", OP_LEA, 2, 2, OPF_DATA },
984 { "movzx",OP_MOVZX, 2, 2, OPF_DATA },
985 { "movsx",OP_MOVSX, 2, 2, OPF_DATA },
986 { "xchg", OP_XCHG, 2, 2, OPF_DATA },
987 { "not", OP_NOT, 1, 1, OPF_DATA },
988 { "xlat", OP_XLAT, 0, 0, OPF_DATA },
989 { "cdq", OP_CDQ, 0, 0, OPF_DATA },
990 { "bswap",OP_BSWAP, 1, 1, OPF_DATA },
991 { "lodsb",OP_LODS, 0, 0, OPF_DATA },
992 { "lodsw",OP_LODS, 0, 0, OPF_DATA },
993 { "lodsd",OP_LODS, 0, 0, OPF_DATA },
994 { "stosb",OP_STOS, 0, 0, OPF_DATA },
995 { "stosw",OP_STOS, 0, 0, OPF_DATA },
996 { "stosd",OP_STOS, 0, 0, OPF_DATA },
997 { "movsb",OP_MOVS, 0, 0, OPF_DATA },
998 { "movsw",OP_MOVS, 0, 0, OPF_DATA },
999 { "movsd",OP_MOVS, 0, 0, OPF_DATA },
1000 { "cmpsb",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
1001 { "cmpsw",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
1002 { "cmpsd",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
1003 { "scasb",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
1004 { "scasw",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
1005 { "scasd",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
1006 { "rdtsc",OP_RDTSC, 0, 0, OPF_DATA },
1007 { "cpuid",OP_CPUID, 0, 0, OPF_DATA },
1008 { "std", OP_STD, 0, 0, OPF_DATA }, // special flag
1009 { "cld", OP_CLD, 0, 0, OPF_DATA },
1010 { "add", OP_ADD, 2, 2, OPF_DATA|OPF_FLAGS },
1011 { "sub", OP_SUB, 2, 2, OPF_DATA|OPF_FLAGS },
1012 { "and", OP_AND, 2, 2, OPF_DATA|OPF_FLAGS },
1013 { "or", OP_OR, 2, 2, OPF_DATA|OPF_FLAGS },
1014 { "xor", OP_XOR, 2, 2, OPF_DATA|OPF_FLAGS },
1015 { "shl", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
1016 { "shr", OP_SHR, 2, 2, OPF_DATA|OPF_FLAGS },
1017 { "sal", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
1018 { "sar", OP_SAR, 2, 2, OPF_DATA|OPF_FLAGS },
1019 { "shld", OP_SHLD, 3, 3, OPF_DATA|OPF_FLAGS },
1020 { "shrd", OP_SHRD, 3, 3, OPF_DATA|OPF_FLAGS },
1021 { "rol", OP_ROL, 2, 2, OPF_DATA|OPF_FLAGS },
1022 { "ror", OP_ROR, 2, 2, OPF_DATA|OPF_FLAGS },
1023 { "rcl", OP_RCL, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1024 { "rcr", OP_RCR, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1025 { "adc", OP_ADC, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1026 { "sbb", OP_SBB, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1027 { "bsf", OP_BSF, 2, 2, OPF_DATA|OPF_FLAGS },
1028 { "bsr", OP_BSR, 2, 2, OPF_DATA|OPF_FLAGS },
1029 { "inc", OP_INC, 1, 1, OPF_DATA|OPF_FLAGS },
1030 { "dec", OP_DEC, 1, 1, OPF_DATA|OPF_FLAGS },
1031 { "neg", OP_NEG, 1, 1, OPF_DATA|OPF_FLAGS },
1032 { "mul", OP_MUL, 1, 1, OPF_DATA|OPF_FLAGS },
1033 { "imul", OP_IMUL, 1, 3, OPF_DATA|OPF_FLAGS },
1034 { "div", OP_DIV, 1, 1, OPF_DATA|OPF_FLAGS },
1035 { "idiv", OP_IDIV, 1, 1, OPF_DATA|OPF_FLAGS },
1036 { "test", OP_TEST, 2, 2, OPF_FLAGS },
1037 { "cmp", OP_CMP, 2, 2, OPF_FLAGS },
1038 { "retn", OP_RET, 0, 1, OPF_TAIL },
1039 { "call", OP_CALL, 1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
1040 { "jmp", OP_JMP, 1, 1, OPF_JMP },
1041 { "jecxz",OP_JECXZ, 1, 1, OPF_JMP|OPF_CJMP },
1042 { "loop", OP_LOOP, 1, 1, OPF_JMP|OPF_CJMP|OPF_DATA },
1043 { "jo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 0 }, // 70 OF=1
1044 { "jno", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 1 }, // 71 OF=0
1045 { "jc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72 CF=1
1046 { "jb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72
1047 { "jnc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73 CF=0
1048 { "jnb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1049 { "jae", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1050 { "jz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74 ZF=1
1051 { "je", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74
1052 { "jnz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75 ZF=0
1053 { "jne", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75
1054 { "jbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76 CF=1||ZF=1
1055 { "jna", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76
1056 { "ja", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77 CF=0&&ZF=0
1057 { "jnbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77
1058 { "js", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 0 }, // 78 SF=1
1059 { "jns", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 1 }, // 79 SF=0
1060 { "jp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a PF=1
1061 { "jpe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a
1062 { "jnp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b PF=0
1063 { "jpo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b
1064 { "jl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c SF!=OF
1065 { "jnge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c
1066 { "jge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d SF=OF
1067 { "jnl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d
1068 { "jle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e ZF=1||SF!=OF
1069 { "jng", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e
1070 { "jg", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f ZF=0&&SF=OF
1071 { "jnle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f
1072 { "seto", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 0 },
1073 { "setno", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 1 },
1074 { "setc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1075 { "setb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1076 { "setnc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1077 { "setae", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1078 { "setnb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1079 { "setz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1080 { "sete", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1081 { "setnz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1082 { "setne", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1083 { "setbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1084 { "setna", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1085 { "seta", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1086 { "setnbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1087 { "sets", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 0 },
1088 { "setns", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 1 },
1089 { "setp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1090 { "setpe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1091 { "setnp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1092 { "setpo", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1093 { "setl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1094 { "setnge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1095 { "setge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1096 { "setnl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1097 { "setle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1098 { "setng", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1099 { "setg", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1100 { "setnle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1102 { "fld", OP_FLD, 1, 1, OPF_FPUSH },
1103 { "fild", OP_FILD, 1, 1, OPF_FPUSH|OPF_FINT },
1104 { "fld1", OP_FLDc, 0, 0, OPF_FPUSH },
1105 { "fldl2t", OP_FLDc, 0, 0, OPF_FPUSH },
1106 { "fldl2e", OP_FLDc, 0, 0, OPF_FPUSH },
1107 { "fldpi", OP_FLDc, 0, 0, OPF_FPUSH },
1108 { "fldlg2", OP_FLDc, 0, 0, OPF_FPUSH },
1109 { "fldln2", OP_FLDc, 0, 0, OPF_FPUSH },
1110 { "fldz", OP_FLDc, 0, 0, OPF_FPUSH },
1111 { "fst", OP_FST, 1, 1, 0 },
1112 { "fstp", OP_FST, 1, 1, OPF_FPOP },
1113 { "fist", OP_FIST, 1, 1, OPF_FINT },
1114 { "fistp", OP_FIST, 1, 1, OPF_FPOP|OPF_FINT },
1115 { "fadd", OP_FADD, 0, 2, 0 },
1116 { "faddp", OP_FADD, 0, 2, OPF_FPOP },
1117 { "fdiv", OP_FDIV, 0, 2, 0 },
1118 { "fdivp", OP_FDIV, 0, 2, OPF_FPOP },
1119 { "fmul", OP_FMUL, 0, 2, 0 },
1120 { "fmulp", OP_FMUL, 0, 2, OPF_FPOP },
1121 { "fsub", OP_FSUB, 0, 2, 0 },
1122 { "fsubp", OP_FSUB, 0, 2, OPF_FPOP },
1123 { "fdivr", OP_FDIVR, 0, 2, 0 },
1124 { "fdivrp", OP_FDIVR, 0, 2, OPF_FPOP },
1125 { "fsubr", OP_FSUBR, 0, 2, 0 },
1126 { "fsubrp", OP_FSUBR, 0, 2, OPF_FPOP },
1127 { "fiadd", OP_FIADD, 1, 1, OPF_FINT },
1128 { "fidiv", OP_FIDIV, 1, 1, OPF_FINT },
1129 { "fimul", OP_FIMUL, 1, 1, OPF_FINT },
1130 { "fisub", OP_FISUB, 1, 1, OPF_FINT },
1131 { "fidivr", OP_FIDIVR, 1, 1, OPF_FINT },
1132 { "fisubr", OP_FISUBR, 1, 1, OPF_FINT },
1133 { "fcom", OP_FCOM, 0, 1, 0 },
1134 { "fcomp", OP_FCOM, 0, 1, OPF_FPOP },
1135 { "fcompp", OP_FCOM, 0, 0, OPF_FPOPP },
1136 { "fucom", OP_FCOM, 0, 1, 0 },
1137 { "fucomp", OP_FCOM, 0, 1, OPF_FPOP },
1138 { "fucompp",OP_FCOM, 0, 0, OPF_FPOPP },
1139 { "fnstsw", OP_FNSTSW, 1, 1, OPF_DATA },
1140 { "fchs", OP_FCHS, 0, 0, 0 },
1141 { "fcos", OP_FCOS, 0, 0, 0 },
1142 { "fpatan", OP_FPATAN, 0, 0, OPF_FPOP },
1143 { "fptan", OP_FPTAN, 0, 0, OPF_FPUSH },
1144 { "fsin", OP_FSIN, 0, 0, 0 },
1145 { "fsqrt", OP_FSQRT, 0, 0, 0 },
1146 { "fxch", OP_FXCH, 1, 1, 0 },
1147 { "fyl2x", OP_FYL2X, 0, 0, OPF_FPOP },
1149 { "emms", OP_EMMS, 0, 0, OPF_DATA },
1150 { "movq", OP_MOV, 2, 2, OPF_DATA },
1151 // pseudo-ops for lib calls
1152 { "_allshl",OPP_ALLSHL },
1153 { "_allshr",OPP_ALLSHR },
1154 { "_ftol", OPP_FTOL },
1155 { "_CIpow", OPP_CIPOW },
1156 { "abort", OPP_ABORT },
1161 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
1163 enum opr_lenmod lmod = OPLM_UNSPEC;
1164 int prefix_flags = 0;
1172 for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
1173 if (IS(words[w], pref_table[i].name)) {
1174 prefix_flags = pref_table[i].flags;
1181 aerr("lone prefix: '%s'\n", words[0]);
1186 for (i = 0; i < ARRAY_SIZE(op_table); i++) {
1187 if (IS(words[w], op_table[i].name))
1191 if (i == ARRAY_SIZE(op_table)) {
1193 aerr("unhandled op: '%s'\n", words[0]);
1198 op->op = op_table[i].op;
1199 op->flags = op_table[i].flags | prefix_flags;
1200 op->pfo = op_table[i].pfo;
1201 op->pfo_inv = op_table[i].pfo_inv;
1202 op->regmask_src = op->regmask_dst = 0;
1205 if (op->op == OP_UD2)
1208 for (opr = 0; opr < op_table[i].maxopr; opr++) {
1209 if (opr >= op_table[i].minopr && w >= wordc)
1212 regmask = regmask_ind = 0;
1213 w = parse_operand(&op->operand[opr], ®mask, ®mask_ind,
1214 words, wordc, w, op->flags);
1216 if (opr == 0 && (op->flags & OPF_DATA))
1217 op->regmask_dst = regmask;
1219 op->regmask_src |= regmask;
1220 op->regmask_src |= regmask_ind;
1222 if (op->operand[opr].lmod != OPLM_UNSPEC)
1223 g_func_lmods |= 1 << op->operand[opr].lmod;
1227 aerr("parse_op %s incomplete: %d/%d\n",
1228 words[0], w, wordc);
1231 op->operand_cnt = opr;
1232 if (!strncmp(op_table[i].name, "set", 3))
1233 op->operand[0].lmod = OPLM_BYTE;
1236 // first operand is not dst
1239 op->regmask_src |= op->regmask_dst;
1240 op->regmask_dst = 0;
1243 // first operand is src too
1256 op->regmask_src |= op->regmask_dst;
1261 op->regmask_src |= op->regmask_dst;
1262 op->regmask_dst |= op->regmask_src;
1268 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1269 && op->operand[0].lmod == op->operand[1].lmod
1270 && op->operand[0].reg == op->operand[1].reg
1271 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1273 op->regmask_src = 0;
1276 op->regmask_src |= op->regmask_dst;
1279 // ops with implicit argumets
1281 op->operand_cnt = 2;
1282 setup_reg_opr(&op->operand[0], xAX, OPLM_BYTE, &op->regmask_src);
1283 op->regmask_dst = op->regmask_src;
1284 setup_reg_opr(&op->operand[1], xBX, OPLM_DWORD, &op->regmask_src);
1288 op->operand_cnt = 2;
1289 setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
1290 setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
1296 if (words[op_w][4] == 'b')
1298 else if (words[op_w][4] == 'w')
1300 else if (words[op_w][4] == 'd')
1303 op->regmask_src = 0;
1304 setup_reg_opr(&op->operand[j++], op->op == OP_LODS ? xSI : xDI,
1305 OPLM_DWORD, &op->regmask_src);
1306 op->regmask_dst = op->regmask_src;
1307 setup_reg_opr(&op->operand[j++], xAX, lmod,
1308 op->op == OP_LODS ? &op->regmask_dst : &op->regmask_src);
1309 if (op->flags & OPF_REP) {
1310 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1311 op->regmask_dst |= 1 << xCX;
1313 op->operand_cnt = j;
1318 if (words[op_w][4] == 'b')
1320 else if (words[op_w][4] == 'w')
1322 else if (words[op_w][4] == 'd')
1325 op->regmask_src = 0;
1326 // note: lmod is not correct, don't have where to place it
1327 setup_reg_opr(&op->operand[j++], xDI, lmod, &op->regmask_src);
1328 setup_reg_opr(&op->operand[j++], xSI, OPLM_DWORD, &op->regmask_src);
1329 if (op->flags & OPF_REP)
1330 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1331 op->operand_cnt = j;
1332 op->regmask_dst = op->regmask_src;
1336 op->regmask_dst = mxAX | mxDX;
1340 // for now, ignore ecx dep for eax={4,7,b,d}
1341 op->regmask_src = mxAX;
1342 op->regmask_dst = mxAX | mxBX | mxCX | mxDX;
1346 op->regmask_dst = 1 << xCX;
1349 op->operand_cnt = 2;
1350 op->regmask_src = 1 << xCX;
1351 op->operand[1].type = OPT_REG;
1352 op->operand[1].reg = xCX;
1353 op->operand[1].lmod = OPLM_DWORD;
1357 if (op->operand_cnt == 2) {
1358 if (op->operand[0].type != OPT_REG)
1359 aerr("reg expected\n");
1360 op->regmask_src |= 1 << op->operand[0].reg;
1362 if (op->operand_cnt != 1)
1367 if (op->operand[0].lmod == OPLM_UNSPEC)
1368 op->operand[0].lmod = OPLM_DWORD;
1369 op->regmask_src = mxAX | op->regmask_dst;
1370 op->regmask_dst = mxAX;
1371 if (op->operand[0].lmod != OPLM_BYTE)
1372 op->regmask_dst |= mxDX;
1377 // we could set up operands for edx:eax, but there is no real need to
1378 // (see is_opr_modified())
1379 if (op->operand[0].lmod == OPLM_UNSPEC)
1380 op->operand[0].lmod = OPLM_DWORD;
1381 op->regmask_src = mxAX | op->regmask_dst;
1382 op->regmask_dst = mxAX;
1383 if (op->operand[0].lmod != OPLM_BYTE) {
1384 op->regmask_src |= mxDX;
1385 op->regmask_dst |= mxDX;
1394 op->regmask_src |= op->regmask_dst;
1395 if (op->operand[1].lmod == OPLM_UNSPEC)
1396 op->operand[1].lmod = OPLM_BYTE;
1401 op->regmask_src |= op->regmask_dst;
1402 if (op->operand[2].lmod == OPLM_UNSPEC)
1403 op->operand[2].lmod = OPLM_BYTE;
1407 op->regmask_src |= op->regmask_dst;
1408 op->regmask_dst = 0;
1409 if (op->operand[0].lmod == OPLM_UNSPEC
1410 && (op->operand[0].type == OPT_CONST
1411 || op->operand[0].type == OPT_OFFSET
1412 || op->operand[0].type == OPT_LABEL))
1413 op->operand[0].lmod = OPLM_DWORD;
1419 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1420 && op->operand[0].lmod == op->operand[1].lmod
1421 && op->operand[0].reg == op->operand[1].reg
1422 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1424 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1425 op->regmask_src = op->regmask_dst = 0;
1430 if (op->operand[0].type == OPT_REG
1431 && op->operand[1].type == OPT_REGMEM)
1434 snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1435 if (IS(buf, op->operand[1].name))
1436 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1441 // needed because of OPF_DATA
1442 op->regmask_src |= op->regmask_dst;
1443 // trashed regs must be explicitly detected later
1444 op->regmask_dst = 0;
1448 op->regmask_dst = (1 << xBP) | (1 << xSP);
1449 op->regmask_src = 1 << xBP;
1454 op->regmask_dst |= mxST0;
1458 op->regmask_dst |= mxST0;
1459 if (IS(words[op_w] + 3, "1"))
1460 op->operand[0].val = X87_CONST_1;
1461 else if (IS(words[op_w] + 3, "l2t"))
1462 op->operand[0].val = X87_CONST_L2T;
1463 else if (IS(words[op_w] + 3, "l2e"))
1464 op->operand[0].val = X87_CONST_L2E;
1465 else if (IS(words[op_w] + 3, "pi"))
1466 op->operand[0].val = X87_CONST_PI;
1467 else if (IS(words[op_w] + 3, "lg2"))
1468 op->operand[0].val = X87_CONST_LG2;
1469 else if (IS(words[op_w] + 3, "ln2"))
1470 op->operand[0].val = X87_CONST_LN2;
1471 else if (IS(words[op_w] + 3, "z"))
1472 op->operand[0].val = X87_CONST_Z;
1474 aerr("fld what?\n");
1479 op->regmask_src |= mxST0;
1488 op->regmask_src |= mxST0;
1489 if (op->operand_cnt == 2)
1490 op->regmask_src |= op->regmask_dst;
1491 else if (op->operand_cnt == 1) {
1492 memcpy(&op->operand[1], &op->operand[0], sizeof(op->operand[1]));
1493 op->operand[0].type = OPT_REG;
1494 op->operand[0].lmod = OPLM_QWORD;
1495 op->operand[0].reg = xST0;
1496 op->regmask_dst |= mxST0;
1499 // IDA doesn't use this
1500 aerr("no operands?\n");
1514 op->regmask_src |= mxST0;
1515 op->regmask_dst |= mxST0;
1520 op->regmask_src |= mxST0 | mxST1;
1521 op->regmask_dst |= mxST0;
1529 op->regmask_src |= mxST0;
1530 if (op->operand_cnt == 0) {
1531 op->operand_cnt = 1;
1532 op->operand[0].type = OPT_REG;
1533 op->operand[0].lmod = OPLM_QWORD;
1534 op->operand[0].reg = xST1;
1535 op->regmask_src |= mxST1;
1543 if (op->operand[0].type == OPT_REG
1544 && op->operand[1].type == OPT_CONST)
1546 struct parsed_opr *op1 = &op->operand[1];
1547 if ((op->op == OP_AND && op1->val == 0)
1550 || (op->operand[0].lmod == OPLM_WORD && op1->val == 0xffff)
1551 || (op->operand[0].lmod == OPLM_BYTE && op1->val == 0xff))))
1553 op->regmask_src = 0;
1558 static const char *op_name(struct parsed_op *po)
1560 static char buf[16];
1564 if (po->op == OP_JCC || po->op == OP_SCC) {
1566 *p++ = (po->op == OP_JCC) ? 'j' : 's';
1569 strcpy(p, parsed_flag_op_names[po->pfo]);
1573 for (i = 0; i < ARRAY_SIZE(op_table); i++)
1574 if (op_table[i].op == po->op)
1575 return op_table[i].name;
1581 static const char *dump_op(struct parsed_op *po)
1583 static char out[128];
1590 snprintf(out, sizeof(out), "%s", op_name(po));
1591 for (i = 0; i < po->operand_cnt; i++) {
1595 snprintf(p, sizeof(out) - (p - out),
1596 po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1597 po->operand[i].name);
1603 static const char *lmod_type_u(struct parsed_op *po,
1604 enum opr_lenmod lmod)
1616 ferr(po, "invalid lmod: %d\n", lmod);
1617 return "(_invalid_)";
1621 static const char *lmod_cast_u(struct parsed_op *po,
1622 enum opr_lenmod lmod)
1634 ferr(po, "invalid lmod: %d\n", lmod);
1635 return "(_invalid_)";
1639 static const char *lmod_cast_u_ptr(struct parsed_op *po,
1640 enum opr_lenmod lmod)
1652 ferr(po, "invalid lmod: %d\n", lmod);
1653 return "(_invalid_)";
1657 static const char *lmod_cast_s(struct parsed_op *po,
1658 enum opr_lenmod lmod)
1670 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1671 return "(_invalid_)";
1675 static const char *lmod_cast(struct parsed_op *po,
1676 enum opr_lenmod lmod, int is_signed)
1679 lmod_cast_s(po, lmod) :
1680 lmod_cast_u(po, lmod);
1683 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1695 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1700 static const char *opr_name(struct parsed_op *po, int opr_num)
1702 if (opr_num >= po->operand_cnt)
1703 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1704 return po->operand[opr_num].name;
1707 static unsigned int opr_const(struct parsed_op *po, int opr_num)
1709 if (opr_num >= po->operand_cnt)
1710 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1711 if (po->operand[opr_num].type != OPT_CONST)
1712 ferr(po, "opr %d: const expected\n", opr_num);
1713 return po->operand[opr_num].val;
1716 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1718 if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
1719 ferr(po, "invalid reg: %d\n", popr->reg);
1720 return regs_r32[popr->reg];
1723 static int check_simple_cast(const char *cast, int *bits, int *is_signed)
1725 if (IS_START(cast, "(s8)") || IS_START(cast, "(u8)"))
1727 else if (IS_START(cast, "(s16)") || IS_START(cast, "(u16)"))
1729 else if (IS_START(cast, "(s32)") || IS_START(cast, "(u32)"))
1731 else if (IS_START(cast, "(s64)") || IS_START(cast, "(u64)"))
1736 *is_signed = cast[1] == 's' ? 1 : 0;
1740 static int check_deref_cast(const char *cast, int *bits)
1742 if (IS_START(cast, "*(u8 *)"))
1744 else if (IS_START(cast, "*(u16 *)"))
1746 else if (IS_START(cast, "*(u32 *)"))
1748 else if (IS_START(cast, "*(u64 *)"))
1756 // cast1 is the "final" cast
1757 static const char *simplify_cast(const char *cast1, const char *cast2)
1759 static char buf[256];
1767 if (IS(cast1, cast2))
1770 if (check_simple_cast(cast1, &bits1, &s1) == 0
1771 && check_simple_cast(cast2, &bits2, &s2) == 0)
1776 if (check_simple_cast(cast1, &bits1, &s1) == 0
1777 && check_deref_cast(cast2, &bits2) == 0)
1779 if (bits1 == bits2) {
1780 snprintf(buf, sizeof(buf), "*(%c%d *)", s1 ? 's' : 'u', bits1);
1785 if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1788 snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1792 static const char *simplify_cast_num(const char *cast, unsigned int val)
1794 if (IS(cast, "(u8)") && val < 0x100)
1796 if (IS(cast, "(s8)") && val < 0x80)
1798 if (IS(cast, "(u16)") && val < 0x10000)
1800 if (IS(cast, "(s16)") && val < 0x8000)
1802 if (IS(cast, "(s32)") && val < 0x80000000)
1808 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1817 namelen = strlen(name);
1819 p = strpbrk(name, "+-");
1823 ferr(po, "equ parse failed for '%s'\n", name);
1826 *extra_offs = strtol(p, &endp, 16);
1827 if (*endp != 0 || errno != 0)
1828 ferr(po, "equ parse failed for '%s'\n", name);
1831 for (i = 0; i < g_eqcnt; i++)
1832 if (strncmp(g_eqs[i].name, name, namelen) == 0
1833 && g_eqs[i].name[namelen] == 0)
1837 ferr(po, "unresolved equ name: '%s'\n", name);
1844 static int is_stack_access(struct parsed_op *po,
1845 const struct parsed_opr *popr)
1847 return (parse_stack_el(popr->name, NULL, NULL, 0)
1848 || (g_bp_frame && !(po->flags & OPF_EBP_S)
1849 && IS_START(popr->name, "ebp")));
1852 static void parse_stack_access(struct parsed_op *po,
1853 const char *name, char *ofs_reg, int *offset_out,
1854 int *stack_ra_out, const char **bp_arg_out, int is_lea)
1856 const char *bp_arg = "";
1857 const char *p = NULL;
1858 struct parsed_equ *eq;
1865 if (IS_START(name, "ebp-")
1866 || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1869 if (IS_START(p, "0x"))
1872 offset = strtoul(p, &endp, 16);
1875 if (*endp != 0 || errno != 0)
1876 ferr(po, "ebp- parse of '%s' failed\n", name);
1879 bp_arg = parse_stack_el(name, ofs_reg, NULL, 0);
1880 eq = equ_find(po, bp_arg, &offset);
1882 ferr(po, "detected but missing eq\n");
1883 offset += eq->offset;
1886 if (!strncmp(name, "ebp", 3))
1889 // yes it sometimes LEAs ra for compares..
1890 if (!is_lea && ofs_reg[0] == 0
1891 && stack_ra <= offset && offset < stack_ra + 4)
1893 ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1896 *offset_out = offset;
1898 *stack_ra_out = stack_ra;
1900 *bp_arg_out = bp_arg;
1903 static int parse_stack_esp_offset(struct parsed_op *po,
1904 const char *name, int *offset_out)
1906 char ofs_reg[16] = { 0, };
1907 struct parsed_equ *eq;
1913 if (strstr(name, "esp") == NULL)
1915 bp_arg = parse_stack_el(name, ofs_reg, &base_val, 0);
1916 if (bp_arg == NULL) {
1917 // just plain offset?
1918 if (!IS_START(name, "esp+"))
1921 offset = strtol(name + 4, &endp, 0);
1922 if (endp == NULL || *endp != 0 || errno != 0)
1924 *offset_out = offset;
1928 if (ofs_reg[0] != 0)
1930 eq = equ_find(po, bp_arg, &offset);
1932 ferr(po, "detected but missing eq\n");
1933 offset += eq->offset;
1934 *offset_out = base_val + offset;
1938 static int stack_frame_access(struct parsed_op *po,
1939 struct parsed_opr *popr, char *buf, size_t buf_size,
1940 const char *name, const char *cast, int is_src, int is_lea)
1942 enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1943 const char *prefix = "";
1944 const char *bp_arg = NULL;
1945 char ofs_reg[16] = { 0, };
1947 int i, arg_i, arg_s;
1954 if (g_bp_frame && (po->flags & OPF_EBP_S)
1955 && !(po->regmask_src & mxSP))
1956 ferr(po, "stack_frame_access while ebp is scratch\n");
1958 parse_stack_access(po, name, ofs_reg, &offset,
1959 &stack_ra, &bp_arg, is_lea);
1961 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1963 if (offset > stack_ra)
1965 arg_i = (offset - stack_ra - 4) / 4;
1966 if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1968 if (g_func_pp->is_vararg
1969 && arg_i == g_func_pp->argc_stack && is_lea)
1971 // should be va_list
1974 snprintf(buf, buf_size, "%sap", cast);
1977 ferr(po, "offset 0x%x (%s,%d) doesn't map to any arg\n",
1978 offset, bp_arg, arg_i);
1980 if (ofs_reg[0] != 0)
1981 ferr(po, "offset reg on arg access?\n");
1983 for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1984 if (g_func_pp->arg[i].reg != NULL)
1990 if (i == g_func_pp->argc)
1991 ferr(po, "arg %d not in prototype?\n", arg_i);
1993 popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
1996 snprintf(argname, sizeof(argname), "%sa%d",
1997 g_sct_func_attr & SCTFA_ARGFRAME ? "af." : "", i + 1);
2003 ferr(po, "lea/byte to arg?\n");
2004 if (is_src && (offset & 3) == 0)
2005 snprintf(buf, buf_size, "%s%s",
2006 simplify_cast(cast, "(u8)"), argname);
2008 snprintf(buf, buf_size, "%sBYTE%d(%s)",
2009 cast, offset & 3, argname);
2014 ferr(po, "lea/word to arg?\n");
2019 ferr(po, "problematic arg store\n");
2020 snprintf(buf, buf_size, "%s((char *)&%s + 1)",
2021 simplify_cast(cast, "*(u16 *)"), argname);
2024 ferr(po, "unaligned arg word load\n");
2026 else if (is_src && (offset & 2) == 0)
2027 snprintf(buf, buf_size, "%s%s",
2028 simplify_cast(cast, "(u16)"), argname);
2030 snprintf(buf, buf_size, "%s%sWORD(%s)",
2031 cast, (offset & 2) ? "HI" : "LO", argname);
2043 snprintf(buf, buf_size, "(u32)&%s + %d",
2044 argname, offset & 3);
2046 ferr(po, "unaligned arg store\n");
2048 // mov edx, [ebp+arg_4+2]; movsx ecx, dx
2049 snprintf(buf, buf_size, "%s(%s >> %d)",
2050 prefix, argname, (offset & 3) * 8);
2054 snprintf(buf, buf_size, "%s%s%s",
2055 prefix, is_lea ? "&" : "", argname);
2060 ferr_assert(po, !(offset & 7));
2063 snprintf(buf, buf_size, "%s%s%s",
2064 prefix, is_lea ? "&" : "", argname);
2068 ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
2072 strcat(g_comment, " unaligned");
2075 guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
2076 if (tmp_lmod != OPLM_DWORD
2077 && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
2078 < lmod_bytes(po, popr->lmod) + (offset & 3))))
2080 ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
2081 i + 1, offset, g_func_pp->arg[i].type.name);
2083 // can't check this because msvc likes to reuse
2084 // arg space for scratch..
2085 //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
2086 // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
2090 if (g_stack_fsz == 0)
2091 ferr(po, "stack var access without stackframe\n");
2092 g_stack_frame_used = 1;
2094 sf_ofs = g_stack_fsz + offset;
2095 if (ofs_reg[0] == 0 && (offset > 0 || sf_ofs < 0))
2096 ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
2106 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2107 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2111 if ((sf_ofs & 1) || ofs_reg[0] != 0) {
2112 // known unaligned or possibly unaligned
2113 strcat(g_comment, " unaligned");
2115 prefix = "*(u16 *)&";
2116 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2117 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2120 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
2124 if ((sf_ofs & 3) || ofs_reg[0] != 0) {
2125 // known unaligned or possibly unaligned
2126 strcat(g_comment, " unaligned");
2128 prefix = "*(u32 *)&";
2129 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2130 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2133 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
2137 ferr_assert(po, !(sf_ofs & 7));
2138 ferr_assert(po, ofs_reg[0] == 0);
2139 // only used for x87 int64/float, float sets is_lea
2140 if (!is_lea && (po->flags & OPF_FINT))
2141 prefix = "*(s64 *)&";
2142 snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
2146 ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
2153 static void check_func_pp(struct parsed_op *po,
2154 const struct parsed_proto *pp, const char *pfx)
2156 enum opr_lenmod tmp_lmod;
2160 if (pp->argc_reg != 0) {
2161 if (!g_allow_user_icall && !pp->is_fastcall) {
2162 pp_print(buf, sizeof(buf), pp);
2163 ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
2165 if (pp->argc_stack > 0 && pp->argc_reg != 2)
2166 ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
2167 pfx, pp->argc_reg, pp->argc_stack);
2170 // fptrs must use 32bit args, callsite might have no information and
2171 // lack a cast to smaller types, which results in incorrectly masked
2172 // args passed (callee may assume masked args, it does on ARM)
2173 if (!pp->is_osinc) {
2174 for (i = 0; i < pp->argc; i++) {
2175 ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
2176 if (ret && tmp_lmod != OPLM_DWORD)
2177 ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
2178 i + 1, pp->arg[i].type.name);
2183 static const char *check_label_read_ref(struct parsed_op *po,
2184 const char *name, int *is_import)
2186 const struct parsed_proto *pp;
2188 pp = proto_parse(g_fhdr, name, 0);
2190 ferr(po, "proto_parse failed for ref '%s'\n", name);
2193 check_func_pp(po, pp, "ref");
2195 if (is_import != NULL)
2196 *is_import = pp->is_import;
2201 static void check_opr(struct parsed_op *po, struct parsed_opr *popr)
2203 if (popr->segment == SEG_FS)
2204 ferr(po, "fs: used\n");
2205 if (popr->segment == SEG_GS)
2206 ferr(po, "gs: used\n");
2209 static char *out_src_opr(char *buf, size_t buf_size,
2210 struct parsed_op *po, struct parsed_opr *popr, const char *cast,
2213 char tmp1[256], tmp2[256];
2220 check_opr(po, popr);
2225 switch (popr->type) {
2228 ferr(po, "lea from reg?\n");
2230 switch (popr->lmod) {
2232 snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2235 snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2238 snprintf(buf, buf_size, "%s%s",
2239 simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2242 if (popr->name[1] == 'h') // XXX..
2243 snprintf(buf, buf_size, "%s(%s >> 8)",
2244 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2246 snprintf(buf, buf_size, "%s%s",
2247 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2250 ferr(po, "invalid src lmod: %d\n", popr->lmod);
2255 if (is_stack_access(po, popr)) {
2256 stack_frame_access(po, popr, buf, buf_size,
2257 popr->name, cast, 1, is_lea);
2261 strcpy(expr, popr->name);
2262 if (strchr(expr, '[')) {
2263 // special case: '[' can only be left for label[reg] form
2264 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2266 ferr(po, "parse failure for '%s'\n", expr);
2267 if (tmp1[0] == '(') {
2268 // (off_4FFF50+3)[eax]
2269 p = strchr(tmp1 + 1, ')');
2270 if (p == NULL || p[1] != 0)
2271 ferr(po, "parse failure (2) for '%s'\n", expr);
2273 memmove(tmp1, tmp1 + 1, strlen(tmp1));
2275 snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2278 // XXX: do we need more parsing?
2280 snprintf(buf, buf_size, "%s", expr);
2284 snprintf(buf, buf_size, "%s(%s)",
2285 simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2289 name = check_label_read_ref(po, popr->name, &is_import);
2291 // for imported data, asm is loading the offset
2294 if (cast[0] == 0 && popr->is_ptr)
2298 snprintf(buf, buf_size, "(u32)&%s", name);
2299 else if (popr->size_lt)
2300 snprintf(buf, buf_size, "%s%s%s%s", cast,
2301 lmod_cast_u_ptr(po, popr->lmod),
2302 popr->is_array ? "" : "&", name);
2304 snprintf(buf, buf_size, "%s%s%s", cast, name,
2305 popr->is_array ? "[0]" : "");
2310 name = check_label_read_ref(po, popr->name, NULL);
2314 ferr(po, "lea an offset?\n");
2315 snprintf(buf, buf_size, "%s&%s", cast, name);
2320 ferr(po, "lea from const?\n");
2322 printf_number(tmp1, sizeof(tmp1), popr->val);
2323 if (popr->val == 0 && strchr(cast, '*'))
2324 snprintf(buf, buf_size, "NULL");
2326 snprintf(buf, buf_size, "%s%s",
2327 simplify_cast_num(cast, popr->val), tmp1);
2331 ferr(po, "invalid src type: %d\n", popr->type);
2337 // note: may set is_ptr (we find that out late for ebp frame..)
2338 static char *out_dst_opr(char *buf, size_t buf_size,
2339 struct parsed_op *po, struct parsed_opr *popr)
2341 check_opr(po, popr);
2343 switch (popr->type) {
2345 switch (popr->lmod) {
2347 snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2350 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2354 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2358 if (popr->name[1] == 'h') // XXX..
2359 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2361 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2364 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2369 if (is_stack_access(po, popr)) {
2370 stack_frame_access(po, popr, buf, buf_size,
2371 popr->name, "", 0, 0);
2375 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2378 if (popr->size_mismatch)
2379 snprintf(buf, buf_size, "%s%s%s",
2380 lmod_cast_u_ptr(po, popr->lmod),
2381 popr->is_array ? "" : "&", popr->name);
2383 snprintf(buf, buf_size, "%s%s", popr->name,
2384 popr->is_array ? "[0]" : "");
2388 ferr(po, "invalid dst type: %d\n", popr->type);
2394 static char *out_src_opr_u32(char *buf, size_t buf_size,
2395 struct parsed_op *po, struct parsed_opr *popr)
2397 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2400 static char *out_opr_float(char *buf, size_t buf_size,
2401 struct parsed_op *po, struct parsed_opr *popr, int is_src,
2402 int need_float_stack)
2404 const char *cast = NULL;
2411 switch (popr->type) {
2413 if (popr->reg < xST0 || popr->reg > xST7) {
2415 ferr_assert(po, po->op == OP_PUSH);
2416 ferr_assert(po, popr->lmod == OPLM_DWORD);
2417 snprintf(buf, buf_size, "*(float *)&%s", opr_reg_p(po, popr));
2421 if (need_float_stack) {
2422 if (popr->reg == xST0)
2423 snprintf(buf, buf_size, "f_st[f_stp & 7]");
2425 snprintf(buf, buf_size, "f_st[(f_stp + %d) & 7]",
2429 snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2433 if (popr->lmod == OPLM_QWORD && is_stack_access(po, popr)) {
2434 stack_frame_access(po, popr, buf, buf_size,
2435 popr->name, "", is_src, 0);
2441 switch (popr->lmod) {
2449 ferr(po, "unhandled lmod: %d\n", popr->lmod);
2452 out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2453 snprintf(buf, buf_size, "*(%s *)(%s)", cast, tmp);
2457 // only for func float args pushes
2458 ferr_assert(po, po->op == OP_PUSH);
2459 u.i = po->operand[0].val;
2460 if (ceilf(u.f) == u.f)
2461 snprintf(buf, buf_size, "%.1ff", u.f);
2463 snprintf(buf, buf_size, "%.8ff", u.f);
2467 ferr(po, "invalid float type: %d\n", popr->type);
2473 static char *out_src_opr_float(char *buf, size_t buf_size,
2474 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2476 return out_opr_float(buf, buf_size, po, popr, 1, need_float_stack);
2479 static char *out_dst_opr_float(char *buf, size_t buf_size,
2480 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2482 return out_opr_float(buf, buf_size, po, popr, 0, need_float_stack);
2485 static void out_test_for_cc(char *buf, size_t buf_size,
2486 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2487 enum opr_lenmod lmod, const char *expr)
2489 const char *cast, *scast;
2491 cast = lmod_cast_u(po, lmod);
2492 scast = lmod_cast_s(po, lmod);
2496 case PFO_BE: // CF==1||ZF==1; CF=0
2497 snprintf(buf, buf_size, "(%s%s %s 0)",
2498 cast, expr, is_inv ? "!=" : "==");
2502 case PFO_L: // SF!=OF; OF=0
2503 snprintf(buf, buf_size, "(%s%s %s 0)",
2504 scast, expr, is_inv ? ">=" : "<");
2507 case PFO_LE: // ZF==1||SF!=OF; OF=0
2508 snprintf(buf, buf_size, "(%s%s %s 0)",
2509 scast, expr, is_inv ? ">" : "<=");
2514 snprintf(buf, buf_size, "(%d)", !!is_inv);
2517 case PFO_P: // PF==1
2518 snprintf(buf, buf_size, "(%sdo_parity(%s))",
2519 is_inv ? "!" : "", expr);
2523 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2527 static void out_cmp_for_cc(char *buf, size_t buf_size,
2528 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2531 const char *cast, *scast, *cast_use;
2532 char buf1[256], buf2[256];
2533 enum opr_lenmod lmod;
2535 if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2536 ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2537 po->operand[0].lmod, po->operand[1].lmod);
2538 lmod = po->operand[0].lmod;
2540 cast = lmod_cast_u(po, lmod);
2541 scast = lmod_cast_s(po, lmod);
2557 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2560 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2561 if (po->op == OP_DEC)
2562 snprintf(buf2, sizeof(buf2), "1");
2565 snprintf(cast_op2, sizeof(cast_op2) - 1, "%s", cast_use);
2567 strcat(cast_op2, "-");
2568 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_op2, 0);
2573 // note: must be unsigned compare
2574 snprintf(buf, buf_size, "(%s %s %s)",
2575 buf1, is_inv ? ">=" : "<", buf2);
2579 snprintf(buf, buf_size, "(%s %s %s)",
2580 buf1, is_inv ? "!=" : "==", buf2);
2584 // note: must be unsigned compare
2585 snprintf(buf, buf_size, "(%s %s %s)",
2586 buf1, is_inv ? ">" : "<=", buf2);
2589 if (is_inv && lmod == OPLM_BYTE
2590 && po->operand[1].type == OPT_CONST
2591 && po->operand[1].val == 0xff)
2593 snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2594 snprintf(buf, buf_size, "(0)");
2598 // note: must be signed compare
2600 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2601 scast, buf1, buf2, is_inv ? ">=" : "<");
2605 snprintf(buf, buf_size, "(%s %s %s)",
2606 buf1, is_inv ? ">=" : "<", buf2);
2610 snprintf(buf, buf_size, "(%s %s %s)",
2611 buf1, is_inv ? ">" : "<=", buf2);
2619 static void out_cmp_test(char *buf, size_t buf_size,
2620 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2622 char buf1[256], buf2[256], buf3[256];
2624 if (po->op == OP_TEST) {
2625 if (IS(opr_name(po, 0), opr_name(po, 1))) {
2626 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2629 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2630 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2631 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2633 out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2634 po->operand[0].lmod, buf3);
2636 else if (po->op == OP_CMP) {
2637 out_cmp_for_cc(buf, buf_size, po, pfo, is_inv, 0);
2640 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2643 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2644 struct parsed_opr *popr2)
2646 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2647 ferr(po, "missing lmod for both operands\n");
2649 if (popr1->lmod == OPLM_UNSPEC)
2650 popr1->lmod = popr2->lmod;
2651 else if (popr2->lmod == OPLM_UNSPEC)
2652 popr2->lmod = popr1->lmod;
2653 else if (popr1->lmod != popr2->lmod) {
2654 if (popr1->type_from_var) {
2655 popr1->size_mismatch = 1;
2656 if (popr1->lmod < popr2->lmod)
2658 popr1->lmod = popr2->lmod;
2660 else if (popr2->type_from_var) {
2661 popr2->size_mismatch = 1;
2662 if (popr2->lmod < popr1->lmod)
2664 popr2->lmod = popr1->lmod;
2667 ferr(po, "conflicting lmods: %d vs %d\n",
2668 popr1->lmod, popr2->lmod);
2672 static const char *op_to_c(struct parsed_op *po)
2696 ferr(po, "op_to_c was supplied with %d\n", po->op);
2700 // last op in stream - unconditional branch or ret
2701 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2702 || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2703 && ops[_i].op != OP_CALL))
2705 #define check_i(po, i) \
2707 ferr(po, "bad " #i ": %d\n", i)
2709 // note: this skips over calls and rm'd stuff assuming they're handled
2710 // so it's intended to use at one of final passes
2711 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2712 int depth, int seen_noreturn, int flags_set)
2714 struct parsed_op *po;
2719 for (; i < opcnt; i++) {
2721 if (po->cc_scratch == magic)
2722 return ret; // already checked
2723 po->cc_scratch = magic;
2725 if (po->flags & OPF_TAIL) {
2726 if (po->op == OP_CALL) {
2727 if (po->pp != NULL && po->pp->is_noreturn)
2736 if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
2739 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2740 if (po->btj != NULL) {
2742 for (j = 0; j < po->btj->count; j++) {
2743 check_i(po, po->btj->d[j].bt_i);
2744 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2745 depth, seen_noreturn, flags_set);
2747 return ret; // dead end
2752 check_i(po, po->bt_i);
2753 if (po->flags & OPF_CJMP) {
2754 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2755 depth, seen_noreturn, flags_set);
2757 return ret; // dead end
2766 if ((po->op == OP_POP || po->op == OP_PUSH)
2767 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2772 if (po->op == OP_PUSH) {
2775 else if (po->op == OP_POP) {
2776 if (relevant && depth == 0) {
2777 po->flags |= flags_set;
2785 // for noreturn, assume msvc skipped stack cleanup
2786 return seen_noreturn ? 1 : -1;
2789 // scan for 'reg' pop backwards starting from i
2790 // intended to use for register restore search, so other reg
2791 // references are considered an error
2792 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2794 struct parsed_op *po;
2795 struct label_ref *lr;
2798 ops[i].cc_scratch = magic;
2802 if (g_labels[i] != NULL) {
2803 lr = &g_label_refs[i];
2804 for (; lr != NULL; lr = lr->next) {
2805 check_i(&ops[i], lr->i);
2806 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2810 if (i > 0 && LAST_OP(i - 1))
2818 if (ops[i].cc_scratch == magic)
2820 ops[i].cc_scratch = magic;
2823 if (po->op == OP_POP && po->operand[0].reg == reg) {
2824 if (po->flags & (OPF_RMD|OPF_DONE))
2827 po->flags |= set_flags;
2831 // this also covers the case where we reach corresponding push
2832 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2836 // nothing interesting on this path,
2837 // still return ret for something recursive calls could find
2841 static void find_reachable_exits(int i, int opcnt, int magic,
2842 int *exits, int *exit_count)
2844 struct parsed_op *po;
2847 for (; i < opcnt; i++)
2850 if (po->cc_scratch == magic)
2852 po->cc_scratch = magic;
2854 if (po->flags & OPF_TAIL) {
2855 ferr_assert(po, *exit_count < MAX_EXITS);
2856 exits[*exit_count] = i;
2861 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2862 if (po->flags & OPF_RMD)
2865 if (po->btj != NULL) {
2866 for (j = 0; j < po->btj->count; j++) {
2867 check_i(po, po->btj->d[j].bt_i);
2868 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2874 check_i(po, po->bt_i);
2875 if (po->flags & OPF_CJMP)
2876 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2884 // scan for 'reg' pop backwards starting from exits (all paths)
2885 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2887 static int exits[MAX_EXITS];
2888 static int exit_count;
2894 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2896 ferr_assert(&ops[i], exit_count > 0);
2899 for (j = 0; j < exit_count; j++) {
2901 ret = scan_for_rsave_pop_reg(e, i + opcnt * 16 + set_flags,
2907 if (ops[e].op == OP_CALL && ops[e].pp != NULL
2908 && ops[e].pp->is_noreturn)
2910 // assume stack cleanup was skipped
2919 // scan for one or more pop of push <const>
2920 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2921 int push_i, int is_probe)
2923 struct parsed_op *po;
2924 struct label_ref *lr;
2928 for (; i < opcnt; i++)
2931 if (po->cc_scratch == magic)
2932 return ret; // already checked
2933 po->cc_scratch = magic;
2935 if (po->flags & OPF_JMP) {
2936 if (po->flags & OPF_RMD)
2938 if (po->op == OP_CALL)
2941 if (po->btj != NULL) {
2942 for (j = 0; j < po->btj->count; j++) {
2943 check_i(po, po->btj->d[j].bt_i);
2944 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2952 check_i(po, po->bt_i);
2953 if (po->flags & OPF_CJMP) {
2954 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2965 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2968 if (g_labels[i] != NULL) {
2969 // all refs must be visited
2970 lr = &g_label_refs[i];
2971 for (; lr != NULL; lr = lr->next) {
2973 if (ops[lr->i].cc_scratch != magic)
2976 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2980 if (po->op == OP_POP)
2982 if (po->flags & (OPF_RMD|OPF_DONE))
2986 po->flags |= OPF_DONE;
2987 po->datap = &ops[push_i];
2996 static void scan_for_pop_const(int i, int opcnt, int magic)
3000 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
3002 ops[i].flags |= OPF_RMD | OPF_DONE;
3003 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
3007 // check if all branch targets within a marked path are also marked
3008 // note: the path checked must not be empty or end with a branch
3009 static int check_path_branches(int opcnt, int magic)
3011 struct parsed_op *po;
3014 for (i = 0; i < opcnt; i++) {
3016 if (po->cc_scratch != magic)
3019 if (po->flags & OPF_JMP) {
3020 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
3023 if (po->btj != NULL) {
3024 for (j = 0; j < po->btj->count; j++) {
3025 check_i(po, po->btj->d[j].bt_i);
3026 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
3031 check_i(po, po->bt_i);
3032 if (ops[po->bt_i].cc_scratch != magic)
3034 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
3042 // scan for multiple pushes for given pop
3043 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
3046 int reg = ops[pop_i].operand[0].reg;
3047 struct parsed_op *po;
3048 struct label_ref *lr;
3051 ops[i].cc_scratch = magic;
3055 if (g_labels[i] != NULL) {
3056 lr = &g_label_refs[i];
3057 for (; lr != NULL; lr = lr->next) {
3058 check_i(&ops[i], lr->i);
3059 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
3063 if (i > 0 && LAST_OP(i - 1))
3071 if (ops[i].cc_scratch == magic)
3073 ops[i].cc_scratch = magic;
3076 if (po->op == OP_CALL)
3078 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
3081 if (po->op == OP_PUSH)
3083 if (po->datap != NULL)
3085 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
3086 // leave this case for reg save/restore handlers
3090 po->flags |= OPF_PPUSH | OPF_DONE;
3091 po->datap = &ops[pop_i];
3100 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
3102 int magic = i + opcnt * 14;
3105 ret = scan_pushes_for_pop_r(i, magic, i, 1);
3107 ret = check_path_branches(opcnt, magic);
3109 ops[i].flags |= OPF_PPUSH | OPF_DONE;
3110 *regmask_pp |= 1 << ops[i].operand[0].reg;
3111 scan_pushes_for_pop_r(i, magic + 1, i, 0);
3116 static void scan_propagate_df(int i, int opcnt)
3118 struct parsed_op *po = &ops[i];
3121 for (; i < opcnt; i++) {
3123 if (po->flags & OPF_DF)
3124 return; // already resolved
3125 po->flags |= OPF_DF;
3127 if (po->op == OP_CALL)
3128 ferr(po, "call with DF set?\n");
3130 if (po->flags & OPF_JMP) {
3131 if (po->btj != NULL) {
3133 for (j = 0; j < po->btj->count; j++) {
3134 check_i(po, po->btj->d[j].bt_i);
3135 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
3140 if (po->flags & OPF_RMD)
3142 check_i(po, po->bt_i);
3143 if (po->flags & OPF_CJMP)
3144 scan_propagate_df(po->bt_i, opcnt);
3150 if (po->flags & OPF_TAIL)
3153 if (po->op == OP_CLD) {
3154 po->flags |= OPF_RMD | OPF_DONE;
3159 ferr(po, "missing DF clear?\n");
3162 // is operand 'opr' referenced by parsed_op 'po'?
3163 static int is_opr_referenced(const struct parsed_opr *opr,
3164 const struct parsed_op *po)
3168 if (opr->type == OPT_REG) {
3169 mask = po->regmask_dst | po->regmask_src;
3170 if (po->op == OP_CALL)
3171 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
3172 if ((1 << opr->reg) & mask)
3178 for (i = 0; i < po->operand_cnt; i++)
3179 if (IS(po->operand[0].name, opr->name))
3185 // is operand 'opr' read by parsed_op 'po'?
3186 static int is_opr_read(const struct parsed_opr *opr,
3187 const struct parsed_op *po)
3189 if (opr->type == OPT_REG) {
3190 if (po->regmask_src & (1 << opr->reg))
3200 // is operand 'opr' modified by parsed_op 'po'?
3201 static int is_opr_modified(const struct parsed_opr *opr,
3202 const struct parsed_op *po)
3206 if (opr->type == OPT_REG) {
3207 if (po->op == OP_CALL) {
3208 mask = po->regmask_dst;
3209 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
3210 if (mask & (1 << opr->reg))
3216 if (po->regmask_dst & (1 << opr->reg))
3222 return IS(po->operand[0].name, opr->name);
3225 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
3226 static int is_any_opr_modified(const struct parsed_op *po_test,
3227 const struct parsed_op *po, int c_mode)
3232 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
3235 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3238 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
3241 // in reality, it can wreck any register, but in decompiled C
3242 // version it can only overwrite eax or edx:eax
3243 mask = (1 << xAX) | (1 << xDX);
3247 if (po->op == OP_CALL
3248 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
3251 for (i = 0; i < po_test->operand_cnt; i++)
3252 if (IS(po_test->operand[i].name, po->operand[0].name))
3258 // scan for any po_test operand modification in range given
3259 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
3262 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3265 for (; i < opcnt; i++) {
3266 if (is_any_opr_modified(po_test, &ops[i], c_mode))
3273 // scan for po_test operand[0] modification in range given
3274 static int scan_for_mod_opr0(struct parsed_op *po_test,
3277 for (; i < opcnt; i++) {
3278 if (is_opr_modified(&po_test->operand[0], &ops[i]))
3285 static int try_resolve_const(int i, const struct parsed_opr *opr,
3286 int magic, unsigned int *val);
3288 static int scan_for_flag_set(int i, int opcnt, int magic,
3289 int *branched, int *setters, int *setter_cnt)
3291 struct label_ref *lr;
3295 if (ops[i].cc_scratch == magic) {
3296 // is this a problem?
3297 //ferr(&ops[i], "%s looped\n", __func__);
3300 ops[i].cc_scratch = magic;
3302 if (g_labels[i] != NULL) {
3305 lr = &g_label_refs[i];
3306 for (; lr->next; lr = lr->next) {
3307 check_i(&ops[i], lr->i);
3308 ret = scan_for_flag_set(lr->i, opcnt, magic,
3309 branched, setters, setter_cnt);
3314 check_i(&ops[i], lr->i);
3315 if (i > 0 && LAST_OP(i - 1)) {
3319 ret = scan_for_flag_set(lr->i, opcnt, magic,
3320 branched, setters, setter_cnt);
3326 if (ops[i].flags & OPF_FLAGS) {
3327 setters[*setter_cnt] = i;
3330 if (ops[i].flags & OPF_REP) {
3331 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
3334 ret = try_resolve_const(i, &opr, i + opcnt * 7, &uval);
3335 if (ret != 1 || uval == 0) {
3336 // can't treat it as full setter because of ecx=0 case,
3337 // also disallow delayed compare
3346 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3353 // scan back for cdq, if anything modifies edx, fail
3354 static int scan_for_cdq_edx(int i)
3357 if (g_labels[i] != NULL) {
3358 if (g_label_refs[i].next != NULL)
3360 if (i > 0 && LAST_OP(i - 1)) {
3361 i = g_label_refs[i].i;
3368 if (ops[i].op == OP_CDQ)
3371 if (ops[i].regmask_dst & (1 << xDX))
3378 static int scan_for_reg_clear(int i, int reg)
3381 if (g_labels[i] != NULL) {
3382 if (g_label_refs[i].next != NULL)
3384 if (i > 0 && LAST_OP(i - 1)) {
3385 i = g_label_refs[i].i;
3392 if (ops[i].op == OP_XOR
3393 && ops[i].operand[0].lmod == OPLM_DWORD
3394 && ops[i].operand[0].reg == ops[i].operand[1].reg
3395 && ops[i].operand[0].reg == reg)
3398 if (ops[i].regmask_dst & (1 << reg))
3405 static void patch_esp_adjust(struct parsed_op *po, int adj)
3407 ferr_assert(po, po->op == OP_ADD);
3408 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3409 ferr_assert(po, po->operand[1].type == OPT_CONST);
3411 // this is a bit of a hack, but deals with use of
3412 // single adj for multiple calls
3413 po->operand[1].val -= adj;
3414 po->flags |= OPF_RMD;
3415 if (po->operand[1].val == 0)
3416 po->flags |= OPF_DONE;
3417 ferr_assert(po, (int)po->operand[1].val >= 0);
3420 // scan for positive, constant esp adjust
3421 // multipath case is preliminary
3422 static int scan_for_esp_adjust(int i, int opcnt,
3423 int adj_expect, int *adj, int *is_multipath, int do_update)
3425 int adj_expect_unknown = 0;
3426 struct parsed_op *po;
3430 *adj = *is_multipath = 0;
3431 if (adj_expect < 0) {
3432 adj_expect_unknown = 1;
3433 adj_expect = 32 * 4; // enough?
3436 for (; i < opcnt && *adj < adj_expect; i++) {
3437 if (g_labels[i] != NULL)
3441 if (po->flags & OPF_DONE)
3444 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3445 if (po->operand[1].type != OPT_CONST)
3446 ferr(&ops[i], "non-const esp adjust?\n");
3447 *adj += po->operand[1].val;
3449 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3452 patch_esp_adjust(po, adj_expect);
3454 po->flags |= OPF_RMD;
3458 else if (po->op == OP_PUSH) {
3459 //if (first_pop == -1)
3460 // first_pop = -2; // none
3461 *adj -= lmod_bytes(po, po->operand[0].lmod);
3463 else if (po->op == OP_POP) {
3464 if (!(po->flags & OPF_DONE)) {
3465 // seems like msvc only uses 'pop ecx' for stack realignment..
3466 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3468 if (first_pop == -1 && *adj >= 0)
3471 if (do_update && *adj >= 0) {
3472 po->flags |= OPF_RMD;
3474 po->flags |= OPF_DONE | OPF_NOREGS;
3477 *adj += lmod_bytes(po, po->operand[0].lmod);
3478 if (*adj > adj_best)
3481 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3482 if (po->op == OP_JMP && po->btj == NULL) {
3488 if (po->op != OP_CALL)
3490 if (po->operand[0].type != OPT_LABEL)
3492 if (po->pp != NULL && po->pp->is_stdcall)
3494 if (adj_expect_unknown && first_pop >= 0)
3496 // assume it's another cdecl call
3500 if (first_pop >= 0) {
3501 // probably only 'pop ecx' was used
3509 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3511 struct parsed_op *po;
3515 ferr(ops, "%s: followed bad branch?\n", __func__);
3517 for (; i < opcnt; i++) {
3519 if (po->cc_scratch == magic)
3521 po->cc_scratch = magic;
3524 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3525 if (po->btj != NULL) {
3527 for (j = 0; j < po->btj->count; j++)
3528 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3532 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3533 if (!(po->flags & OPF_CJMP))
3536 if (po->flags & OPF_TAIL)
3541 static const struct parsed_proto *try_recover_pp(
3542 struct parsed_op *po, const struct parsed_opr *opr,
3543 int is_call, int *search_instead)
3545 const struct parsed_proto *pp = NULL;
3549 if (po->pp != NULL && (po->flags & OPF_DATA)) {
3550 // hint given in asm
3554 // maybe an arg of g_func?
3555 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3557 char ofs_reg[16] = { 0, };
3558 int arg, arg_s, arg_i;
3565 parse_stack_access(po, opr->name, ofs_reg,
3566 &offset, &stack_ra, NULL, 0);
3567 if (ofs_reg[0] != 0)
3568 ferr(po, "offset reg on arg access?\n");
3569 if (offset <= stack_ra) {
3570 // search who set the stack var instead
3571 if (search_instead != NULL)
3572 *search_instead = 1;
3576 arg_i = (offset - stack_ra - 4) / 4;
3577 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3578 if (g_func_pp->arg[arg].reg != NULL)
3584 if (arg == g_func_pp->argc)
3585 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3587 pp = g_func_pp->arg[arg].pp;
3590 ferr(po, "icall arg: arg%d has no pp\n", arg + 1);
3591 check_func_pp(po, pp, "icall arg");
3594 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3596 p = strchr(opr->name + 1, '[');
3597 memcpy(buf, opr->name, p - opr->name);
3598 buf[p - opr->name] = 0;
3599 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3601 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3602 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3605 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3608 check_func_pp(po, pp, "reg-fptr ref");
3614 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3615 int magic, const struct parsed_proto **pp_found, int *pp_i,
3618 const struct parsed_proto *pp = NULL;
3619 struct parsed_op *po;
3620 struct label_ref *lr;
3622 ops[i].cc_scratch = magic;
3625 if (g_labels[i] != NULL) {
3626 lr = &g_label_refs[i];
3627 for (; lr != NULL; lr = lr->next) {
3628 check_i(&ops[i], lr->i);
3629 scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3631 if (i > 0 && LAST_OP(i - 1))
3639 if (ops[i].cc_scratch == magic)
3641 ops[i].cc_scratch = magic;
3643 if (!(ops[i].flags & OPF_DATA))
3645 if (!is_opr_modified(opr, &ops[i]))
3647 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3648 // most probably trashed by some processing
3653 opr = &ops[i].operand[1];
3654 if (opr->type != OPT_REG)
3658 po = (i >= 0) ? &ops[i] : ops;
3661 // reached the top - can only be an arg-reg
3662 if (opr->type != OPT_REG || g_func_pp == NULL)
3665 for (i = 0; i < g_func_pp->argc; i++) {
3666 if (g_func_pp->arg[i].reg == NULL)
3668 if (IS(opr->name, g_func_pp->arg[i].reg))
3671 if (i == g_func_pp->argc)
3673 pp = g_func_pp->arg[i].pp;
3675 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3676 i + 1, g_func_pp->arg[i].reg);
3677 check_func_pp(po, pp, "icall reg-arg");
3680 pp = try_recover_pp(po, opr, 1, NULL);
3682 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3683 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3684 || (*pp_found)->is_stdcall != pp->is_stdcall
3685 //|| (*pp_found)->is_fptr != pp->is_fptr
3686 || (*pp_found)->argc != pp->argc
3687 || (*pp_found)->argc_reg != pp->argc_reg
3688 || (*pp_found)->argc_stack != pp->argc_stack)
3690 ferr(po, "icall: parsed_proto mismatch\n");
3700 static void add_label_ref(struct label_ref *lr, int op_i)
3702 struct label_ref *lr_new;
3709 lr_new = calloc(1, sizeof(*lr_new));
3711 lr_new->next = lr->next;
3715 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3717 struct parsed_op *po = &ops[i];
3718 struct parsed_data *pd;
3719 char label[NAMELEN], *p;
3722 p = strchr(po->operand[0].name, '[');
3726 len = p - po->operand[0].name;
3727 strncpy(label, po->operand[0].name, len);
3730 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3731 if (IS(g_func_pd[j].label, label)) {
3737 //ferr(po, "label '%s' not parsed?\n", label);
3740 if (pd->type != OPT_OFFSET)
3741 ferr(po, "label '%s' with non-offset data?\n", label);
3743 // find all labels, link
3744 for (j = 0; j < pd->count; j++) {
3745 for (l = 0; l < opcnt; l++) {
3746 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3747 add_label_ref(&g_label_refs[l], i);
3757 static void clear_labels(int count)
3761 for (i = 0; i < count; i++) {
3762 if (g_labels[i] != NULL) {
3769 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3774 for (i = 0; i < pp->argc; i++) {
3775 if (pp->arg[i].reg != NULL) {
3776 reg = char_array_i(regs_r32,
3777 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3779 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3780 pp->arg[i].reg, pp->name);
3781 regmask |= 1 << reg;
3788 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3793 if (pp->has_retreg) {
3794 for (i = 0; i < pp->argc; i++) {
3795 if (pp->arg[i].type.is_retreg) {
3796 reg = char_array_i(regs_r32,
3797 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3798 ferr_assert(ops, reg >= 0);
3799 regmask |= 1 << reg;
3804 if (strstr(pp->ret_type.name, "int64"))
3805 return regmask | (1 << xAX) | (1 << xDX);
3806 if (IS(pp->ret_type.name, "float")
3807 || IS(pp->ret_type.name, "double"))
3809 return regmask | mxST0;
3811 if (strcasecmp(pp->ret_type.name, "void") == 0)
3814 return regmask | mxAX;
3817 static int are_ops_same(struct parsed_op *po1, struct parsed_op *po2)
3819 return po1->op == po2->op && po1->operand_cnt == po2->operand_cnt
3820 && memcmp(po1->operand, po2->operand,
3821 sizeof(po1->operand[0]) * po1->operand_cnt) == 0;
3824 static void resolve_branches_parse_calls(int opcnt)
3826 static const struct {
3830 unsigned int regmask_src;
3831 unsigned int regmask_dst;
3833 { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3834 { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3835 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3836 // more precise? Wine gets away with just __ftol handler
3837 { "__ftol2", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3838 { "__CIpow", OPP_CIPOW, OPF_FPOP, mxST0|mxST1, mxST0 },
3840 const struct parsed_proto *pp_c;
3841 struct parsed_proto *pp;
3842 struct parsed_data *pd;
3843 struct parsed_op *po;
3844 const char *tmpname;
3849 for (i = 0; i < opcnt; i++)
3855 if (po->datap != NULL) {
3856 pp = calloc(1, sizeof(*pp));
3857 my_assert_not(pp, NULL);
3859 ret = parse_protostr(po->datap, pp);
3861 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3867 if (po->op == OP_CALL) {
3872 else if (po->operand[0].type == OPT_LABEL)
3874 tmpname = opr_name(po, 0);
3875 if (IS_START(tmpname, "loc_")) {
3877 ferr(po, "call to loc_*\n");
3878 // eliminate_seh() must take care of it
3881 if (IS(tmpname, "__alloca_probe"))
3883 if (IS(tmpname, "__SEH_prolog")) {
3884 ferr_assert(po, g_seh_found == 0);
3888 if (IS(tmpname, "__SEH_epilog"))
3891 // convert some calls to pseudo-ops
3892 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3893 if (!IS(tmpname, pseudo_ops[l].name))
3896 po->op = pseudo_ops[l].op;
3897 po->operand_cnt = 0;
3898 po->regmask_src = pseudo_ops[l].regmask_src;
3899 po->regmask_dst = pseudo_ops[l].regmask_dst;
3900 po->flags = pseudo_ops[l].flags;
3901 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3904 if (l < ARRAY_SIZE(pseudo_ops))
3907 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3908 if (!g_header_mode && pp_c == NULL)
3909 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3912 pp = proto_clone(pp_c);
3913 my_assert_not(pp, NULL);
3919 check_func_pp(po, pp, "fptr var call");
3920 if (pp->is_noreturn) {
3921 po->flags |= OPF_TAIL;
3922 po->flags &= ~OPF_ATAIL; // most likely...
3929 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3932 if (po->operand[0].type == OPT_REGMEM) {
3933 pd = try_resolve_jumptab(i, opcnt);
3941 for (l = 0; l < opcnt; l++) {
3942 if (g_labels[l] != NULL
3943 && IS(po->operand[0].name, g_labels[l]))
3945 if (l == i + 1 && po->op == OP_JMP) {
3946 // yet another alignment type...
3947 po->flags |= OPF_RMD | OPF_DONE;
3948 po->flags &= ~OPF_JMP;
3952 add_label_ref(&g_label_refs[l], i);
3958 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3961 if (po->operand[0].type == OPT_LABEL)
3965 ferr(po, "unhandled branch\n");
3969 po->flags |= OPF_TAIL;
3970 prev_op = i > 0 ? ops[i - 1].op : OP_UD2;
3971 if (prev_op == OP_POP)
3972 po->flags |= OPF_ATAIL;
3973 if (g_stack_fsz + g_bp_frame == 0 && prev_op != OP_PUSH
3974 && (g_func_pp == NULL || g_func_pp->argc_stack > 0))
3976 po->flags |= OPF_ATAIL;
3982 static int resolve_origin(int i, const struct parsed_opr *opr,
3983 int magic, int *op_i, int *is_caller);
3984 static void set_label(int i, const char *name);
3986 static void eliminate_seh_writes(int opcnt)
3988 const struct parsed_opr *opr;
3993 // assume all sf writes above g_seh_size to be seh related
3994 // (probably unsafe but oh well)
3995 for (i = 0; i < opcnt; i++) {
3996 if (ops[i].op != OP_MOV)
3998 opr = &ops[i].operand[0];
3999 if (opr->type != OPT_REGMEM)
4001 if (!is_stack_access(&ops[i], opr))
4005 parse_stack_access(&ops[i], opr->name, ofs_reg, &offset,
4007 if (offset < 0 && offset >= -g_seh_size)
4008 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4012 static void eliminate_seh_finally(int opcnt)
4014 const char *target_name = NULL;
4015 const char *return_name = NULL;
4016 int exits[MAX_EXITS];
4024 for (i = 0; i < opcnt; i++) {
4025 if (ops[i].op != OP_CALL)
4027 if (!IS_START(opr_name(&ops[i], 0), "loc_"))
4029 if (target_name != NULL)
4030 ferr(&ops[i], "multiple finally calls? (last was %s)\n",
4032 target_name = opr_name(&ops[i], 0);
4035 if (g_labels[i + 1] == NULL)
4036 set_label(i + 1, "seh_fin_done");
4037 return_name = g_labels[i + 1];
4045 // find finally code (bt_i is not set because it's call)
4046 for (i = 0; i < opcnt; i++) {
4047 if (g_labels[i] == NULL)
4049 if (!IS(g_labels[i], target_name))
4052 ferr_assert(&ops[i], target_i == -1);
4055 ferr_assert(&ops[0], target_i != -1);
4057 find_reachable_exits(target_i, opcnt, target_i + opcnt * 24,
4058 exits, &exit_count);
4059 ferr_assert(&ops[target_i], exit_count == 1);
4060 ferr_assert(&ops[target_i], ops[exits[0]].op == OP_RET);
4063 // convert to jumps, link
4064 ops[call_i].op = OP_JMP;
4065 ops[call_i].bt_i = target_i;
4066 add_label_ref(&g_label_refs[target_i], call_i);
4068 ops[tgend_i].op = OP_JMP;
4069 ops[tgend_i].flags &= ~OPF_TAIL;
4070 ops[tgend_i].flags |= OPF_JMP;
4071 ops[tgend_i].bt_i = return_i;
4072 ops[tgend_i].operand_cnt = 1;
4073 ops[tgend_i].operand[0].type = OPT_LABEL;
4074 snprintf(ops[tgend_i].operand[0].name, NAMELEN, "%s", return_name);
4075 add_label_ref(&g_label_refs[return_i], tgend_i);
4077 // rm seh finally entry code
4078 for (i = target_i - 1; i >= 0; i--) {
4079 if (g_labels[i] != NULL && g_label_refs[i].i != -1)
4081 if (ops[i].flags & OPF_CJMP)
4083 if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4086 for (i = target_i - 1; i >= 0; i--) {
4087 if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4089 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4093 static void eliminate_seh(int opcnt)
4097 for (i = 0; i < opcnt; i++) {
4098 if (ops[i].op != OP_MOV)
4100 if (ops[i].operand[0].segment != SEG_FS)
4102 if (!IS(opr_name(&ops[i], 0), "0"))
4105 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4106 if (ops[i].operand[1].reg == xSP) {
4107 for (j = i - 1; j >= 0; j--) {
4108 if (ops[j].op != OP_PUSH)
4110 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4112 if (ops[j].operand[0].val == ~0)
4114 if (ops[j].operand[0].type == OPT_REG) {
4116 ret = resolve_origin(j, &ops[j].operand[0],
4117 j + opcnt * 22, &k, NULL);
4119 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4123 ferr(ops, "missing seh terminator\n");
4127 ret = resolve_origin(i, &ops[i].operand[1],
4128 i + opcnt * 23, &k, NULL);
4130 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4134 eliminate_seh_writes(opcnt);
4135 eliminate_seh_finally(opcnt);
4138 static void eliminate_seh_calls(int opcnt)
4140 int epilog_found = 0;
4147 ferr_assert(&ops[i], ops[i].op == OP_PUSH
4148 && ops[i].operand[0].type == OPT_CONST);
4149 g_stack_fsz = g_seh_size + ops[i].operand[0].val;
4150 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4153 ferr_assert(&ops[i], ops[i].op == OP_PUSH
4154 && ops[i].operand[0].type == OPT_OFFSET);
4155 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4158 ferr_assert(&ops[i], ops[i].op == OP_CALL
4159 && IS(opr_name(&ops[i], 0), "__SEH_prolog"));
4160 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4162 for (i++; i < opcnt; i++) {
4163 if (ops[i].op != OP_CALL)
4165 if (!IS(opr_name(&ops[i], 0), "__SEH_epilog"))
4168 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4171 ferr_assert(ops, epilog_found);
4173 eliminate_seh_writes(opcnt);
4174 eliminate_seh_finally(opcnt);
4177 // check for prologue of many pushes and epilogue with pops
4178 static void check_simple_sequence(int opcnt, int *fsz)
4187 for (i = 0; i < opcnt && i < ARRAY_SIZE(seq); i++) {
4188 if (ops[i].op != OP_PUSH || ops[i].operand[0].type != OPT_REG)
4190 reg = ops[i].operand[0].reg;
4191 if (reg != xBX && reg != xSI && reg != xDI && reg != xBP)
4193 for (j = 0; j < i; j++)
4197 // probably something else is going on here
4205 for (; i < opcnt && seq_len > 0; i++) {
4206 if (!(ops[i].flags & OPF_TAIL))
4209 for (j = i - 1, seq_p = 0; j >= 0 && seq_p < seq_len; j--) {
4210 if (ops[j].op != OP_POP || ops[j].operand[0].type != OPT_REG)
4212 if (ops[j].operand[0].reg != seq[seq_p])
4216 found = seq_len = seq_p;
4221 for (i = 0; i < seq_len; i++)
4222 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4224 for (; i < opcnt && seq_len > 0; i++) {
4225 if (!(ops[i].flags & OPF_TAIL))
4228 for (j = i - 1, seq_p = 0; j >= 0 && seq_p < seq_len; j--) {
4229 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4234 // unlike pushes after sub esp,
4235 // IDA treats pushed like this as part of var area
4236 *fsz += seq_len * 4;
4239 static int scan_prologue(int i, int opcnt, int *ecx_push, int *esp_sub)
4244 for (; i < opcnt; i++)
4245 if (!(ops[i].flags & OPF_DONE))
4248 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4249 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4255 for (; i < opcnt; i++) {
4256 if (i > 0 && g_labels[i] != NULL)
4258 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
4260 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
4261 && ops[i].operand[1].type == OPT_CONST)
4263 g_stack_fsz += opr_const(&ops[i], 1);
4264 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4269 if (ops[i].op == OP_LEA && ops[i].operand[0].reg == xSP
4270 && ops[i].operand[1].type == OPT_REGMEM
4271 && IS_START(ops[i].operand[1].name, "esp-"))
4273 name = ops[i].operand[1].name;
4274 ret = sscanf(name, "esp-%x%n", &j, &len);
4275 ferr_assert(&ops[i], ret == 1 && len == strlen(name));
4277 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4282 if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
4283 && ops[i].operand[1].type == OPT_CONST)
4285 for (j = i + 1; j < opcnt; j++)
4286 if (!(ops[j].flags & OPF_DONE))
4288 if (ops[j].op == OP_CALL
4289 && IS(opr_name(&ops[j], 0), "__alloca_probe"))
4291 g_stack_fsz += opr_const(&ops[i], 1);
4292 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4293 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4304 static void scan_prologue_epilogue(int opcnt, int *stack_align)
4306 int ecx_push = 0, esp_sub = 0, pusha = 0;
4307 int sandard_epilogue;
4308 int found, ret, len;
4312 if (g_seh_found == 2) {
4313 eliminate_seh_calls(opcnt);
4317 eliminate_seh(opcnt);
4318 // ida treats seh as part of sf
4319 g_stack_fsz = g_seh_size;
4323 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
4324 && ops[1].op == OP_MOV
4325 && IS(opr_name(&ops[1], 0), "ebp")
4326 && IS(opr_name(&ops[1], 1), "esp"))
4329 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4330 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4332 for (i = 2; i < opcnt; i++)
4333 if (!(ops[i].flags & OPF_DONE))
4336 if (ops[i].op == OP_PUSHA) {
4337 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4342 if (ops[i].op == OP_AND && ops[i].operand[0].reg == xSP
4343 && ops[i].operand[1].type == OPT_CONST)
4345 l = ops[i].operand[1].val;
4347 if (j == -1 || (l >> j) != -1)
4348 ferr(&ops[i], "unhandled esp align: %x\n", l);
4349 if (stack_align != NULL)
4350 *stack_align = 1 << j;
4351 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4355 i = scan_prologue(i, opcnt, &ecx_push, &esp_sub);
4359 for (; i < opcnt; i++)
4360 if (ops[i].flags & OPF_TAIL)
4363 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4364 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4370 sandard_epilogue = 0;
4371 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
4373 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4374 // the standard epilogue is sometimes even used without a sf
4375 if (ops[j - 1].op == OP_MOV
4376 && IS(opr_name(&ops[j - 1], 0), "esp")
4377 && IS(opr_name(&ops[j - 1], 1), "ebp"))
4378 sandard_epilogue = 1;
4380 else if (ops[j].op == OP_LEAVE)
4382 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4383 sandard_epilogue = 1;
4385 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
4386 && ops[i].pp->is_noreturn)
4388 // on noreturn, msvc sometimes cleans stack, sometimes not
4393 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4394 ferr(&ops[j], "'pop ebp' expected\n");
4396 if (g_stack_fsz != 0 || sandard_epilogue) {
4397 if (ops[j].op == OP_LEAVE)
4399 else if (sandard_epilogue) // mov esp, ebp
4401 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4404 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4406 ferr(&ops[j], "esp restore expected\n");
4409 if (ecx_push && j >= 0 && ops[j].op == OP_POP
4410 && IS(opr_name(&ops[j], 0), "ecx"))
4412 ferr(&ops[j], "unexpected ecx pop\n");
4417 if (ops[j].op == OP_POPA)
4418 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4420 ferr(&ops[j], "popa expected\n");
4425 } while (i < opcnt);
4428 ferr(ops, "missing ebp epilogue\n");
4433 check_simple_sequence(opcnt, &push_fsz);
4434 i = scan_prologue(0, opcnt, &ecx_push, &esp_sub);
4436 if (ecx_push && !esp_sub) {
4437 // could actually be args for a call..
4438 for (; i < opcnt; i++)
4439 if (ops[i].op != OP_PUSH)
4442 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
4443 const struct parsed_proto *pp;
4444 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
4445 j = pp ? pp->argc_stack : 0;
4446 while (i > 0 && j > 0) {
4448 if (ops[i].op == OP_PUSH) {
4449 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
4454 ferr(&ops[i], "unhandled prologue\n");
4458 g_stack_fsz = g_seh_size;
4459 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4460 if (!(ops[i].flags & OPF_RMD))
4470 if (ecx_push || esp_sub)
4475 for (; i < opcnt; i++)
4476 if (ops[i].flags & OPF_TAIL)
4480 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4481 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4486 else if (i < opcnt && (ops[i].flags & OPF_ATAIL)) {
4487 // skip arg updates for arg-reuse tailcall
4488 for (; j >= 0; j--) {
4489 if (ops[j].op != OP_MOV)
4491 if (ops[j].operand[0].type != OPT_REGMEM)
4493 if (strstr(ops[j].operand[0].name, "arg_") == NULL)
4498 for (; j >= 0; j--) {
4499 if ((ops[j].flags & (OPF_RMD | OPF_DONE | OPF_NOREGS)) !=
4500 (OPF_RMD | OPF_DONE | OPF_NOREGS))
4504 if (ecx_push > 0 && !esp_sub) {
4505 for (l = 0; l < ecx_push && j >= 0; l++) {
4506 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
4508 else if (ops[j].op == OP_ADD
4509 && IS(opr_name(&ops[j], 0), "esp")
4510 && ops[j].operand[1].type == OPT_CONST)
4513 l += ops[j].operand[1].val / 4 - 1;
4518 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4521 if (l != ecx_push) {
4522 if (i < opcnt && ops[i].op == OP_CALL
4523 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4525 // noreturn tailcall with no epilogue
4530 ferr(&ops[j], "epilogue scan failed\n");
4537 if (ops[j].op == OP_ADD
4538 && IS(opr_name(&ops[j], 0), "esp")
4539 && ops[j].operand[1].type == OPT_CONST)
4541 if (ops[j].operand[1].val < g_stack_fsz)
4542 ferr(&ops[j], "esp adj is too low (need %d)\n", g_stack_fsz);
4544 ops[j].operand[1].val -= g_stack_fsz; // for stack arg scanner
4545 if (ops[j].operand[1].val == 0)
4546 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4549 else if (ops[j].op == OP_LEA && ops[j].operand[0].reg == xSP
4550 && ops[j].operand[1].type == OPT_REGMEM
4551 && IS_START(ops[j].operand[1].name, "esp+"))
4553 const char *name = ops[j].operand[1].name;
4554 ret = sscanf(name, "esp+%x%n", &l, &len);
4555 ferr_assert(&ops[j], ret == 1 && len == strlen(name));
4556 ferr_assert(&ops[j], l <= g_stack_fsz);
4557 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4560 else if (i < opcnt && ops[i].op == OP_CALL
4561 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4563 // noreturn tailcall with no epilogue
4567 ferr(&ops[j], "'add esp' expected\n");
4571 } while (i < opcnt);
4574 ferr(ops, "missing esp epilogue\n");
4577 if (g_stack_fsz != 0)
4578 // see check_simple_sequence
4579 g_stack_fsz += push_fsz;
4582 // find an instruction that changed opr before i op
4583 // *op_i must be set to -1 by the caller
4584 // *is_caller is set to 1 if one source is determined to be g_func arg
4585 // returns 1 if found, *op_i is then set to origin
4586 // returns -1 if multiple origins are found
4587 static int resolve_origin(int i, const struct parsed_opr *opr,
4588 int magic, int *op_i, int *is_caller)
4590 struct label_ref *lr;
4594 if (g_labels[i] != NULL) {
4595 lr = &g_label_refs[i];
4596 for (; lr != NULL; lr = lr->next) {
4597 check_i(&ops[i], lr->i);
4598 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4600 if (i > 0 && LAST_OP(i - 1))
4606 if (is_caller != NULL)
4611 if (ops[i].cc_scratch == magic)
4613 ops[i].cc_scratch = magic;
4615 if (!(ops[i].flags & OPF_DATA))
4617 if (!is_opr_modified(opr, &ops[i]))
4621 if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4632 // find an instruction that previously referenced opr
4633 // if multiple results are found - fail
4634 // *op_i must be set to -1 by the caller
4635 // returns 1 if found, *op_i is then set to referencer insn
4636 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4637 int magic, int *op_i)
4639 struct label_ref *lr;
4643 if (g_labels[i] != NULL) {
4644 lr = &g_label_refs[i];
4645 for (; lr != NULL; lr = lr->next) {
4646 check_i(&ops[i], lr->i);
4647 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4649 if (i > 0 && LAST_OP(i - 1))
4657 if (ops[i].cc_scratch == magic)
4659 ops[i].cc_scratch = magic;
4661 if (!is_opr_referenced(opr, &ops[i]))
4672 // adjust datap of all reachable 'op' insns when moving back
4673 // returns 1 if at least 1 op was found
4674 // returns -1 if path without an op was found
4675 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4677 struct label_ref *lr;
4680 if (ops[i].cc_scratch == magic)
4682 ops[i].cc_scratch = magic;
4685 if (g_labels[i] != NULL) {
4686 lr = &g_label_refs[i];
4687 for (; lr != NULL; lr = lr->next) {
4688 check_i(&ops[i], lr->i);
4689 ret |= adjust_prev_op(lr->i, op, magic, datap);
4691 if (i > 0 && LAST_OP(i - 1))
4699 if (ops[i].cc_scratch == magic)
4701 ops[i].cc_scratch = magic;
4703 if (ops[i].op != op)
4706 ops[i].datap = datap;
4711 // find next instruction that reads opr
4712 // *op_i must be set to -1 by the caller
4713 // on return, *op_i is set to first referencer insn
4714 // returns 1 if exactly 1 referencer is found
4715 static int find_next_read(int i, int opcnt,
4716 const struct parsed_opr *opr, int magic, int *op_i)
4718 struct parsed_op *po;
4721 for (; i < opcnt; i++)
4723 if (ops[i].cc_scratch == magic)
4725 ops[i].cc_scratch = magic;
4728 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4729 if (po->btj != NULL) {
4731 for (j = 0; j < po->btj->count; j++) {
4732 check_i(po, po->btj->d[j].bt_i);
4733 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4739 if (po->flags & OPF_RMD)
4741 check_i(po, po->bt_i);
4742 if (po->flags & OPF_CJMP) {
4743 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4752 if (!is_opr_read(opr, po)) {
4754 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4755 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4757 full_opr = po->operand[0].lmod >= opr->lmod;
4759 if (is_opr_modified(opr, po) && full_opr) {
4763 if (po->flags & OPF_TAIL)
4778 static int find_next_read_reg(int i, int opcnt, int reg,
4779 enum opr_lenmod lmod, int magic, int *op_i)
4781 struct parsed_opr opr = OPR_INIT(OPT_REG, lmod, reg);
4784 return find_next_read(i, opcnt, &opr, magic, op_i);
4787 // find next instruction that reads opr
4788 // *op_i must be set to -1 by the caller
4789 // on return, *op_i is set to first flag user insn
4790 // returns 1 if exactly 1 flag user is found
4791 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4793 struct parsed_op *po;
4796 for (; i < opcnt; i++)
4798 if (ops[i].cc_scratch == magic)
4800 ops[i].cc_scratch = magic;
4803 if (po->op == OP_CALL)
4805 if (po->flags & OPF_JMP) {
4806 if (po->btj != NULL) {
4808 for (j = 0; j < po->btj->count; j++) {
4809 check_i(po, po->btj->d[j].bt_i);
4810 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4816 if (po->flags & OPF_RMD)
4818 check_i(po, po->bt_i);
4819 if (po->flags & OPF_CJMP)
4826 if (!(po->flags & OPF_CC)) {
4827 if (po->flags & OPF_FLAGS)
4830 if (po->flags & OPF_TAIL)
4846 static int try_resolve_const(int i, const struct parsed_opr *opr,
4847 int magic, unsigned int *val)
4852 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4855 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4858 *val = ops[i].operand[1].val;
4865 static int resolve_used_bits(int i, int opcnt, int reg,
4866 int *mask, int *is_z_check)
4868 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4872 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4876 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4878 fnote(&ops[j], "(first read)\n");
4879 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4882 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4883 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4885 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4886 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4888 *mask = ops[j].operand[1].val;
4889 if (ops[j].operand[0].lmod == OPLM_BYTE
4890 && ops[j].operand[0].name[1] == 'h')
4894 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4897 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4899 *is_z_check = ops[k].pfo == PFO_Z;
4904 static const struct parsed_proto *resolve_deref(int i, int magic,
4905 struct parsed_opr *opr, int level)
4907 struct parsed_opr opr_s = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
4908 const struct parsed_proto *pp = NULL;
4909 int from_caller = 0;
4918 ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4919 if (ret != 2 || len != strlen(opr->name)) {
4920 ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4921 if (ret != 1 || len != strlen(opr->name))
4925 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4930 ret = resolve_origin(i, &opr_s, i + magic, &j, NULL);
4934 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4935 && strlen(ops[j].operand[1].name) == 3
4936 && ops[j].operand[0].lmod == OPLM_DWORD
4937 && ops[j].pp == NULL // no hint
4940 // allow one simple dereference (com/directx)
4941 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4942 ops[j].operand[1].name);
4946 ret = resolve_origin(j, &opr_s, j + magic, &k, NULL);
4951 if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
4954 if (ops[j].pp != NULL) {
4958 else if (ops[j].operand[1].type == OPT_REGMEM) {
4959 pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
4961 // maybe structure ptr in structure
4962 pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
4965 else if (ops[j].operand[1].type == OPT_LABEL)
4966 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4967 else if (ops[j].operand[1].type == OPT_REG) {
4970 ret = resolve_origin(j, &ops[j].operand[1], i + magic,
4972 if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
4973 for (k = 0; k < g_func_pp->argc; k++) {
4974 if (g_func_pp->arg[k].reg == NULL)
4976 if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
4977 pp = g_func_pp->arg[k].pp;
4986 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4988 ferr(&ops[j], "expected struct, got '%s %s'\n",
4989 pp->type.name, pp->name);
4993 return proto_lookup_struct(g_fhdr, pp->type.name, offset);
4996 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4997 int *pp_i, int *multi_src)
4999 const struct parsed_proto *pp = NULL;
5000 int search_advice = 0;
5005 switch (ops[i].operand[0].type) {
5007 // try to resolve struct member calls
5008 pp = resolve_deref(i, i + opcnt * 19, &ops[i].operand[0], 0);
5014 pp = try_recover_pp(&ops[i], &ops[i].operand[0],
5020 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
5028 static struct parsed_proto *process_call_early(int i, int opcnt,
5031 struct parsed_op *po = &ops[i];
5032 struct parsed_proto *pp;
5038 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
5042 // look for and make use of esp adjust
5044 if (!pp->is_stdcall && pp->argc_stack > 0)
5045 ret = scan_for_esp_adjust(i + 1, opcnt,
5046 pp->argc_stack * 4, &adj, &multipath, 0);
5048 if (pp->argc_stack > adj / 4)
5052 if (ops[ret].op == OP_POP) {
5053 for (j = 1; j < adj / 4; j++) {
5054 if (ops[ret + j].op != OP_POP
5055 || ops[ret + j].operand[0].reg != xCX)
5067 static struct parsed_proto *process_call(int i, int opcnt)
5069 struct parsed_op *po = &ops[i];
5070 const struct parsed_proto *pp_c;
5071 struct parsed_proto *pp;
5072 const char *tmpname;
5073 int call_i = -1, ref_i = -1;
5074 int adj = 0, multipath = 0;
5077 tmpname = opr_name(po, 0);
5082 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
5084 if (!pp_c->is_func && !pp_c->is_fptr)
5085 ferr(po, "call to non-func: %s\n", pp_c->name);
5086 pp = proto_clone(pp_c);
5087 my_assert_not(pp, NULL);
5089 // not resolved just to single func
5092 switch (po->operand[0].type) {
5094 // we resolved this call and no longer need the register
5095 po->regmask_src &= ~(1 << po->operand[0].reg);
5097 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
5098 && ops[call_i].operand[1].type == OPT_LABEL)
5100 // no other source users?
5101 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
5103 if (ret == 1 && call_i == ref_i) {
5104 // and nothing uses it after us?
5106 find_next_read(i + 1, opcnt, &po->operand[0],
5107 i + opcnt * 11, &ref_i);
5109 // then also don't need the source mov
5110 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
5122 pp = calloc(1, sizeof(*pp));
5123 my_assert_not(pp, NULL);
5126 ret = scan_for_esp_adjust(i + 1, opcnt,
5127 -1, &adj, &multipath, 0);
5128 if (ret < 0 || adj < 0) {
5129 if (!g_allow_regfunc)
5130 ferr(po, "non-__cdecl indirect call unhandled yet\n");
5131 pp->is_unresolved = 1;
5135 if (adj > ARRAY_SIZE(pp->arg))
5136 ferr(po, "esp adjust too large: %d\n", adj);
5137 pp->ret_type.name = strdup("int");
5138 pp->argc = pp->argc_stack = adj;
5139 for (arg = 0; arg < pp->argc; arg++)
5140 pp->arg[arg].type.name = strdup("int");
5145 // look for and make use of esp adjust
5148 if (!pp->is_stdcall && pp->argc_stack > 0) {
5149 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
5150 ret = scan_for_esp_adjust(i + 1, opcnt,
5151 adj_expect, &adj, &multipath, 0);
5154 if (pp->is_vararg) {
5155 if (adj / 4 < pp->argc_stack) {
5156 fnote(po, "(this call)\n");
5157 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
5158 adj, pp->argc_stack * 4);
5160 // modify pp to make it have varargs as normal args
5162 pp->argc += adj / 4 - pp->argc_stack;
5163 for (; arg < pp->argc; arg++) {
5164 pp->arg[arg].type.name = strdup("int");
5167 if (pp->argc > ARRAY_SIZE(pp->arg))
5168 ferr(po, "too many args for '%s'\n", tmpname);
5170 if (pp->argc_stack > adj / 4) {
5171 if (pp->is_noreturn)
5172 // assume no stack adjust was emited
5174 fnote(po, "(this call)\n");
5175 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
5176 tmpname, pp->argc_stack * 4, adj);
5179 scan_for_esp_adjust(i + 1, opcnt,
5180 pp->argc_stack * 4, &adj, &multipath, 1);
5182 else if (pp->is_vararg)
5183 ferr(po, "missing esp_adjust for vararg func '%s'\n",
5190 static void mark_float_arg(struct parsed_op *po,
5191 struct parsed_proto *pp, int arg, int *regmask_ffca)
5194 po->p_argnum = arg + 1;
5195 ferr_assert(po, pp->arg[arg].datap == NULL);
5196 pp->arg[arg].datap = po;
5197 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
5198 if (regmask_ffca != NULL)
5199 *regmask_ffca |= 1 << arg;
5202 static int check_for_stp(int i, int i_to)
5204 struct parsed_op *po;
5206 for (; i < i_to; i++) {
5208 if (po->op == OP_FST)
5210 if (g_labels[i] != NULL || (po->flags & OPF_JMP))
5212 if (po->op == OP_CALL || po->op == OP_PUSH || po->op == OP_POP)
5214 if (po->op == OP_ADD && po->operand[0].reg == xSP)
5221 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
5224 struct parsed_op *po;
5230 for (base_arg = 0; base_arg < pp->argc; base_arg++)
5231 if (pp->arg[base_arg].reg == NULL)
5234 for (j = i; j > 0; )
5236 ferr_assert(&ops[j], g_labels[j] == NULL);
5240 ferr_assert(po, po->op != OP_PUSH);
5241 if (po->op == OP_FST)
5243 if (po->operand[0].type != OPT_REGMEM)
5245 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
5248 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3)) {
5249 //ferr(po, "offset %d, %d args\n", offset, pp->argc_stack);
5253 arg = base_arg + offset / 4;
5254 mark_float_arg(po, pp, arg, regmask_ffca);
5256 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5257 && po->operand[1].type == OPT_CONST)
5259 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5264 for (arg = base_arg; arg < pp->argc; arg++) {
5265 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
5266 po = pp->arg[arg].datap;
5268 ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
5269 if (po->operand[0].lmod == OPLM_QWORD)
5276 static int collect_call_args_early(int i, struct parsed_proto *pp,
5277 int *regmask, int *regmask_ffca)
5279 struct parsed_op *po;
5284 for (arg = 0; arg < pp->argc; arg++)
5285 if (pp->arg[arg].reg == NULL)
5288 // first see if it can be easily done
5289 for (j = i; j > 0 && arg < pp->argc; )
5291 if (g_labels[j] != NULL)
5296 if (po->op == OP_CALL)
5298 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
5300 else if (po->op == OP_POP)
5302 else if (po->flags & OPF_CJMP)
5304 else if (po->op == OP_PUSH) {
5305 if (po->flags & (OPF_FARG|OPF_FARGNR))
5307 if (!g_header_mode) {
5308 ret = scan_for_mod(po, j + 1, i, 1);
5313 if (pp->arg[arg].type.is_va_list)
5317 for (arg++; arg < pp->argc; arg++)
5318 if (pp->arg[arg].reg == NULL)
5321 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5322 && po->operand[1].type == OPT_CONST)
5324 if (po->flags & (OPF_RMD|OPF_DONE))
5326 if (po->operand[1].val != pp->argc_stack * 4)
5327 ferr(po, "unexpected esp adjust: %d\n",
5328 po->operand[1].val * 4);
5329 ferr_assert(po, pp->argc - arg == pp->argc_stack);
5330 return collect_call_args_no_push(i, pp, regmask_ffca);
5338 for (arg = 0; arg < pp->argc; arg++)
5339 if (pp->arg[arg].reg == NULL)
5342 for (j = i; j > 0 && arg < pp->argc; )
5346 if (ops[j].op == OP_PUSH)
5348 ops[j].p_argnext = -1;
5349 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
5351 k = check_for_stp(j + 1, i);
5353 // push ecx; fstp dword ptr [esp]
5354 ret = parse_stack_esp_offset(&ops[k],
5355 ops[k].operand[0].name, &offset);
5356 if (ret == 0 && offset == 0) {
5357 if (!pp->arg[arg].type.is_float)
5358 ferr(&ops[i], "arg %d should be float\n", arg + 1);
5359 mark_float_arg(&ops[k], pp, arg, regmask_ffca);
5363 if (pp->arg[arg].datap == NULL) {
5364 pp->arg[arg].datap = &ops[j];
5365 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
5366 *regmask |= 1 << ops[j].operand[0].reg;
5369 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5370 ops[j].flags &= ~OPF_RSAVE;
5373 for (arg++; arg < pp->argc; arg++)
5374 if (pp->arg[arg].reg == NULL)
5382 static int sync_argnum(struct parsed_op *po, int argnum)
5384 struct parsed_op *po_tmp;
5386 // see if other branches don't have higher argnum
5387 for (po_tmp = po; po_tmp != NULL; ) {
5388 if (argnum < po_tmp->p_argnum)
5389 argnum = po_tmp->p_argnum;
5390 // note: p_argnext is active on current collect_call_args only
5391 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5394 // make all argnums consistent
5395 for (po_tmp = po; po_tmp != NULL; ) {
5396 if (po_tmp->p_argnum != 0)
5397 po_tmp->p_argnum = argnum;
5398 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5404 static int collect_call_args_r(struct parsed_op *po, int i,
5405 struct parsed_proto *pp, int *regmask, int *arg_grp,
5406 int arg, int argnum, int magic, int need_op_saving, int may_reuse)
5408 struct parsed_proto *pp_tmp;
5409 struct parsed_op *po_tmp;
5410 struct label_ref *lr;
5411 int need_to_save_current;
5412 int arg_grp_current = 0;
5413 int save_args_seen = 0;
5420 ferr(po, "dead label encountered\n");
5424 for (; arg < pp->argc; arg++, argnum++)
5425 if (pp->arg[arg].reg == NULL)
5427 magic = (magic & 0xffffff) | (arg << 24);
5429 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
5431 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
5432 if (ops[j].cc_scratch != magic) {
5433 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
5437 // ok: have already been here
5440 ops[j].cc_scratch = magic;
5442 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
5443 lr = &g_label_refs[j];
5444 if (lr->next != NULL)
5446 for (; lr->next; lr = lr->next) {
5447 check_i(&ops[j], lr->i);
5448 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5450 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5451 arg, argnum, magic, need_op_saving, may_reuse);
5456 check_i(&ops[j], lr->i);
5457 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5459 if (j > 0 && LAST_OP(j - 1)) {
5460 // follow last branch in reverse
5465 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5466 arg, argnum, magic, need_op_saving, may_reuse);
5472 if (ops[j].op == OP_CALL)
5474 if (pp->is_unresolved)
5479 ferr(po, "arg collect %d/%d hit unparsed call '%s'\n",
5480 arg, pp->argc, ops[j].operand[0].name);
5481 if (may_reuse && pp_tmp->argc_stack > 0)
5482 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
5483 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
5485 // esp adjust of 0 means we collected it before
5486 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
5487 && (ops[j].operand[1].type != OPT_CONST
5488 || ops[j].operand[1].val != 0))
5490 if (pp->is_unresolved)
5493 fnote(po, "(this call)\n");
5494 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
5495 arg, pp->argc, ops[j].operand[1].val);
5497 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
5499 if (pp->is_unresolved)
5502 fnote(po, "(this call)\n");
5503 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
5505 else if (ops[j].flags & OPF_CJMP)
5507 if (pp->is_unresolved)
5512 else if (ops[j].op == OP_PUSH
5513 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
5515 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
5518 ops[j].p_argnext = -1;
5519 po_tmp = pp->arg[arg].datap;
5521 ops[j].p_argnext = po_tmp - ops;
5522 pp->arg[arg].datap = &ops[j];
5524 argnum = sync_argnum(&ops[j], argnum);
5526 need_to_save_current = 0;
5528 if (ops[j].operand[0].type == OPT_REG)
5529 reg = ops[j].operand[0].reg;
5531 if (!need_op_saving) {
5532 ret = scan_for_mod(&ops[j], j + 1, i, 1);
5533 need_to_save_current = (ret >= 0);
5535 if (need_op_saving || need_to_save_current) {
5536 // mark this arg as one that needs operand saving
5537 pp->arg[arg].is_saved = 1;
5539 if (save_args_seen & (1 << (argnum - 1))) {
5542 if (arg_grp_current >= MAX_ARG_GRP)
5543 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
5547 else if (ops[j].p_argnum == 0)
5548 ops[j].flags |= OPF_RMD;
5550 // some PUSHes are reused by different calls on other branches,
5551 // but that can't happen if we didn't branch, so they
5552 // can be removed from future searches (handles nested calls)
5554 ops[j].flags |= OPF_FARGNR;
5556 ops[j].flags |= OPF_FARG;
5557 ops[j].flags &= ~OPF_RSAVE;
5559 // check for __VALIST
5560 if (!pp->is_unresolved && g_func_pp != NULL
5561 && pp->arg[arg].type.is_va_list)
5564 ret = resolve_origin(j, &ops[j].operand[0],
5565 magic + 1, &k, NULL);
5566 if (ret == 1 && k >= 0)
5568 if (ops[k].op == OP_LEA) {
5569 if (!g_func_pp->is_vararg)
5570 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
5573 snprintf(buf, sizeof(buf), "arg_%X",
5574 g_func_pp->argc_stack * 4);
5575 if (strstr(ops[k].operand[1].name, buf)
5576 || strstr(ops[k].operand[1].name, "arglist"))
5578 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
5579 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
5580 pp->arg[arg].is_saved = 0;
5584 ferr(&ops[k], "va_list arg detection failed\n");
5586 // check for va_list from g_func_pp arg too
5587 else if (ops[k].op == OP_MOV
5588 && is_stack_access(&ops[k], &ops[k].operand[1]))
5590 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5591 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5593 ops[k].flags |= OPF_RMD | OPF_DONE;
5594 ops[j].flags |= OPF_RMD;
5595 ops[j].p_argpass = ret + 1;
5596 pp->arg[arg].is_saved = 0;
5603 if (pp->arg[arg].is_saved) {
5604 ops[j].flags &= ~OPF_RMD;
5605 ops[j].p_argnum = argnum;
5608 // tracking reg usage
5610 *regmask |= 1 << reg;
5614 if (!pp->is_unresolved) {
5616 for (; arg < pp->argc; arg++, argnum++)
5617 if (pp->arg[arg].reg == NULL)
5620 magic = (magic & 0xffffff) | (arg << 24);
5623 if (ops[j].p_arggrp > arg_grp_current) {
5625 arg_grp_current = ops[j].p_arggrp;
5627 if (ops[j].p_argnum > 0)
5628 save_args_seen |= 1 << (ops[j].p_argnum - 1);
5631 if (arg < pp->argc) {
5632 ferr(po, "arg collect failed for '%s': %d/%d\n",
5633 pp->name, arg, pp->argc);
5637 if (arg_grp_current > *arg_grp)
5638 *arg_grp = arg_grp_current;
5643 static int collect_call_args(struct parsed_op *po, int i,
5644 struct parsed_proto *pp, int *regmask, int magic)
5646 // arg group is for cases when pushes for
5647 // multiple funcs are going on
5648 struct parsed_op *po_tmp;
5653 ret = collect_call_args_r(po, i, pp, regmask, &arg_grp,
5659 // propagate arg_grp
5660 for (a = 0; a < pp->argc; a++) {
5661 if (pp->arg[a].reg != NULL)
5664 po_tmp = pp->arg[a].datap;
5665 while (po_tmp != NULL) {
5666 po_tmp->p_arggrp = arg_grp;
5667 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5672 if (pp->is_unresolved) {
5674 pp->argc_stack += ret;
5675 for (a = 0; a < pp->argc; a++)
5676 if (pp->arg[a].type.name == NULL)
5677 pp->arg[a].type.name = strdup("int");
5683 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5684 int regmask_now, int *regmask,
5685 int regmask_save_now, int *regmask_save,
5686 int *regmask_init, int regmask_arg)
5688 struct parsed_op *po;
5696 for (; i < opcnt; i++)
5699 if (cbits[i >> 3] & (1 << (i & 7)))
5701 cbits[i >> 3] |= (1 << (i & 7));
5703 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5704 if (po->flags & (OPF_RMD|OPF_DONE))
5706 if (po->btj != NULL) {
5707 for (j = 0; j < po->btj->count; j++) {
5708 check_i(po, po->btj->d[j].bt_i);
5709 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5710 regmask_now, regmask, regmask_save_now, regmask_save,
5711 regmask_init, regmask_arg);
5716 check_i(po, po->bt_i);
5717 if (po->flags & OPF_CJMP)
5718 reg_use_pass(po->bt_i, opcnt, cbits,
5719 regmask_now, regmask, regmask_save_now, regmask_save,
5720 regmask_init, regmask_arg);
5726 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5727 && !g_func_pp->is_userstack
5728 && po->operand[0].type == OPT_REG)
5730 reg = po->operand[0].reg;
5731 ferr_assert(po, reg >= 0);
5734 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5735 if (regmask_now & (1 << reg)) {
5736 already_saved = regmask_save_now & (1 << reg);
5737 flags_set = OPF_RSAVE | OPF_DONE;
5740 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, 0);
5742 scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5743 reg, 0, 0, flags_set);
5746 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5748 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5753 ferr_assert(po, !already_saved);
5754 po->flags |= flags_set;
5756 if (regmask_now & (1 << reg)) {
5757 regmask_save_now |= (1 << reg);
5758 *regmask_save |= regmask_save_now;
5763 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5764 reg = po->operand[0].reg;
5765 ferr_assert(po, reg >= 0);
5767 if (regmask_save_now & (1 << reg))
5768 regmask_save_now &= ~(1 << reg);
5770 regmask_now &= ~(1 << reg);
5773 else if (po->op == OP_CALL) {
5774 if ((po->regmask_dst & (1 << xAX))
5775 && !(po->regmask_dst & (1 << xDX)))
5777 if (po->flags & OPF_TAIL)
5778 // don't need eax, will do "return f();" or "f(); return;"
5779 po->regmask_dst &= ~(1 << xAX);
5781 find_next_read_reg(i + 1, opcnt, xAX, OPLM_DWORD,
5782 i + opcnt * 17, &j);
5785 po->regmask_dst &= ~(1 << xAX);
5789 // not "full stack" mode and have something in stack
5790 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5791 ferr(po, "float stack is not empty on func call\n");
5794 if (po->flags & OPF_NOREGS)
5797 // if incomplete register is used, clear it on init to avoid
5798 // later use of uninitialized upper part in some situations
5799 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5800 && po->operand[0].lmod != OPLM_DWORD)
5802 reg = po->operand[0].reg;
5803 ferr_assert(po, reg >= 0);
5805 if (!(regmask_now & (1 << reg)))
5806 *regmask_init |= 1 << reg;
5809 regmask_op = po->regmask_src | po->regmask_dst;
5811 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5812 regmask_new &= ~(1 << xSP);
5813 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5814 regmask_new &= ~(1 << xBP);
5816 if (regmask_new != 0)
5817 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5819 if (regmask_op & (1 << xBP)) {
5820 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5821 if (po->regmask_dst & (1 << xBP))
5822 // compiler decided to drop bp frame and use ebp as scratch
5823 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5825 regmask_op &= ~(1 << xBP);
5829 if (po->flags & OPF_FPUSH) {
5830 if (regmask_now & mxST1)
5831 regmask_now |= mxSTa; // switch to "full stack" mode
5832 if (regmask_now & mxSTa)
5833 po->flags |= OPF_FSHIFT;
5834 if (!(regmask_now & mxST7_2)) {
5836 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5840 regmask_now |= regmask_op;
5841 *regmask |= regmask_now;
5844 if (po->flags & OPF_FPOPP) {
5845 if ((regmask_now & mxSTa) == 0)
5846 ferr(po, "float pop on empty stack?\n");
5847 if (regmask_now & mxST7_2)
5848 po->flags |= OPF_FSHIFT;
5849 if (!(regmask_now & mxST7_2))
5850 regmask_now &= ~mxST1_0;
5852 else if (po->flags & OPF_FPOP) {
5853 if ((regmask_now & mxSTa) == 0)
5854 ferr(po, "float pop on empty stack?\n");
5855 if (regmask_now & (mxST7_2 | mxST1))
5856 po->flags |= OPF_FSHIFT;
5857 if (!(regmask_now & mxST7_2)) {
5859 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5863 if (po->flags & OPF_TAIL) {
5864 if (!(regmask_now & mxST7_2)) {
5865 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5866 if (!(regmask_now & mxST0))
5867 ferr(po, "no st0 on float return, mask: %x\n",
5870 else if (regmask_now & mxST1_0)
5871 ferr(po, "float regs on tail: %x\n", regmask_now);
5874 // there is support for "conditional tailcall", sort of
5875 if (!(po->flags & OPF_CC))
5881 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5885 for (i = 0; i < pp->argc; i++)
5886 if (pp->arg[i].reg == NULL)
5890 memmove(&pp->arg[i + 1], &pp->arg[i],
5891 sizeof(pp->arg[0]) * pp->argc_stack);
5892 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5893 pp->arg[i].reg = strdup(reg);
5894 pp->arg[i].type.name = strdup("int");
5899 static void output_std_flag_z(FILE *fout, struct parsed_op *po,
5900 int *pfomask, const char *dst_opr_text)
5902 if (*pfomask & (1 << PFO_Z)) {
5903 fprintf(fout, "\n cond_z = (%s%s == 0);",
5904 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5905 *pfomask &= ~(1 << PFO_Z);
5909 static void output_std_flag_s(FILE *fout, struct parsed_op *po,
5910 int *pfomask, const char *dst_opr_text)
5912 if (*pfomask & (1 << PFO_S)) {
5913 fprintf(fout, "\n cond_s = (%s%s < 0);",
5914 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5915 *pfomask &= ~(1 << PFO_S);
5919 static void output_std_flags(FILE *fout, struct parsed_op *po,
5920 int *pfomask, const char *dst_opr_text)
5922 output_std_flag_z(fout, po, pfomask, dst_opr_text);
5923 output_std_flag_s(fout, po, pfomask, dst_opr_text);
5927 OPP_FORCE_NORETURN = (1 << 0),
5928 OPP_SIMPLE_ARGS = (1 << 1),
5929 OPP_ALIGN = (1 << 2),
5932 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
5935 const char *cconv = "";
5937 if (pp->is_fastcall)
5938 cconv = "__fastcall ";
5939 else if (pp->is_stdcall && pp->argc_reg == 0)
5940 cconv = "__stdcall ";
5942 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5944 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
5945 fprintf(fout, "noreturn ");
5948 static void output_pp(FILE *fout, const struct parsed_proto *pp,
5953 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5957 output_pp_attrs(fout, pp, flags);
5960 fprintf(fout, "%s", pp->name);
5965 for (i = 0; i < pp->argc; i++) {
5967 fprintf(fout, ", ");
5968 if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
5969 && !(flags & OPP_SIMPLE_ARGS))
5972 output_pp(fout, pp->arg[i].pp, 0);
5974 else if (pp->arg[i].type.is_retreg) {
5975 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
5978 fprintf(fout, "%s", pp->arg[i].type.name);
5980 fprintf(fout, " a%d", i + 1);
5983 if (pp->arg[i].type.is_64bit)
5986 if (pp->is_vararg) {
5988 fprintf(fout, ", ");
5989 fprintf(fout, "...");
5994 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
6000 snprintf(buf1, sizeof(buf1), "%d", grp);
6001 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
6006 static void gen_x_cleanup(int opcnt);
6008 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
6010 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
6011 struct parsed_opr *last_arith_dst = NULL;
6012 char buf1[256], buf2[256], buf3[256], cast[64];
6013 struct parsed_proto *pp, *pp_tmp;
6014 struct parsed_data *pd;
6015 int save_arg_vars[MAX_ARG_GRP] = { 0, };
6016 unsigned char cbits[MAX_OPS / 8];
6017 const char *float_type;
6018 const char *float_st0;
6019 const char *float_st1;
6020 int need_float_stack = 0;
6021 int need_float_sw = 0; // status word
6022 int need_tmp_var = 0;
6026 int label_pending = 0;
6027 int need_double = 0;
6028 int stack_align = 0;
6029 int stack_fsz_adj = 0;
6030 int lock_handled = 0;
6031 int regmask_save = 0; // used regs saved/restored in this func
6032 int regmask_arg; // regs from this function args (fastcall, etc)
6033 int regmask_ret; // regs needed on ret
6034 int regmask_now; // temp
6035 int regmask_init = 0; // regs that need zero initialization
6036 int regmask_pp = 0; // regs used in complex push-pop graph
6037 int regmask_ffca = 0; // float function call args
6038 int regmask = 0; // used regs
6048 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
6049 g_stack_frame_used = 0;
6051 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
6052 regmask_init = g_regmask_init;
6054 g_func_pp = proto_parse(fhdr, funcn, 0);
6055 if (g_func_pp == NULL)
6056 ferr(ops, "proto_parse failed for '%s'\n", funcn);
6058 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
6059 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
6062 // - resolve all branches
6063 // - parse calls with labels
6064 resolve_branches_parse_calls(opcnt);
6067 // - handle ebp/esp frame, remove ops related to it
6068 scan_prologue_epilogue(opcnt, &stack_align);
6070 // handle a case where sf size is unalignment, but is
6071 // placed in a way that elements are still aligned
6072 if (g_stack_fsz & 4) {
6073 for (i = 0; i < g_eqcnt; i++) {
6074 if (g_eqs[i].lmod != OPLM_QWORD)
6076 if (!(g_eqs[i].offset & 4)) {
6085 // - remove dead labels
6086 // - set regs needed at ret
6087 for (i = 0; i < opcnt; i++)
6089 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
6094 if (ops[i].op == OP_RET)
6095 ops[i].regmask_src |= regmask_ret;
6099 // - process trivial calls
6100 for (i = 0; i < opcnt; i++)
6103 if (po->flags & (OPF_RMD|OPF_DONE))
6106 if (po->op == OP_CALL)
6108 pp = process_call_early(i, opcnt, &j);
6110 if (!(po->flags & OPF_ATAIL)) {
6111 // since we know the args, try to collect them
6112 ret = collect_call_args_early(i, pp, ®mask, ®mask_ffca);
6120 // commit esp adjust
6121 if (ops[j].op != OP_POP)
6122 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
6124 for (l = 0; l < pp->argc_stack; l++)
6125 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
6129 if (strstr(pp->ret_type.name, "int64"))
6132 po->flags |= OPF_DONE;
6138 // - process calls, stage 2
6139 // - handle some push/pop pairs
6140 // - scan for STD/CLD, propagate DF
6141 // - try to resolve needed x87 status word bits
6142 for (i = 0; i < opcnt; i++)
6147 if (po->flags & OPF_RMD)
6150 if (po->op == OP_CALL)
6152 if (!(po->flags & OPF_DONE)) {
6153 pp = process_call(i, opcnt);
6155 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
6156 // since we know the args, collect them
6157 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
6159 // for unresolved, collect after other passes
6163 ferr_assert(po, pp != NULL);
6165 po->regmask_src |= get_pp_arg_regmask_src(pp);
6166 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
6168 if (po->regmask_dst & mxST0)
6169 po->flags |= OPF_FPUSH;
6171 if (strstr(pp->ret_type.name, "int64"))
6177 if (po->flags & OPF_DONE)
6182 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
6183 && po->operand[0].type == OPT_CONST)
6185 scan_for_pop_const(i, opcnt, i + opcnt * 12);
6190 scan_pushes_for_pop(i, opcnt, ®mask_pp);
6194 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
6195 scan_propagate_df(i + 1, opcnt);
6200 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
6201 ferr(po, "TODO: fnstsw to mem\n");
6202 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
6204 ferr(po, "fnstsw resolve failed\n");
6205 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
6206 (void *)(long)(mask | (z_check << 16)));
6208 ferr(po, "failed to find fcom: %d\n", ret);
6217 // - find POPs for PUSHes, rm both
6218 // - scan for all used registers
6219 memset(cbits, 0, sizeof(cbits));
6220 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
6221 0, ®mask_save, ®mask_init, regmask_arg);
6223 need_float_stack = !!(regmask & mxST7_2);
6226 // - find flag set ops for their users
6227 // - do unresolved calls
6228 // - declare indirect functions
6229 // - other op specific processing
6230 for (i = 0; i < opcnt; i++)
6233 if (po->flags & (OPF_RMD|OPF_DONE))
6236 if (po->flags & OPF_CC)
6238 int setters[16], cnt = 0, branched = 0;
6240 ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
6241 &branched, setters, &cnt);
6242 if (ret < 0 || cnt <= 0)
6243 ferr(po, "unable to trace flag setter(s)\n");
6244 if (cnt > ARRAY_SIZE(setters))
6245 ferr(po, "too many flag setters\n");
6247 for (j = 0; j < cnt; j++)
6249 tmp_op = &ops[setters[j]]; // flag setter
6252 // to get nicer code, we try to delay test and cmp;
6253 // if we can't because of operand modification, or if we
6254 // have arith op, or branch, make it calculate flags explicitly
6255 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
6257 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
6258 pfomask = 1 << po->pfo;
6260 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
6261 pfomask = 1 << po->pfo;
6264 // see if we'll be able to handle based on op result
6265 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
6266 && po->pfo != PFO_Z && po->pfo != PFO_S
6267 && po->pfo != PFO_P)
6269 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
6271 pfomask = 1 << po->pfo;
6274 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
6275 propagate_lmod(tmp_op, &tmp_op->operand[0],
6276 &tmp_op->operand[1]);
6277 if (tmp_op->operand[0].lmod == OPLM_DWORD)
6282 tmp_op->pfomask |= pfomask;
6283 cond_vars |= pfomask;
6285 // note: may overwrite, currently not a problem
6289 if (po->op == OP_RCL || po->op == OP_RCR
6290 || po->op == OP_ADC || po->op == OP_SBB)
6291 cond_vars |= 1 << PFO_C;
6297 cond_vars |= 1 << PFO_Z;
6301 if (po->operand[0].lmod == OPLM_DWORD)
6306 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
6311 // note: resolved non-reg calls are OPF_DONE already
6313 ferr_assert(po, pp != NULL);
6315 if (pp->is_unresolved) {
6316 int regmask_stack = 0;
6317 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
6319 // this is pretty rough guess:
6320 // see ecx and edx were pushed (and not their saved versions)
6321 for (arg = 0; arg < pp->argc; arg++) {
6322 if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
6325 tmp_op = pp->arg[arg].datap;
6327 ferr(po, "parsed_op missing for arg%d\n", arg);
6328 if (tmp_op->operand[0].type == OPT_REG)
6329 regmask_stack |= 1 << tmp_op->operand[0].reg;
6332 if (!((regmask_stack & (1 << xCX))
6333 && (regmask_stack & (1 << xDX))))
6335 if (pp->argc_stack != 0
6336 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
6338 pp_insert_reg_arg(pp, "ecx");
6339 pp->is_fastcall = 1;
6340 regmask_init |= 1 << xCX;
6341 regmask |= 1 << xCX;
6343 if (pp->argc_stack != 0
6344 || ((regmask | regmask_arg) & (1 << xDX)))
6346 pp_insert_reg_arg(pp, "edx");
6347 regmask_init |= 1 << xDX;
6348 regmask |= 1 << xDX;
6352 // note: __cdecl doesn't fall into is_unresolved category
6353 if (pp->argc_stack > 0)
6356 if (!(po->flags & OPF_TAIL)
6357 && !(g_sct_func_attr & SCTFA_NOWARN) && !g_nowarn_reguse)
6359 // treat al write as overwrite to avoid many false positives
6360 if (IS(pp->ret_type.name, "void") || pp->ret_type.is_float) {
6361 find_next_read_reg(i + 1, opcnt, xAX, OPLM_BYTE,
6362 i + opcnt * 25, &j);
6364 fnote(po, "eax used after void/float ret call\n");
6365 fnote(&ops[j], "(used here)\n");
6368 if (!strstr(pp->ret_type.name, "int64")) {
6369 find_next_read_reg(i + 1, opcnt, xDX, OPLM_BYTE,
6370 i + opcnt * 26, &j);
6371 // indirect calls are often guessed, don't warn
6372 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j])) {
6373 fnote(po, "edx used after 32bit ret call\n");
6374 fnote(&ops[j], "(used here)\n");
6378 // msvc often relies on callee not modifying 'this'
6379 for (arg = 0; arg < pp->argc; arg++) {
6380 if (pp->arg[arg].reg && IS(pp->arg[arg].reg, "ecx")) {
6386 find_next_read_reg(i + 1, opcnt, xCX, OPLM_BYTE,
6387 i + opcnt * 27, &j);
6388 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j])) {
6389 fnote(po, "ecx used after call\n");
6390 fnote(&ops[j], "(used here)\n");
6397 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
6399 // <var> = offset <something>
6400 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
6401 && !IS_START(po->operand[1].name, "off_"))
6403 if (!po->operand[0].pp->is_fptr)
6404 ferr(po, "%s not declared as fptr when it should be\n",
6405 po->operand[0].name);
6406 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
6407 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
6408 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
6409 fnote(po, "var: %s\n", buf1);
6410 fnote(po, "func: %s\n", buf2);
6411 ferr(po, "^ mismatch\n");
6419 if (po->operand[0].lmod == OPLM_DWORD) {
6420 // 32bit division is common, look for it
6421 if (po->op == OP_DIV)
6422 ret = scan_for_reg_clear(i, xDX);
6424 ret = scan_for_cdq_edx(i);
6426 po->flags |= OPF_32BIT;
6435 po->flags |= OPF_RMD | OPF_DONE;
6445 if (po->operand[0].lmod == OPLM_QWORD)
6456 find_next_read_reg(i + 1, opcnt, xDX, OPLM_DWORD,
6457 i + opcnt * 18, &j);
6459 po->flags |= OPF_32BIT;
6466 // this might need it's own pass...
6467 if (po->op != OP_FST && po->p_argnum > 0)
6468 save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
6470 // correct for "full stack" mode late enable
6471 if ((po->flags & (OPF_PPUSH|OPF_FPOP|OPF_FPOPP))
6472 && need_float_stack)
6473 po->flags |= OPF_FSHIFT;
6476 float_type = need_double ? "double" : "float";
6477 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
6478 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
6480 // output starts here
6483 fprintf(fout, "// had SEH\n");
6485 // define userstack size
6486 if (g_func_pp->is_userstack) {
6487 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
6488 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
6489 fprintf(fout, "#endif\n");
6492 // the function itself
6493 ferr_assert(ops, !g_func_pp->is_fptr);
6494 output_pp(fout, g_func_pp,
6495 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
6496 fprintf(fout, "\n{\n");
6498 // declare indirect functions
6499 for (i = 0; i < opcnt; i++) {
6501 if (po->flags & OPF_RMD)
6504 if (po->op == OP_CALL) {
6507 ferr(po, "NULL pp\n");
6509 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
6510 if (pp->name[0] != 0) {
6511 if (IS_START(pp->name, "guess"))
6514 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
6515 memcpy(pp->name, "i_", 2);
6517 // might be declared already
6519 for (j = 0; j < i; j++) {
6520 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
6521 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
6531 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
6534 output_pp(fout, pp, OPP_SIMPLE_ARGS);
6535 fprintf(fout, ";\n");
6540 // output LUTs/jumptables
6541 for (i = 0; i < g_func_pd_cnt; i++) {
6543 fprintf(fout, " static const ");
6544 if (pd->type == OPT_OFFSET) {
6545 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
6547 for (j = 0; j < pd->count; j++) {
6549 fprintf(fout, ", ");
6550 fprintf(fout, "&&%s", pd->d[j].u.label);
6554 fprintf(fout, "%s %s[] =\n { ",
6555 lmod_type_u(ops, pd->lmod), pd->label);
6557 for (j = 0; j < pd->count; j++) {
6559 fprintf(fout, ", ");
6560 fprintf(fout, "%u", pd->d[j].u.val);
6563 fprintf(fout, " };\n");
6567 // declare stack frame, va_arg
6570 fprintf(fout, " // stack_fsz_adj %d\n", stack_fsz_adj);
6572 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
6573 if (g_func_lmods & (1 << OPLM_WORD))
6574 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
6575 if (g_func_lmods & (1 << OPLM_BYTE))
6576 fprintf(fout, " u8 b[%d];", g_stack_fsz);
6577 if (g_func_lmods & (1 << OPLM_QWORD))
6578 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
6580 if (stack_align > 8)
6581 ferr(ops, "unhandled stack align of %d\n", stack_align);
6582 else if (stack_align == 8)
6583 fprintf(fout, " u64 align;");
6584 fprintf(fout, " } sf;\n");
6588 if ((g_sct_func_attr & SCTFA_ARGFRAME) && g_func_pp->argc_stack) {
6589 fprintf(fout, " struct { u32 ");
6590 for (i = j = 0; i < g_func_pp->argc; i++) {
6591 if (g_func_pp->arg[i].reg != NULL)
6594 fprintf(fout, ", ");
6595 fprintf(fout, "a%d", i + 1);
6597 fprintf(fout, "; } af = {\n ");
6598 for (i = j = 0; i < g_func_pp->argc; i++) {
6599 if (g_func_pp->arg[i].reg != NULL)
6602 fprintf(fout, ", ");
6603 if (g_func_pp->arg[i].type.is_ptr)
6604 fprintf(fout, "(u32)");
6605 fprintf(fout, "a%d", i + 1);
6607 fprintf(fout, "\n };\n");
6610 if (g_func_pp->is_userstack) {
6611 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
6612 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
6616 if (g_func_pp->is_vararg) {
6617 fprintf(fout, " va_list ap;\n");
6621 // declare arg-registers
6622 for (i = 0; i < g_func_pp->argc; i++) {
6623 if (g_func_pp->arg[i].reg != NULL) {
6624 reg = char_array_i(regs_r32,
6625 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
6626 if (regmask & (1 << reg)) {
6627 if (g_func_pp->arg[i].type.is_retreg)
6628 fprintf(fout, " u32 %s = *r_%s;\n",
6629 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
6631 fprintf(fout, " u32 %s = (u32)a%d;\n",
6632 g_func_pp->arg[i].reg, i + 1);
6635 if (g_func_pp->arg[i].type.is_retreg)
6636 ferr(ops, "retreg '%s' is unused?\n",
6637 g_func_pp->arg[i].reg);
6638 fprintf(fout, " // %s = a%d; // unused\n",
6639 g_func_pp->arg[i].reg, i + 1);
6645 // declare normal registers
6646 regmask_now = regmask & ~regmask_arg & ~g_regmask_rm;
6647 regmask_now &= ~(1 << xSP);
6648 if (regmask_now & 0x00ff) {
6649 for (reg = 0; reg < 8; reg++) {
6650 if (regmask_now & (1 << reg)) {
6651 fprintf(fout, " u32 %s", regs_r32[reg]);
6652 if (regmask_init & (1 << reg))
6653 fprintf(fout, " = 0");
6654 fprintf(fout, ";\n");
6660 if (regmask_now & 0xff00) {
6661 for (reg = 8; reg < 16; reg++) {
6662 if (regmask_now & (1 << reg)) {
6663 fprintf(fout, " mmxr %s", regs_r32[reg]);
6664 if (regmask_init & (1 << reg))
6665 fprintf(fout, " = { 0, }");
6666 fprintf(fout, ";\n");
6672 if (need_float_stack) {
6673 fprintf(fout, " %s f_st[8];\n", float_type);
6674 fprintf(fout, " int f_stp = 0;\n");
6678 if (regmask_now & 0xff0000) {
6679 for (reg = 16; reg < 24; reg++) {
6680 if (regmask_now & (1 << reg)) {
6681 fprintf(fout, " %s f_st%d", float_type, reg - 16);
6682 if (regmask_init & (1 << reg))
6683 fprintf(fout, " = 0");
6684 fprintf(fout, ";\n");
6691 if (need_float_sw) {
6692 fprintf(fout, " u16 f_sw;\n");
6697 for (reg = 0; reg < 8; reg++) {
6698 if (regmask_save & (1 << reg)) {
6699 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
6705 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6706 if (save_arg_vars[i] == 0)
6708 for (reg = 0; reg < 32; reg++) {
6709 if (save_arg_vars[i] & (1 << reg)) {
6710 fprintf(fout, " u32 %s;\n",
6711 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
6718 for (reg = 0; reg < 32; reg++) {
6719 if (regmask_ffca & (1 << reg)) {
6720 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
6726 // declare push-pop temporaries
6728 for (reg = 0; reg < 8; reg++) {
6729 if (regmask_pp & (1 << reg)) {
6730 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
6737 for (i = 0; i < 8; i++) {
6738 if (cond_vars & (1 << i)) {
6739 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
6746 fprintf(fout, " u32 tmp;\n");
6751 fprintf(fout, " u64 tmp64;\n");
6756 fprintf(fout, "\n");
6758 // do stack clear, if needed
6759 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6761 if (g_stack_clear_len != 0) {
6762 if (g_stack_clear_len <= 4) {
6763 for (i = 0; i < g_stack_clear_len; i++)
6764 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6765 fprintf(fout, "0;\n");
6768 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6769 g_stack_clear_start, g_stack_clear_len * 4);
6773 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6776 if (g_func_pp->is_vararg) {
6777 if (g_func_pp->argc_stack == 0)
6778 ferr(ops, "vararg func without stack args?\n");
6779 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
6783 for (i = 0; i < opcnt; i++)
6785 if (g_labels[i] != NULL) {
6786 fprintf(fout, "\n%s:\n", g_labels[i]);
6789 delayed_flag_op = NULL;
6790 last_arith_dst = NULL;
6794 if (po->flags & OPF_RMD)
6800 #define assert_operand_cnt(n_) \
6801 if (po->operand_cnt != n_) \
6802 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6804 // conditional/flag using op?
6805 if (po->flags & OPF_CC)
6811 // we go through all this trouble to avoid using parsed_flag_op,
6812 // which makes generated code much nicer
6813 if (delayed_flag_op != NULL)
6815 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6816 po->pfo, po->pfo_inv);
6819 else if (last_arith_dst != NULL
6820 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6821 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6824 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6825 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6826 last_arith_dst->lmod, buf3);
6829 else if (tmp_op != NULL) {
6830 // use preprocessed flag calc results
6831 if (!(tmp_op->pfomask & (1 << po->pfo)))
6832 ferr(po, "not prepared for pfo %d\n", po->pfo);
6834 // note: pfo_inv was not yet applied
6835 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6836 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6839 ferr(po, "all methods of finding comparison failed\n");
6842 if (po->flags & OPF_JMP) {
6843 fprintf(fout, " if %s", buf1);
6845 else if (po->op == OP_RCL || po->op == OP_RCR
6846 || po->op == OP_ADC || po->op == OP_SBB)
6849 fprintf(fout, " cond_%s = %s;\n",
6850 parsed_flag_op_names[po->pfo], buf1);
6852 else if (po->flags & OPF_DATA) { // SETcc
6853 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6854 fprintf(fout, " %s = %s;", buf2, buf1);
6857 ferr(po, "unhandled conditional op\n");
6861 pfomask = po->pfomask;
6866 assert_operand_cnt(2);
6867 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6868 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6869 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
6870 fprintf(fout, " %s = %s;", buf1,
6871 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6876 assert_operand_cnt(2);
6877 po->operand[1].lmod = OPLM_DWORD; // always
6878 fprintf(fout, " %s = %s;",
6879 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6880 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6885 assert_operand_cnt(2);
6886 fprintf(fout, " %s = %s;",
6887 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6888 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6892 assert_operand_cnt(2);
6893 switch (po->operand[1].lmod) {
6895 strcpy(buf3, "(s8)");
6898 strcpy(buf3, "(s16)");
6901 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6903 fprintf(fout, " %s = %s;",
6904 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6905 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6910 assert_operand_cnt(2);
6911 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6912 fprintf(fout, " tmp = %s;",
6913 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6914 fprintf(fout, " %s = %s;",
6915 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6916 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6917 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6918 fprintf(fout, " %s = %stmp;",
6919 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6920 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
6921 snprintf(g_comment, sizeof(g_comment), "xchg");
6925 assert_operand_cnt(1);
6926 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6927 fprintf(fout, " %s = ~%s;", buf1, buf1);
6931 assert_operand_cnt(2);
6932 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6933 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6934 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6935 strcpy(g_comment, "xlat");
6939 assert_operand_cnt(2);
6940 fprintf(fout, " %s = (s32)%s >> 31;",
6941 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6942 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6943 strcpy(g_comment, "cdq");
6947 assert_operand_cnt(1);
6948 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6949 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
6953 if (po->flags & OPF_REP) {
6954 assert_operand_cnt(3);
6959 assert_operand_cnt(2);
6960 fprintf(fout, " %s = %sesi; esi %c= %d;",
6961 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6962 lmod_cast_u_ptr(po, po->operand[1].lmod),
6963 (po->flags & OPF_DF) ? '-' : '+',
6964 lmod_bytes(po, po->operand[1].lmod));
6965 strcpy(g_comment, "lods");
6970 if (po->flags & OPF_REP) {
6971 assert_operand_cnt(3);
6972 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
6973 (po->flags & OPF_DF) ? '-' : '+',
6974 lmod_bytes(po, po->operand[1].lmod));
6975 fprintf(fout, " %sedi = eax;\n",
6976 lmod_cast_u_ptr(po, po->operand[1].lmod));
6977 fprintf(fout, " barrier();");
6978 strcpy(g_comment, "^ rep stos");
6981 assert_operand_cnt(2);
6982 fprintf(fout, " %sedi = eax; edi %c= %d;",
6983 lmod_cast_u_ptr(po, po->operand[1].lmod),
6984 (po->flags & OPF_DF) ? '-' : '+',
6985 lmod_bytes(po, po->operand[1].lmod));
6986 strcpy(g_comment, "stos");
6991 j = lmod_bytes(po, po->operand[0].lmod);
6992 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6993 l = (po->flags & OPF_DF) ? '-' : '+';
6994 if (po->flags & OPF_REP) {
6995 assert_operand_cnt(3);
6997 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
7000 " %sedi = %sesi;\n", buf1, buf1);
7001 // this can overwrite many variables
7002 fprintf(fout, " barrier();");
7003 strcpy(g_comment, "^ rep movs");
7006 assert_operand_cnt(2);
7007 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
7008 buf1, buf1, l, j, l, j);
7009 strcpy(g_comment, "movs");
7014 // repe ~ repeat while ZF=1
7015 j = lmod_bytes(po, po->operand[0].lmod);
7016 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
7017 l = (po->flags & OPF_DF) ? '-' : '+';
7018 if (po->flags & OPF_REP) {
7019 assert_operand_cnt(3);
7021 " while (ecx != 0) {\n");
7022 if (pfomask & (1 << PFO_C)) {
7025 " cond_c = %sesi < %sedi;\n", buf1, buf1);
7026 pfomask &= ~(1 << PFO_C);
7029 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
7030 buf1, buf1, l, j, l, j);
7033 " if (cond_z %s 0) break;\n",
7034 (po->flags & OPF_REPZ) ? "==" : "!=");
7037 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
7038 (po->flags & OPF_REPZ) ? "e" : "ne");
7041 assert_operand_cnt(2);
7043 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
7044 buf1, buf1, l, j, l, j);
7045 strcpy(g_comment, "cmps");
7047 pfomask &= ~(1 << PFO_Z);
7048 last_arith_dst = NULL;
7049 delayed_flag_op = NULL;
7053 // only does ZF (for now)
7054 // repe ~ repeat while ZF=1
7055 j = lmod_bytes(po, po->operand[1].lmod);
7056 l = (po->flags & OPF_DF) ? '-' : '+';
7057 if (po->flags & OPF_REP) {
7058 assert_operand_cnt(3);
7060 " while (ecx != 0) {\n");
7062 " cond_z = (%seax == %sedi); edi %c= %d;\n",
7063 lmod_cast_u(po, po->operand[1].lmod),
7064 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
7067 " if (cond_z %s 0) break;\n",
7068 (po->flags & OPF_REPZ) ? "==" : "!=");
7071 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
7072 (po->flags & OPF_REPZ) ? "e" : "ne");
7075 assert_operand_cnt(2);
7076 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
7077 lmod_cast_u(po, po->operand[1].lmod),
7078 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
7079 strcpy(g_comment, "scas");
7081 pfomask &= ~(1 << PFO_Z);
7082 last_arith_dst = NULL;
7083 delayed_flag_op = NULL;
7087 fprintf(fout, " tmp64 = ext_rdtsc();\n");
7088 fprintf(fout, " edx = tmp64 >> 32;\n");
7089 fprintf(fout, " eax = tmp64;");
7093 fprintf(fout, " ext_cpuid(&eax, &ebx, &ecx, &edx);");
7096 // arithmetic w/flags
7098 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
7099 goto dualop_arith_const;
7100 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7104 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7105 if (po->operand[1].type == OPT_CONST) {
7106 j = lmod_bytes(po, po->operand[0].lmod);
7107 if (((1ull << j * 8) - 1) == po->operand[1].val)
7108 goto dualop_arith_const;
7113 assert_operand_cnt(2);
7114 fprintf(fout, " %s %s= %s;",
7115 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7117 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7118 output_std_flags(fout, po, &pfomask, buf1);
7119 last_arith_dst = &po->operand[0];
7120 delayed_flag_op = NULL;
7124 // and 0, or ~0 used instead mov
7125 assert_operand_cnt(2);
7126 fprintf(fout, " %s = %s;",
7127 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7128 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
7129 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7130 output_std_flags(fout, po, &pfomask, buf1);
7131 last_arith_dst = &po->operand[0];
7132 delayed_flag_op = NULL;
7137 assert_operand_cnt(2);
7138 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7139 if (pfomask & (1 << PFO_C)) {
7140 if (po->operand[1].type == OPT_CONST) {
7141 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7142 j = po->operand[1].val;
7145 if (po->op == OP_SHL)
7149 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
7153 ferr(po, "zero shift?\n");
7157 pfomask &= ~(1 << PFO_C);
7159 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
7160 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7161 if (po->operand[1].type != OPT_CONST)
7162 fprintf(fout, " & 0x1f");
7164 output_std_flags(fout, po, &pfomask, buf1);
7165 last_arith_dst = &po->operand[0];
7166 delayed_flag_op = NULL;
7170 assert_operand_cnt(2);
7171 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7172 fprintf(fout, " %s = %s%s >> %s;", buf1,
7173 lmod_cast_s(po, po->operand[0].lmod), buf1,
7174 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7175 output_std_flags(fout, po, &pfomask, buf1);
7176 last_arith_dst = &po->operand[0];
7177 delayed_flag_op = NULL;
7182 assert_operand_cnt(3);
7183 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7184 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7185 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
7186 if (po->operand[2].type != OPT_CONST) {
7187 // no handling for "undefined" case, hopefully not needed
7188 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
7191 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7192 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7193 if (po->op == OP_SHLD) {
7194 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
7195 buf1, buf3, buf1, buf2, l, buf3);
7196 strcpy(g_comment, "shld");
7199 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
7200 buf1, buf3, buf1, buf2, l, buf3);
7201 strcpy(g_comment, "shrd");
7203 output_std_flags(fout, po, &pfomask, buf1);
7204 last_arith_dst = &po->operand[0];
7205 delayed_flag_op = NULL;
7210 assert_operand_cnt(2);
7211 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7212 if (po->operand[1].type == OPT_CONST) {
7213 j = po->operand[1].val;
7214 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
7215 fprintf(fout, po->op == OP_ROL ?
7216 " %s = (%s << %d) | (%s >> %d);" :
7217 " %s = (%s >> %d) | (%s << %d);",
7218 buf1, buf1, j, buf1,
7219 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
7223 output_std_flags(fout, po, &pfomask, buf1);
7224 last_arith_dst = &po->operand[0];
7225 delayed_flag_op = NULL;
7230 assert_operand_cnt(2);
7231 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7232 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7233 if (po->operand[1].type == OPT_CONST) {
7234 j = po->operand[1].val % l;
7236 ferr(po, "zero rotate\n");
7237 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
7238 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
7239 if (po->op == OP_RCL) {
7241 " %s = (%s << %d) | (cond_c << %d)",
7242 buf1, buf1, j, j - 1);
7244 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
7248 " %s = (%s >> %d) | (cond_c << %d)",
7249 buf1, buf1, j, l - j);
7251 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
7253 fprintf(fout, ";\n");
7254 fprintf(fout, " cond_c = tmp;");
7258 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
7259 output_std_flags(fout, po, &pfomask, buf1);
7260 last_arith_dst = &po->operand[0];
7261 delayed_flag_op = NULL;
7265 assert_operand_cnt(2);
7266 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7267 if (IS(opr_name(po, 0), opr_name(po, 1))) {
7268 // special case for XOR
7269 int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
7270 for (j = 0; j <= PFO_LE; j++) {
7271 if (pfomask & (1 << j)) {
7272 fprintf(fout, " cond_%s = %d;\n",
7273 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
7274 pfomask &= ~(1 << j);
7277 fprintf(fout, " %s = 0;",
7278 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7279 last_arith_dst = &po->operand[0];
7280 delayed_flag_op = NULL;
7286 assert_operand_cnt(2);
7287 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7288 if (pfomask & (1 << PFO_C)) {
7289 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7290 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7291 if (po->operand[0].lmod == OPLM_DWORD) {
7292 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
7293 fprintf(fout, " cond_c = tmp64 >> 32;\n");
7294 fprintf(fout, " %s = (u32)tmp64;",
7295 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7296 strcat(g_comment, " add64");
7299 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
7300 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
7301 fprintf(fout, " %s += %s;",
7302 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7305 pfomask &= ~(1 << PFO_C);
7306 output_std_flags(fout, po, &pfomask, buf1);
7307 last_arith_dst = &po->operand[0];
7308 delayed_flag_op = NULL;
7311 if (pfomask & (1 << PFO_LE)) {
7312 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
7313 fprintf(fout, " cond_%s = %s;\n",
7314 parsed_flag_op_names[PFO_LE], buf1);
7315 pfomask &= ~(1 << PFO_LE);
7320 assert_operand_cnt(2);
7321 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7322 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
7323 for (j = 0; j <= PFO_LE; j++) {
7324 if (!(pfomask & (1 << j)))
7326 if (j == PFO_Z || j == PFO_S)
7329 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7330 fprintf(fout, " cond_%s = %s;\n",
7331 parsed_flag_op_names[j], buf1);
7332 pfomask &= ~(1 << j);
7339 assert_operand_cnt(2);
7340 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7341 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7342 if (po->op == OP_SBB
7343 && IS(po->operand[0].name, po->operand[1].name))
7345 // avoid use of unitialized var
7346 fprintf(fout, " %s = -cond_c;", buf1);
7347 // carry remains what it was
7348 pfomask &= ~(1 << PFO_C);
7351 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
7352 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7354 output_std_flags(fout, po, &pfomask, buf1);
7355 last_arith_dst = &po->operand[0];
7356 delayed_flag_op = NULL;
7361 // on SKL, if src is 0, dst is left unchanged
7362 assert_operand_cnt(2);
7363 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7364 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7365 output_std_flag_z(fout, po, &pfomask, buf2);
7366 if (po->op == OP_BSF)
7367 snprintf(buf3, sizeof(buf3), "__builtin_ffs(%s) - 1", buf2);
7369 snprintf(buf3, sizeof(buf3), "31 - __builtin_clz(%s)", buf2);
7370 fprintf(fout, " if (%s) %s = %s;", buf2, buf1, buf3);
7371 last_arith_dst = &po->operand[0];
7372 delayed_flag_op = NULL;
7373 strcat(g_comment, po->op == OP_BSF ? " bsf" : " bsr");
7377 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
7378 for (j = 0; j <= PFO_LE; j++) {
7379 if (!(pfomask & (1 << j)))
7381 if (j == PFO_Z || j == PFO_S || j == PFO_C)
7384 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7385 fprintf(fout, " cond_%s = %s;\n",
7386 parsed_flag_op_names[j], buf1);
7387 pfomask &= ~(1 << j);
7393 if (pfomask & (1 << PFO_C))
7394 // carry is unaffected by inc/dec.. wtf?
7395 ferr(po, "carry propagation needed\n");
7397 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7398 if (po->operand[0].type == OPT_REG) {
7399 ferr_assert(po, !(po->flags & OPF_LOCK));
7400 strcpy(buf2, po->op == OP_INC ? "++" : "--");
7401 fprintf(fout, " %s%s;", buf1, buf2);
7403 else if (po->flags & OPF_LOCK) {
7404 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0], "", 1);
7405 fprintf(fout, " __sync_fetch_and_%s((%s *)(%s), 1);",
7406 po->op == OP_INC ? "add" : "sub",
7407 lmod_type_u(po, po->operand[0].lmod), buf2);
7408 strcat(g_comment, " lock");
7412 strcpy(buf2, po->op == OP_INC ? "+" : "-");
7413 fprintf(fout, " %s %s= 1;", buf1, buf2);
7415 output_std_flags(fout, po, &pfomask, buf1);
7416 last_arith_dst = &po->operand[0];
7417 delayed_flag_op = NULL;
7421 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7422 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
7423 fprintf(fout, " %s = -%s%s;", buf1,
7424 lmod_cast_s(po, po->operand[0].lmod), buf2);
7425 last_arith_dst = &po->operand[0];
7426 delayed_flag_op = NULL;
7427 if (pfomask & PFOB_C) {
7428 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
7431 output_std_flags(fout, po, &pfomask, buf1);
7435 if (po->operand_cnt == 2) {
7436 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7439 if (po->operand_cnt == 3)
7440 ferr(po, "TODO imul3\n");
7443 assert_operand_cnt(1);
7444 switch (po->operand[0].lmod) {
7446 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
7447 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
7448 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
7449 fprintf(fout, " edx = tmp64 >> 32;\n");
7450 fprintf(fout, " eax = tmp64;");
7453 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
7454 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
7455 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
7459 ferr(po, "TODO: unhandled mul type\n");
7462 last_arith_dst = NULL;
7463 delayed_flag_op = NULL;
7468 assert_operand_cnt(1);
7469 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7470 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
7471 po->op == OP_IDIV));
7472 switch (po->operand[0].lmod) {
7474 if (po->flags & OPF_32BIT)
7475 snprintf(buf2, sizeof(buf2), "%seax", cast);
7477 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7478 snprintf(buf2, sizeof(buf2), "%stmp64",
7479 (po->op == OP_IDIV) ? "(s64)" : "");
7481 if (po->operand[0].type == OPT_REG
7482 && po->operand[0].reg == xDX)
7484 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
7485 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
7488 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
7489 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
7493 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
7494 snprintf(buf2, sizeof(buf2), "%stmp",
7495 (po->op == OP_IDIV) ? "(s32)" : "");
7496 if (po->operand[0].type == OPT_REG
7497 && po->operand[0].reg == xDX)
7499 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
7501 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
7505 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
7507 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
7510 strcat(g_comment, " div16");
7513 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
7515 last_arith_dst = NULL;
7516 delayed_flag_op = NULL;
7521 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7523 for (j = 0; j < 8; j++) {
7524 if (pfomask & (1 << j)) {
7525 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
7526 fprintf(fout, " cond_%s = %s;",
7527 parsed_flag_op_names[j], buf1);
7534 last_arith_dst = NULL;
7535 delayed_flag_op = po;
7539 // SETcc - should already be handled
7542 // note: we reuse OP_Jcc for SETcc, only flags differ
7544 fprintf(fout, "\n goto %s;", po->operand[0].name);
7548 fprintf(fout, " if (ecx == 0)\n");
7549 fprintf(fout, " goto %s;", po->operand[0].name);
7550 strcat(g_comment, " jecxz");
7554 fprintf(fout, " if (--ecx != 0)\n");
7555 fprintf(fout, " goto %s;", po->operand[0].name);
7556 strcat(g_comment, " loop");
7560 assert_operand_cnt(1);
7561 last_arith_dst = NULL;
7562 delayed_flag_op = NULL;
7564 if (po->operand[0].type == OPT_REGMEM) {
7565 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
7568 ferr(po, "parse failure for jmp '%s'\n",
7569 po->operand[0].name);
7570 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
7573 else if (po->operand[0].type != OPT_LABEL)
7574 ferr(po, "unhandled jmp type\n");
7576 fprintf(fout, " goto %s;", po->operand[0].name);
7580 assert_operand_cnt(1);
7582 my_assert_not(pp, NULL);
7585 if (po->flags & OPF_CC) {
7586 // we treat conditional branch to another func
7587 // (yes such code exists..) as conditional tailcall
7589 fprintf(fout, " {\n");
7592 if (pp->is_fptr && !pp->is_arg) {
7593 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
7594 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7597 if (pp->is_fptr && (pp->is_unresolved || pp->is_guessed)) {
7598 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
7599 buf3, asmfn, po->asmln, pp->name);
7602 fprintf(fout, "%s", buf3);
7603 if (strstr(pp->ret_type.name, "int64")) {
7604 if (po->flags & OPF_TAIL)
7605 ferr(po, "int64 and tail?\n");
7606 fprintf(fout, "tmp64 = ");
7608 else if (!IS(pp->ret_type.name, "void")) {
7609 if (po->flags & OPF_TAIL) {
7610 if (regmask_ret & mxAX) {
7611 fprintf(fout, "return ");
7612 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
7613 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
7615 else if (regmask_ret & mxST0)
7616 ferr(po, "float tailcall\n");
7618 else if (po->regmask_dst & mxAX) {
7619 fprintf(fout, "eax = ");
7620 if (pp->ret_type.is_ptr)
7621 fprintf(fout, "(u32)");
7623 else if (po->regmask_dst & mxST0) {
7624 ferr_assert(po, po->flags & OPF_FPUSH);
7625 if (need_float_stack)
7626 fprintf(fout, "f_st[--f_stp & 7] = ");
7628 fprintf(fout, "f_st0 = ");
7632 if (pp->name[0] == 0)
7633 ferr(po, "missing pp->name\n");
7634 fprintf(fout, "%s%s(", pp->name,
7635 pp->has_structarg ? "_sa" : "");
7637 if (po->flags & OPF_ATAIL) {
7639 g_func_pp->is_stdcall && g_func_pp->argc_stack > 0;
7640 check_compat |= pp->argc_stack > 0;
7642 && (pp->argc_stack != g_func_pp->argc_stack
7643 || pp->is_stdcall != g_func_pp->is_stdcall))
7644 ferr(po, "incompatible arg-reuse tailcall\n");
7645 if (g_func_pp->has_retreg)
7646 ferr(po, "TODO: retreg+tailcall\n");
7648 for (arg = j = 0; arg < pp->argc; arg++) {
7650 fprintf(fout, ", ");
7653 if (pp->arg[arg].type.is_ptr)
7654 snprintf(cast, sizeof(cast), "(%s)",
7655 pp->arg[arg].type.name);
7657 if (pp->arg[arg].reg != NULL) {
7658 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7662 for (; j < g_func_pp->argc; j++)
7663 if (g_func_pp->arg[j].reg == NULL)
7665 fprintf(fout, "%sa%d", cast, j + 1);
7670 for (arg = 0; arg < pp->argc; arg++) {
7672 fprintf(fout, ", ");
7675 if (pp->arg[arg].type.is_ptr)
7676 snprintf(cast, sizeof(cast), "(%s)",
7677 pp->arg[arg].type.name);
7679 if (pp->arg[arg].reg != NULL) {
7680 if (pp->arg[arg].type.is_retreg)
7681 fprintf(fout, "&%s", pp->arg[arg].reg);
7682 else if (IS(pp->arg[arg].reg, "ebp")
7683 && g_bp_frame && !(po->flags & OPF_EBP_S))
7685 // rare special case
7686 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
7687 strcat(g_comment, " bp_ref");
7690 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7695 tmp_op = pp->arg[arg].datap;
7697 ferr(po, "parsed_op missing for arg%d\n", arg);
7699 if (tmp_op->flags & OPF_VAPUSH) {
7700 fprintf(fout, "ap");
7702 else if (tmp_op->op == OP_FST) {
7703 fprintf(fout, "fs_%d", tmp_op->p_argnum);
7704 if (tmp_op->operand[0].lmod == OPLM_QWORD)
7707 else if (pp->arg[arg].type.is_64bit) {
7708 ferr_assert(po, tmp_op->p_argpass == 0);
7709 ferr_assert(po, !pp->arg[arg].is_saved);
7710 ferr_assert(po, !pp->arg[arg].type.is_float);
7711 ferr_assert(po, cast[0] == 0);
7712 out_src_opr(buf1, sizeof(buf1),
7713 tmp_op, &tmp_op->operand[0], cast, 0);
7714 tmp_op = pp->arg[++arg].datap;
7715 ferr_assert(po, tmp_op != NULL);
7716 out_src_opr(buf2, sizeof(buf2),
7717 tmp_op, &tmp_op->operand[0], cast, 0);
7718 fprintf(fout, "((u64)(%s) << 32) | (%s)",
7721 else if (tmp_op->p_argpass != 0) {
7722 ferr_assert(po, !pp->arg[arg].type.is_float);
7723 fprintf(fout, "a%d", tmp_op->p_argpass);
7725 else if (pp->arg[arg].is_saved) {
7726 ferr_assert(po, tmp_op->p_argnum > 0);
7727 ferr_assert(po, !pp->arg[arg].type.is_float);
7728 fprintf(fout, "%s%s", cast,
7729 saved_arg_name(buf1, sizeof(buf1),
7730 tmp_op->p_arggrp, tmp_op->p_argnum));
7732 else if (pp->arg[arg].type.is_float) {
7733 ferr_assert(po, !pp->arg[arg].type.is_64bit);
7735 out_src_opr_float(buf1, sizeof(buf1),
7736 tmp_op, &tmp_op->operand[0], need_float_stack));
7740 out_src_opr(buf1, sizeof(buf1),
7741 tmp_op, &tmp_op->operand[0], cast, 0));
7745 fprintf(fout, ");");
7747 if (strstr(pp->ret_type.name, "int64")) {
7748 fprintf(fout, "\n");
7749 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7750 fprintf(fout, "%seax = tmp64;", buf3);
7753 if (pp->is_unresolved) {
7754 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
7756 strcat(g_comment, buf2);
7759 if (po->flags & OPF_TAIL) {
7761 if (i == opcnt - 1 || pp->is_noreturn)
7763 else if (IS(pp->ret_type.name, "void"))
7765 else if (!(regmask_ret & (1 << xAX)))
7767 // else already handled as 'return f()'
7770 fprintf(fout, "\n%sreturn;", buf3);
7771 strcat(g_comment, " ^ tailcall");
7774 strcat(g_comment, " tailcall");
7776 if ((regmask_ret & (1 << xAX))
7777 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7779 ferr(po, "int func -> void func tailcall?\n");
7782 if (pp->is_noreturn)
7783 strcat(g_comment, " noreturn");
7784 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7785 strcat(g_comment, " argframe");
7786 if (po->flags & OPF_CC)
7787 strcat(g_comment, " cond");
7789 if (po->flags & OPF_CC)
7790 fprintf(fout, "\n }");
7792 delayed_flag_op = NULL;
7793 last_arith_dst = NULL;
7797 if (g_func_pp->is_vararg)
7798 fprintf(fout, " va_end(ap);\n");
7799 if (g_func_pp->has_retreg) {
7800 for (arg = 0; arg < g_func_pp->argc; arg++)
7801 if (g_func_pp->arg[arg].type.is_retreg)
7802 fprintf(fout, " *r_%s = %s;\n",
7803 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7806 if (regmask_ret & mxST0) {
7807 fprintf(fout, " return %s;", float_st0);
7809 else if (!(regmask_ret & mxAX)) {
7810 if (i != opcnt - 1 || label_pending)
7811 fprintf(fout, " return;");
7813 else if (g_func_pp->ret_type.is_ptr) {
7814 fprintf(fout, " return (%s)eax;",
7815 g_func_pp->ret_type.name);
7817 else if (IS(g_func_pp->ret_type.name, "__int64"))
7818 fprintf(fout, " return ((u64)edx << 32) | eax;");
7820 fprintf(fout, " return eax;");
7822 last_arith_dst = NULL;
7823 delayed_flag_op = NULL;
7827 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7828 if (po->p_argnum != 0) {
7829 // special case - saved func arg
7830 fprintf(fout, " %s = %s;",
7831 saved_arg_name(buf2, sizeof(buf2),
7832 po->p_arggrp, po->p_argnum), buf1);
7835 else if (po->flags & OPF_RSAVE) {
7836 fprintf(fout, " s_%s = %s;", buf1, buf1);
7839 else if (po->flags & OPF_PPUSH) {
7841 ferr_assert(po, tmp_op != NULL);
7842 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7843 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7846 else if (g_func_pp->is_userstack) {
7847 fprintf(fout, " *(--esp) = %s;", buf1);
7850 if (!(g_ida_func_attr & IDAFA_NORETURN))
7851 ferr(po, "stray push encountered\n");
7856 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7857 if (po->flags & OPF_RSAVE) {
7858 fprintf(fout, " %s = s_%s;", buf1, buf1);
7861 else if (po->flags & OPF_PPUSH) {
7862 // push/pop graph / non-const
7863 ferr_assert(po, po->datap == NULL);
7864 fprintf(fout, " %s = pp_%s;", buf1, buf1);
7867 else if (po->datap != NULL) {
7870 fprintf(fout, " %s = %s;", buf1,
7871 out_src_opr(buf2, sizeof(buf2),
7872 tmp_op, &tmp_op->operand[0],
7873 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7876 else if (g_func_pp->is_userstack) {
7877 fprintf(fout, " %s = *esp++;", buf1);
7881 ferr(po, "stray pop encountered\n");
7891 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7892 fprintf(fout, " tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
7893 po->op == OPP_ALLSHL ? "<<" : ">>");
7894 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
7895 strcat(g_comment, po->op == OPP_ALLSHL
7896 ? " allshl" : " allshr");
7901 if (need_float_stack) {
7902 out_src_opr_float(buf1, sizeof(buf1),
7903 po, &po->operand[0], 1);
7904 if (po->regmask_src & mxSTa) {
7905 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7909 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
7912 if (po->flags & OPF_FSHIFT)
7913 fprintf(fout, " f_st1 = f_st0;");
7914 if (po->operand[0].type == OPT_REG
7915 && po->operand[0].reg == xST0)
7917 strcat(g_comment, " fld st");
7920 fprintf(fout, " f_st0 = %s;",
7921 out_src_opr_float(buf1, sizeof(buf1),
7922 po, &po->operand[0], 0));
7924 strcat(g_comment, " fld");
7928 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7929 lmod_cast(po, po->operand[0].lmod, 1), 0);
7930 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7931 if (need_float_stack) {
7932 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
7935 if (po->flags & OPF_FSHIFT)
7936 fprintf(fout, " f_st1 = f_st0;");
7937 fprintf(fout, " f_st0 = %s;", buf2);
7939 strcat(g_comment, " fild");
7943 if (need_float_stack)
7944 fprintf(fout, " f_st[--f_stp & 7] = ");
7946 if (po->flags & OPF_FSHIFT)
7947 fprintf(fout, " f_st1 = f_st0;");
7948 fprintf(fout, " f_st0 = ");
7950 switch (po->operand[0].val) {
7951 case X87_CONST_1: fprintf(fout, "1.0;"); break;
7952 case X87_CONST_L2T: fprintf(fout, "3.321928094887362;"); break;
7953 case X87_CONST_L2E: fprintf(fout, "M_LOG2E;"); break;
7954 case X87_CONST_PI: fprintf(fout, "M_PI;"); break;
7955 case X87_CONST_LG2: fprintf(fout, "0.301029995663981;"); break;
7956 case X87_CONST_LN2: fprintf(fout, "M_LN2;"); break;
7957 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
7958 default: ferr_assert(po, 0); break;
7963 if (po->flags & OPF_FARG) {
7964 // store to stack as func arg
7965 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7969 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7971 dead_dst = po->operand[0].type == OPT_REG
7972 && po->operand[0].reg == xST0;
7975 fprintf(fout, " %s = %s;", buf1, float_st0);
7976 if (po->flags & OPF_FSHIFT) {
7977 if (need_float_stack)
7978 fprintf(fout, " f_stp++;");
7980 fprintf(fout, " f_st0 = f_st1;");
7982 if (dead_dst && !(po->flags & OPF_FSHIFT))
7985 strcat(g_comment, " fst");
7989 fprintf(fout, " %s = %s%s;",
7990 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7991 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7992 if (po->flags & OPF_FSHIFT) {
7993 if (need_float_stack)
7994 fprintf(fout, " f_stp++;");
7996 fprintf(fout, " f_st0 = f_st1;");
7998 strcat(g_comment, " fist");
8005 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8007 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
8009 dead_dst = (po->flags & OPF_FPOP)
8010 && po->operand[0].type == OPT_REG
8011 && po->operand[0].reg == xST0;
8013 case OP_FADD: j = '+'; break;
8014 case OP_FDIV: j = '/'; break;
8015 case OP_FMUL: j = '*'; break;
8016 case OP_FSUB: j = '-'; break;
8017 default: j = 'x'; break;
8019 if (need_float_stack) {
8021 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
8022 if (po->flags & OPF_FSHIFT)
8023 fprintf(fout, " f_stp++;");
8026 if (po->flags & OPF_FSHIFT) {
8027 // note: assumes only 2 regs handled
8029 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
8031 fprintf(fout, " f_st0 = f_st1;");
8034 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
8036 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
8041 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8043 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
8045 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
8047 dead_dst = (po->flags & OPF_FPOP)
8048 && po->operand[0].type == OPT_REG
8049 && po->operand[0].reg == xST0;
8050 j = po->op == OP_FDIVR ? '/' : '-';
8051 if (need_float_stack) {
8053 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
8054 if (po->flags & OPF_FSHIFT)
8055 fprintf(fout, " f_stp++;");
8058 if (po->flags & OPF_FSHIFT) {
8060 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
8062 fprintf(fout, " f_st0 = f_st1;");
8065 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
8067 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
8075 case OP_FIADD: j = '+'; break;
8076 case OP_FIDIV: j = '/'; break;
8077 case OP_FIMUL: j = '*'; break;
8078 case OP_FISUB: j = '-'; break;
8079 default: j = 'x'; break;
8081 fprintf(fout, " %s %c= (%s)%s;", float_st0,
8083 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
8084 lmod_cast(po, po->operand[0].lmod, 1), 0));
8089 fprintf(fout, " %s = %s %c %s;", float_st0,
8090 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
8092 po->op == OP_FIDIVR ? '/' : '-', float_st0);
8097 ferr_assert(po, po->datap != NULL);
8098 mask = (long)po->datap & 0xffff;
8099 z_check = ((long)po->datap >> 16) & 1;
8100 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8102 if (mask == 0x0100 || mask == 0x0500) { // C0 -> <
8103 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
8106 else if (mask == 0x4000 || mask == 0x4400) { // C3 -> =
8107 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
8110 else if (mask == 0x4100) { // C3, C0
8112 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
8114 strcat(g_comment, " z_chk_det");
8117 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
8118 "(%s < %s ? 0x0100 : 0);",
8119 float_st0, buf1, float_st0, buf1);
8123 ferr(po, "unhandled sw mask: %x\n", mask);
8124 if (po->flags & OPF_FSHIFT) {
8125 if (need_float_stack) {
8126 if (po->flags & OPF_FPOPP)
8127 fprintf(fout, " f_stp += 2;");
8129 fprintf(fout, " f_stp++;");
8132 ferr_assert(po, !(po->flags & OPF_FPOPP));
8133 fprintf(fout, " f_st0 = f_st1;");
8140 fprintf(fout, " %s = f_sw;",
8141 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
8145 fprintf(fout, " %s = -%s;", float_st0, float_st0);
8149 fprintf(fout, " %s = cos%s(%s);", float_st0,
8150 need_double ? "" : "f", float_st0);
8154 if (need_float_stack) {
8155 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
8156 need_double ? "" : "f", float_st1, float_st0);
8157 fprintf(fout, " f_stp++;");
8160 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
8161 need_double ? "" : "f");
8166 if (need_float_stack) {
8167 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
8168 float_st1, need_double ? "" : "f", float_st0);
8169 fprintf(fout, " f_stp++;");
8172 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
8173 need_double ? "" : "f");
8175 strcat(g_comment, " fyl2x");
8179 fprintf(fout, " %s = sin%s(%s);", float_st0,
8180 need_double ? "" : "f", float_st0);
8184 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
8185 need_double ? "" : "f", float_st0);
8189 dead_dst = po->operand[0].type == OPT_REG
8190 && po->operand[0].reg == xST0;
8192 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8194 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
8195 float_st0, float_st0, buf1, buf1);
8196 strcat(g_comment, " fxch");
8203 ferr_assert(po, po->flags & OPF_32BIT);
8204 fprintf(fout, " eax = (s32)%s;", float_st0);
8205 if (po->flags & OPF_FSHIFT) {
8206 if (need_float_stack)
8207 fprintf(fout, " f_stp++;");
8209 fprintf(fout, " f_st0 = f_st1;");
8211 strcat(g_comment, " ftol");
8215 if (need_float_stack) {
8216 fprintf(fout, " %s = pow%s(%s, %s);", float_st1,
8217 need_double ? "" : "f", float_st1, float_st0);
8218 fprintf(fout, " f_stp++;");
8221 fprintf(fout, " f_st0 = pow%s(f_st1, f_st0);",
8222 need_double ? "" : "f");
8224 strcat(g_comment, " CIpow");
8228 fprintf(fout, " do_skip_code_abort();");
8233 fprintf(fout, " do_emms();");
8238 ferr(po, "unhandled op type %d, flags %x\n",
8243 if (g_comment[0] != 0) {
8244 char *p = g_comment;
8245 while (my_isblank(*p))
8247 fprintf(fout, " // %s", p);
8252 fprintf(fout, "\n");
8254 // some sanity checking
8255 if (po->flags & OPF_REP) {
8256 if (po->op != OP_STOS && po->op != OP_MOVS
8257 && po->op != OP_CMPS && po->op != OP_SCAS)
8258 ferr(po, "unexpected rep\n");
8259 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
8260 && (po->op == OP_CMPS || po->op == OP_SCAS))
8261 ferr(po, "cmps/scas with plain rep\n");
8263 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
8264 && po->op != OP_CMPS && po->op != OP_SCAS)
8265 ferr(po, "unexpected repz/repnz\n");
8268 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
8270 if ((po->flags & OPF_LOCK) && !lock_handled)
8271 ferr(po, "unhandled lock\n");
8273 // see is delayed flag stuff is still valid
8274 if (delayed_flag_op != NULL && delayed_flag_op != po) {
8275 if (is_any_opr_modified(delayed_flag_op, po, 0))
8276 delayed_flag_op = NULL;
8279 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
8280 if (is_opr_modified(last_arith_dst, po))
8281 last_arith_dst = NULL;
8288 if (g_stack_fsz && !g_stack_frame_used)
8289 fprintf(fout, " (void)sf;\n");
8291 fprintf(fout, "}\n\n");
8293 gen_x_cleanup(opcnt);
8296 static void gen_x_cleanup(int opcnt)
8300 for (i = 0; i < opcnt; i++) {
8301 struct label_ref *lr, *lr_del;
8303 lr = g_label_refs[i].next;
8304 while (lr != NULL) {
8309 g_label_refs[i].i = -1;
8310 g_label_refs[i].next = NULL;
8312 if (ops[i].op == OP_CALL) {
8314 proto_release(ops[i].pp);
8320 struct func_proto_dep;
8322 struct func_prototype {
8326 int regmask_dep; // likely register args
8327 int regmask_use; // used registers
8328 int has_ret:3; // -1, 0, 1: unresolved, no, yes
8329 unsigned int has_ret64:1;
8330 unsigned int dep_resolved:1;
8331 unsigned int is_stdcall:1;
8332 unsigned int eax_pass:1; // returns without touching eax
8333 unsigned int ptr_taken:1; // pointer taken of this func
8334 struct func_proto_dep *dep_func;
8336 const struct parsed_proto *pp; // seed pp, if any
8339 struct func_proto_dep {
8341 struct func_prototype *proto;
8342 int regmask_live; // .. at the time of call
8343 unsigned int ret_dep:1; // return from this is caller's return
8344 unsigned int has_ret:1; // found from eax use after return
8345 unsigned int has_ret64:1;
8346 unsigned int ptr_taken:1; // pointer taken, not a call
8349 static struct func_prototype *hg_fp;
8350 static int hg_fp_cnt;
8352 static struct scanned_var {
8354 enum opr_lenmod lmod;
8355 unsigned int is_seeded:1;
8356 unsigned int is_c_str:1;
8357 const struct parsed_proto *pp; // seed pp, if any
8359 static int hg_var_cnt;
8361 static char **hg_refs;
8362 static int hg_ref_cnt;
8364 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8367 static struct func_prototype *hg_fp_add(const char *funcn)
8369 struct func_prototype *fp;
8371 if ((hg_fp_cnt & 0xff) == 0) {
8372 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
8373 my_assert_not(hg_fp, NULL);
8374 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
8377 fp = &hg_fp[hg_fp_cnt];
8378 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
8380 fp->argc_stack = -1;
8386 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
8391 for (i = 0; i < fp->dep_func_cnt; i++)
8392 if (IS(fp->dep_func[i].name, name))
8393 return &fp->dep_func[i];
8398 static void hg_fp_add_dep(struct func_prototype *fp, const char *name,
8399 unsigned int ptr_taken)
8401 struct func_proto_dep * dep;
8404 dep = hg_fp_find_dep(fp, name);
8405 if (dep != NULL && dep->ptr_taken == ptr_taken)
8408 if ((fp->dep_func_cnt & 0xff) == 0) {
8409 fp->dep_func = realloc(fp->dep_func,
8410 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
8411 my_assert_not(fp->dep_func, NULL);
8412 memset(&fp->dep_func[fp->dep_func_cnt], 0,
8413 sizeof(fp->dep_func[0]) * 0x100);
8415 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
8416 fp->dep_func[fp->dep_func_cnt].ptr_taken = ptr_taken;
8420 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
8422 const struct func_prototype *p1 = p1_, *p2 = p2_;
8423 return strcmp(p1->name, p2->name);
8427 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
8429 const struct func_prototype *p1 = p1_, *p2 = p2_;
8430 return p1->id - p2->id;
8434 static void hg_ref_add(const char *name)
8436 if ((hg_ref_cnt & 0xff) == 0) {
8437 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
8438 my_assert_not(hg_refs, NULL);
8439 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
8442 hg_refs[hg_ref_cnt] = strdup(name);
8443 my_assert_not(hg_refs[hg_ref_cnt], NULL);
8447 // recursive register dep pass
8448 // - track saved regs (part 2)
8449 // - try to figure out arg-regs
8450 // - calculate reg deps
8451 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
8452 struct func_prototype *fp, int regmask_save, int regmask_dst,
8453 int *regmask_dep, int *regmask_use, int *has_ret)
8455 struct func_proto_dep *dep;
8456 struct parsed_op *po;
8457 int from_caller = 0;
8462 for (; i < opcnt; i++)
8464 if (cbits[i >> 3] & (1 << (i & 7)))
8466 cbits[i >> 3] |= (1 << (i & 7));
8470 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
8471 if (po->flags & OPF_RMD)
8474 if (po->btj != NULL) {
8476 for (j = 0; j < po->btj->count; j++) {
8477 check_i(po, po->btj->d[j].bt_i);
8478 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
8479 regmask_save, regmask_dst, regmask_dep, regmask_use,
8485 check_i(po, po->bt_i);
8486 if (po->flags & OPF_CJMP) {
8487 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
8488 regmask_save, regmask_dst, regmask_dep, regmask_use,
8497 if (po->flags & OPF_FARG)
8498 /* (just calculate register deps) */;
8499 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
8501 reg = po->operand[0].reg;
8502 ferr_assert(po, reg >= 0);
8504 if (po->flags & OPF_RSAVE) {
8505 regmask_save |= 1 << reg;
8508 if (po->flags & OPF_DONE)
8511 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0, 0);
8513 regmask_save |= 1 << reg;
8514 po->flags |= OPF_RMD;
8515 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, OPF_RMD);
8519 else if (po->flags & OPF_RMD)
8521 else if (po->op == OP_CALL) {
8522 po->regmask_dst |= 1 << xAX;
8524 dep = hg_fp_find_dep(fp, po->operand[0].name);
8526 dep->regmask_live = regmask_save | regmask_dst;
8527 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8528 dep->regmask_live |= 1 << xBP;
8531 else if (po->op == OP_RET) {
8532 if (po->operand_cnt > 0) {
8534 if (fp->argc_stack >= 0
8535 && fp->argc_stack != po->operand[0].val / 4)
8536 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
8537 fp->argc_stack = po->operand[0].val / 4;
8541 if (!fp->eax_pass && (po->flags & OPF_TAIL)) {
8542 if (po->op == OP_CALL) {
8547 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
8550 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
8553 if (ret != 1 && from_caller) {
8554 // unresolved eax - probably void func
8559 if (j >= 0 && ops[j].op == OP_CALL) {
8560 if (ops[j].pp != NULL && !ops[j].pp->is_unresolved) {
8561 int call_has_ret = !IS(ops[j].pp->ret_type.name, "void");
8562 if (ops[j].pp->is_noreturn) {
8563 // could be some fail path
8565 *has_ret = call_has_ret;
8568 *has_ret = call_has_ret;
8571 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
8583 l = regmask_save | regmask_dst;
8584 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8587 l = po->regmask_src & ~l;
8590 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
8591 l, regmask_dst, regmask_save, po->flags);
8594 *regmask_use |= (po->regmask_src | po->regmask_dst)
8596 regmask_dst |= po->regmask_dst;
8598 if (po->flags & OPF_TAIL) {
8599 if (!(po->flags & OPF_CC)) // not cond. tailcall
8605 static void gen_hdr(const char *funcn, int opcnt)
8607 unsigned char cbits[MAX_OPS / 8];
8608 const struct parsed_proto *pp_c;
8609 struct parsed_proto *pp;
8610 struct func_prototype *fp;
8611 struct func_proto_dep *dep;
8612 struct parsed_op *po;
8613 const char *tmpname;
8614 int regmask_dummy = 0;
8617 int max_bp_offset = 0;
8622 pp_c = proto_parse(g_fhdr, funcn, 1);
8624 // already in seed, will add to hg_fp later
8627 fp = hg_fp_add(funcn);
8629 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
8630 g_stack_frame_used = 0;
8634 // - resolve all branches
8635 // - parse calls with labels
8636 resolve_branches_parse_calls(opcnt);
8639 // - handle ebp/esp frame, remove ops related to it
8640 scan_prologue_epilogue(opcnt, NULL);
8643 // - remove dead labels
8645 // - collect function ptr refs
8646 for (i = 0; i < opcnt; i++)
8648 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8654 if (po->flags & (OPF_RMD|OPF_DONE))
8657 if (po->op == OP_CALL) {
8658 if (po->operand[0].type == OPT_LABEL)
8659 hg_fp_add_dep(fp, opr_name(po, 0), 0);
8660 else if (po->pp != NULL)
8661 hg_fp_add_dep(fp, po->pp->name, 0);
8663 else if (po->op == OP_MOV && po->operand[1].type == OPT_OFFSET) {
8664 tmpname = opr_name(po, 1);
8665 if (IS_START(tmpname, "p_") || IS_START(tmpname, "sub_"))
8666 hg_fp_add_dep(fp, tmpname, 1);
8668 else if (po->op == OP_PUSH && po->operand[0].type == OPT_OFFSET) {
8669 tmpname = opr_name(po, 0);
8670 if (IS_START(tmpname, "p_") || IS_START(tmpname, "sub_"))
8671 hg_fp_add_dep(fp, tmpname, 1);
8676 // - handle push <const>/pop pairs
8677 for (i = 0; i < opcnt; i++)
8680 if (po->flags & (OPF_RMD|OPF_DONE))
8683 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
8684 scan_for_pop_const(i, opcnt, i + opcnt * 13);
8688 // - process trivial calls
8689 for (i = 0; i < opcnt; i++)
8692 if (po->flags & (OPF_RMD|OPF_DONE))
8695 if (po->op == OP_CALL)
8697 pp = process_call_early(i, opcnt, &j);
8699 if (!(po->flags & OPF_ATAIL))
8700 // since we know the args, try to collect them
8701 if (collect_call_args_early(i, pp, NULL, NULL) != 0)
8707 // commit esp adjust
8708 if (ops[j].op != OP_POP)
8709 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
8711 for (l = 0; l < pp->argc_stack; l++)
8712 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
8716 po->flags |= OPF_DONE;
8722 // - track saved regs (simple)
8724 for (i = 0; i < opcnt; i++)
8727 if (po->flags & (OPF_RMD|OPF_DONE))
8730 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
8731 && po->operand[0].reg != xCX)
8733 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
8735 // regmask_save |= 1 << po->operand[0].reg; // do it later
8736 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
8737 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
8740 else if (po->op == OP_CALL)
8742 pp = process_call(i, opcnt);
8744 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
8745 // since we know the args, collect them
8746 ret = collect_call_args(po, i, pp, ®mask_dummy,
8749 if (!(po->flags & OPF_TAIL)
8750 && po->operand[0].type == OPT_LABEL)
8752 dep = hg_fp_find_dep(fp, opr_name(po, 0));
8753 ferr_assert(po, dep != NULL);
8754 // treat al write as overwrite to avoid many false positives
8755 find_next_read_reg(i + 1, opcnt, xAX, OPLM_BYTE,
8756 i + opcnt * 25, &j);
8759 find_next_read_reg(i + 1, opcnt, xDX, OPLM_BYTE,
8760 i + opcnt * 26, &j);
8761 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j]))
8768 memset(cbits, 0, (opcnt + 7) / 8);
8769 regmask_dep = regmask_use = 0;
8772 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0,
8773 ®mask_dep, ®mask_use, &has_ret);
8775 // find unreachable code - must be fixed in IDA
8776 for (i = 0; i < opcnt; i++)
8778 if (cbits[i >> 3] & (1 << (i & 7)))
8781 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
8782 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
8784 // the compiler sometimes still generates code after
8785 // noreturn OS functions
8788 if (!(ops[i].flags & OPF_RMD)
8789 && ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
8791 ferr(&ops[i], "unreachable code\n");
8795 for (i = 0; i < g_eqcnt; i++) {
8796 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
8797 max_bp_offset = g_eqs[i].offset;
8800 if (fp->argc_stack < 0) {
8801 max_bp_offset = (max_bp_offset + 3) & ~3;
8802 fp->argc_stack = max_bp_offset / 4;
8803 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
8807 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
8808 fp->regmask_use = regmask_use;
8809 fp->has_ret = has_ret;
8811 printf("// has_ret %d, regmask_dep %x\n",
8812 fp->has_ret, fp->regmask_dep);
8813 output_hdr_fp(stdout, fp, 1);
8814 if (IS(funcn, "sub_10007F72")) exit(1);
8817 gen_x_cleanup(opcnt);
8820 static void hg_fp_resolve_deps(struct func_prototype *fp)
8822 struct func_prototype fp_s;
8823 struct func_proto_dep *dep;
8827 // this thing is recursive, so mark first..
8828 fp->dep_resolved = 1;
8830 for (i = 0; i < fp->dep_func_cnt; i++) {
8831 dep = &fp->dep_func[i];
8833 strcpy(fp_s.name, dep->name);
8834 dep->proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8835 sizeof(hg_fp[0]), hg_fp_cmp_name);
8836 if (dep->proto != NULL) {
8837 if (dep->ptr_taken) {
8838 dep->proto->ptr_taken = 1;
8842 if (!dep->proto->dep_resolved)
8843 hg_fp_resolve_deps(dep->proto);
8845 regmask_dep = ~dep->regmask_live
8846 & dep->proto->regmask_dep;
8847 fp->regmask_dep |= regmask_dep;
8848 // printf("dep %s %s |= %x\n", fp->name,
8849 // fp->dep_func[i].name, regmask_dep);
8851 if (dep->has_ret && (dep->proto->regmask_use & mxAX))
8852 dep->proto->has_ret = 1;
8853 if (dep->has_ret64 && (dep->proto->regmask_use & mxDX))
8854 dep->proto->has_ret64 = 1;
8855 if (fp->has_ret == -1 && dep->ret_dep)
8856 fp->has_ret = dep->proto->has_ret;
8861 // make all thiscall/edx arg functions referenced from .data fastcall
8862 static void do_func_refs_from_data(void)
8864 struct func_prototype *fp, fp_s;
8867 for (i = 0; i < hg_ref_cnt; i++) {
8868 strcpy(fp_s.name, hg_refs[i]);
8869 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8870 sizeof(hg_fp[0]), hg_fp_cmp_name);
8876 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8879 const struct parsed_proto *pp;
8880 char *p, namebuf[NAMELEN];
8886 for (; count > 0; count--, fp++) {
8887 if (fp->has_ret == -1)
8888 fprintf(fout, "// ret unresolved\n");
8890 fprintf(fout, "// dep:");
8891 for (j = 0; j < fp->dep_func_cnt; j++) {
8892 fprintf(fout, " %s/", fp->dep_func[j].name);
8893 if (fp->dep_func[j].proto != NULL)
8894 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8895 fp->dep_func[j].proto->has_ret);
8897 fprintf(fout, "\n");
8900 p = strchr(fp->name, '@');
8902 memcpy(namebuf, fp->name, p - fp->name);
8903 namebuf[p - fp->name] = 0;
8911 pp = proto_parse(g_fhdr, name, 1);
8912 if (pp != NULL && pp->is_include)
8915 if (fp->pp != NULL) {
8916 // part of seed, output later
8920 regmask_dep = fp->regmask_dep;
8921 argc_normal = fp->argc_stack;
8922 if (fp->ptr_taken && regmask_dep
8923 && (regmask_dep & ~(mxCX|mxDX)) == 0)
8925 if ((regmask_dep & mxDX) || fp->argc_stack > 0)
8926 regmask_dep |= mxCX | mxDX;
8929 fprintf(fout, "%-5s",
8930 fp->pp ? fp->pp->ret_type.name :
8931 fp->has_ret64 ? "__int64" :
8932 fp->has_ret ? "int" : "void");
8933 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
8934 && (regmask_dep & ~mxCX) == 0)
8936 fprintf(fout, "/*__thiscall*/ ");
8940 else if ((regmask_dep == (mxCX | mxDX)
8941 && (fp->is_stdcall || fp->argc_stack == 0))
8942 || (regmask_dep == mxCX && fp->argc_stack == 0))
8944 fprintf(fout, " __fastcall ");
8945 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8951 else if (regmask_dep && !fp->is_stdcall) {
8952 fprintf(fout, "/*__usercall*/ ");
8954 else if (regmask_dep) {
8955 fprintf(fout, "/*__userpurge*/ ");
8957 else if (fp->is_stdcall)
8958 fprintf(fout, " __stdcall ");
8960 fprintf(fout, " __cdecl ");
8962 fprintf(fout, "%s(", name);
8965 for (j = 0; j < xSP; j++) {
8966 if (regmask_dep & (1 << j)) {
8969 fprintf(fout, ", ");
8971 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8973 fprintf(fout, "int");
8974 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
8978 for (j = 0; j < argc_normal; j++) {
8981 fprintf(fout, ", ");
8982 if (fp->pp != NULL) {
8983 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8984 if (!fp->pp->arg[arg - 1].type.is_ptr)
8988 fprintf(fout, "int ");
8989 fprintf(fout, "a%d", arg);
8992 fprintf(fout, ");\n");
8996 static void output_hdr(FILE *fout)
8998 static const char *lmod_c_names[] = {
8999 [OPLM_UNSPEC] = "???",
9000 [OPLM_BYTE] = "uint8_t",
9001 [OPLM_WORD] = "uint16_t",
9002 [OPLM_DWORD] = "uint32_t",
9003 [OPLM_QWORD] = "uint64_t",
9005 const struct scanned_var *var;
9006 struct func_prototype *fp;
9007 char line[256] = { 0, };
9011 // add stuff from headers
9012 for (i = 0; i < pp_cache_size; i++) {
9013 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
9014 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
9016 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
9017 fp = hg_fp_add(name);
9018 fp->pp = &pp_cache[i];
9019 fp->argc_stack = fp->pp->argc_stack;
9020 fp->is_stdcall = fp->pp->is_stdcall;
9021 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
9022 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
9026 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
9027 for (i = 0; i < hg_fp_cnt; i++)
9028 hg_fp_resolve_deps(&hg_fp[i]);
9030 // adjust functions referenced from data segment
9031 do_func_refs_from_data();
9033 // final adjustments
9034 for (i = 0; i < hg_fp_cnt; i++) {
9035 if (hg_fp[i].eax_pass && (hg_fp[i].regmask_dep & mxAX))
9036 hg_fp[i].has_ret = 1;
9039 // note: messes up .proto ptr, don't use
9040 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
9043 for (i = 0; i < hg_var_cnt; i++) {
9046 if (var->pp != NULL)
9049 else if (var->is_c_str)
9050 fprintf(fout, "extern %-8s %s[];", "char", var->name);
9052 fprintf(fout, "extern %-8s %s;",
9053 lmod_c_names[var->lmod], var->name);
9056 fprintf(fout, " // seeded");
9057 fprintf(fout, "\n");
9060 fprintf(fout, "\n");
9062 // output function prototypes
9063 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
9066 fprintf(fout, "\n// - seed -\n");
9069 while (fgets(line, sizeof(line), g_fhdr))
9070 fwrite(line, 1, strlen(line), fout);
9073 // '=' needs special treatment
9075 static char *next_word_s(char *w, size_t wsize, char *s)
9082 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
9084 for (i = 1; i < wsize - 1; i++) {
9086 printf("warning: missing closing quote: \"%s\"\n", s);
9095 for (; i < wsize - 1; i++) {
9096 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
9102 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
9103 printf("warning: '%s' truncated\n", w);
9108 static int cmpstringp(const void *p1, const void *p2)
9110 return strcmp(*(char * const *)p1, *(char * const *)p2);
9113 static int is_xref_needed(char *p, char **rlist, int rlist_len)
9118 if (strstr(p, "..."))
9119 // unable to determine, assume needed
9122 if (*p == '.') // .text, .data, ...
9123 // ref from other data or non-function -> no
9126 p2 = strpbrk(p, "+:\r\n\x18");
9129 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9130 // referenced from removed code
9136 static int ida_xrefs_show_need(FILE *fasm, char *p,
9137 char **rlist, int rlist_len)
9143 p = strrchr(p, ';');
9144 if (p != NULL && *p == ';') {
9145 if (IS_START(p + 2, "sctref"))
9147 if (IS_START(p + 2, "DATA XREF: ")) {
9149 if (is_xref_needed(p, rlist, rlist_len))
9157 if (!my_fgets(line, sizeof(line), fasm))
9159 // non-first line is always indented
9160 if (!my_isblank(line[0]))
9163 // should be no content, just comment
9168 p = strrchr(p, ';');
9171 if (IS_START(p, "sctref")) {
9176 // it's printed once, but no harm to check again
9177 if (IS_START(p, "DATA XREF: "))
9180 if (is_xref_needed(p, rlist, rlist_len)) {
9185 fseek(fasm, pos, SEEK_SET);
9189 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
9191 struct scanned_var *var;
9192 char line[256] = { 0, };
9201 // skip to next data section
9202 while (my_fgets(line, sizeof(line), fasm))
9207 if (*p == 0 || *p == ';')
9210 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
9211 if (*p == 0 || *p == ';')
9214 if (*p != 's' || !IS_START(p, "segment para public"))
9220 if (p == NULL || !IS_START(p, "segment para public"))
9224 if (!IS_START(p, "'DATA'"))
9228 while (my_fgets(line, sizeof(line), fasm))
9233 no_identifier = my_isblank(*p);
9236 if (*p == 0 || *p == ';')
9239 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9240 words[wordc][0] = 0;
9241 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9242 if (*p == 0 || *p == ';') {
9248 if (wordc == 2 && IS(words[1], "ends"))
9253 if (no_identifier) {
9254 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
9255 hg_ref_add(words[2]);
9259 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
9260 // when this starts, we don't need anything from this section
9264 // check refs comment(s)
9265 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
9268 if ((hg_var_cnt & 0xff) == 0) {
9269 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
9270 * (hg_var_cnt + 0x100));
9271 my_assert_not(hg_vars, NULL);
9272 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
9275 var = &hg_vars[hg_var_cnt++];
9276 snprintf(var->name, sizeof(var->name), "%s", words[0]);
9278 // maybe already in seed header?
9279 var->pp = proto_parse(g_fhdr, var->name, 1);
9280 if (var->pp != NULL) {
9281 if (var->pp->is_fptr) {
9282 var->lmod = OPLM_DWORD;
9285 else if (var->pp->is_func)
9287 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
9288 aerr("unhandled C type '%s' for '%s'\n",
9289 var->pp->type.name, var->name);
9295 if (IS(words[1], "dd")) {
9296 var->lmod = OPLM_DWORD;
9297 if (wordc >= 4 && IS(words[2], "offset"))
9298 hg_ref_add(words[3]);
9300 else if (IS(words[1], "dw"))
9301 var->lmod = OPLM_WORD;
9302 else if (IS(words[1], "db")) {
9303 var->lmod = OPLM_BYTE;
9304 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
9305 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
9309 else if (IS(words[1], "dq"))
9310 var->lmod = OPLM_QWORD;
9311 //else if (IS(words[1], "dt"))
9313 aerr("type '%s' not known\n", words[1]);
9321 static void set_label(int i, const char *name)
9327 p = strchr(name, ':');
9331 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
9332 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
9333 g_labels[i] = realloc(g_labels[i], len + 1);
9334 my_assert_not(g_labels[i], NULL);
9335 memcpy(g_labels[i], name, len);
9336 g_labels[i][len] = 0;
9345 static struct chunk_item *func_chunks;
9346 static int func_chunk_cnt;
9347 static int func_chunk_alloc;
9349 static void add_func_chunk(FILE *fasm, const char *name, int line)
9351 if (func_chunk_cnt >= func_chunk_alloc) {
9352 func_chunk_alloc *= 2;
9353 func_chunks = realloc(func_chunks,
9354 func_chunk_alloc * sizeof(func_chunks[0]));
9355 my_assert_not(func_chunks, NULL);
9357 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
9358 func_chunks[func_chunk_cnt].name = strdup(name);
9359 func_chunks[func_chunk_cnt].asmln = line;
9363 static int cmp_chunks(const void *p1, const void *p2)
9365 const struct chunk_item *c1 = p1, *c2 = p2;
9366 return strcmp(c1->name, c2->name);
9369 static void scan_ahead_for_chunks(FILE *fasm)
9379 oldpos = ftell(fasm);
9382 while (my_fgets(line, sizeof(line), fasm))
9393 // get rid of random tabs
9394 for (i = 0; line[i] != 0; i++)
9395 if (line[i] == '\t')
9398 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9401 next_word(words[0], sizeof(words[0]), p);
9402 if (words[0][0] == 0)
9403 aerr("missing name for func chunk?\n");
9405 add_func_chunk(fasm, words[0], asmln);
9407 else if (IS_START(p, "; sctend"))
9413 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9414 words[wordc][0] = 0;
9415 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9416 if (*p == 0 || *p == ';') {
9422 if (wordc == 2 && IS(words[1], "ends"))
9426 fseek(fasm, oldpos, SEEK_SET);
9430 int main(int argc, char *argv[])
9432 FILE *fout, *fasm, *frlist;
9433 struct parsed_data *pd = NULL;
9435 char **rlist = NULL;
9437 int rlist_alloc = 0;
9438 int func_chunks_used = 0;
9439 int func_chunks_sorted = 0;
9440 int func_chunk_i = -1;
9441 long func_chunk_ret = 0;
9442 int func_chunk_ret_ln = 0;
9443 int scanned_ahead = 0;
9445 char words[20][256];
9446 enum opr_lenmod lmod;
9447 char *sctproto = NULL;
9449 int pending_endp = 0;
9451 int skip_code_end = 0;
9452 int skip_warned = 0;
9465 for (arg = 1; arg < argc; arg++) {
9466 if (IS(argv[arg], "-v"))
9468 else if (IS(argv[arg], "-rf"))
9469 g_allow_regfunc = 1;
9470 else if (IS(argv[arg], "-uc"))
9471 g_allow_user_icall = 1;
9472 else if (IS(argv[arg], "-wu"))
9473 g_nowarn_reguse = 1;
9474 else if (IS(argv[arg], "-m"))
9476 else if (IS(argv[arg], "-hdr"))
9477 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
9482 if (argc < arg + 3) {
9483 printf("usage:\n%s [options] <.c> <.asm> <hdr.h> [rlist]*\n"
9484 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
9486 " -hdr - header generation mode\n"
9487 " -rf - allow unannotated indirect calls\n"
9488 " -uc - allow ind. calls/refs to __usercall\n"
9489 " -m - allow multiple .text sections\n"
9490 " -wu - don't warn about bad reg use\n"
9491 "[rlist] is a file with function names to skip,"
9499 asmfn = argv[arg++];
9500 fasm = fopen(asmfn, "r");
9501 my_assert_not(fasm, NULL);
9503 hdrfn = argv[arg++];
9504 g_fhdr = fopen(hdrfn, "r");
9505 my_assert_not(g_fhdr, NULL);
9508 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
9509 my_assert_not(rlist, NULL);
9510 // needs special handling..
9511 rlist[rlist_len++] = "__alloca_probe";
9513 func_chunk_alloc = 32;
9514 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
9515 my_assert_not(func_chunks, NULL);
9517 memset(words, 0, sizeof(words));
9519 for (; arg < argc; arg++) {
9522 frlist = fopen(argv[arg], "r");
9523 my_assert_not(frlist, NULL);
9525 while (my_fgets(line, sizeof(line), frlist)) {
9527 if (*p == 0 || *p == ';')
9530 if (IS_START(p, "#if 0")
9531 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
9535 else if (IS_START(p, "#endif"))
9542 p = next_word(words[0], sizeof(words[0]), p);
9543 if (words[0][0] == 0)
9546 if (rlist_len >= rlist_alloc) {
9547 rlist_alloc = rlist_alloc * 2 + 64;
9548 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
9549 my_assert_not(rlist, NULL);
9551 rlist[rlist_len++] = strdup(words[0]);
9559 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
9561 fout = fopen(argv[arg_out], "w");
9562 my_assert_not(fout, NULL);
9565 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
9566 my_assert_not(g_eqs, NULL);
9568 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
9569 g_label_refs[i].i = -1;
9570 g_label_refs[i].next = NULL;
9574 scan_variables(fasm, rlist, rlist_len);
9576 while (my_fgets(line, sizeof(line), fasm))
9585 // get rid of random tabs
9586 for (i = 0; line[i] != 0; i++)
9587 if (line[i] == '\t')
9592 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
9593 goto do_pending_endp; // eww..
9595 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
9597 static const char *attrs[] = {
9606 // parse IDA's attribute-list comment
9607 g_ida_func_attr = 0;
9610 for (; *p != 0; p = sskip(p)) {
9611 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9612 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9613 g_ida_func_attr |= 1 << i;
9614 p += strlen(attrs[i]);
9618 if (i == ARRAY_SIZE(attrs)) {
9619 anote("unparsed IDA attr: %s\n", p);
9622 if (IS(attrs[i], "fpd=")) {
9623 p = next_word(words[0], sizeof(words[0]), p);
9628 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
9630 static const char *attrs[] = {
9638 // parse manual attribute-list comment
9639 g_sct_func_attr = 0;
9642 for (; *p != 0; p = sskip(p)) {
9643 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9644 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9645 g_sct_func_attr |= 1 << i;
9646 p += strlen(attrs[i]);
9653 // clear_sf=start,len (in dwords)
9654 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
9655 &g_stack_clear_len, &j);
9657 // clear_regmask=<mask>
9658 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
9660 // rm_regmask=<mask>
9661 ret = sscanf(p, "=%x%n", &g_regmask_rm, &j) + 1;
9663 anote("unparsed attr value: %s\n", p);
9668 else if (i == ARRAY_SIZE(attrs)) {
9669 anote("unparsed sct attr: %s\n", p);
9674 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9677 next_word(words[0], sizeof(words[0]), p);
9678 if (words[0][0] == 0)
9679 aerr("missing name for func chunk?\n");
9681 if (!scanned_ahead) {
9682 add_func_chunk(fasm, words[0], asmln);
9683 func_chunks_sorted = 0;
9686 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
9688 if (func_chunk_i >= 0) {
9689 if (func_chunk_i < func_chunk_cnt
9690 && IS(func_chunks[func_chunk_i].name, g_func))
9692 // move on to next chunk
9693 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9695 aerr("seek failed for '%s' chunk #%d\n",
9696 g_func, func_chunk_i);
9697 asmln = func_chunks[func_chunk_i].asmln;
9701 if (func_chunk_ret == 0)
9702 aerr("no return from chunk?\n");
9703 fseek(fasm, func_chunk_ret, SEEK_SET);
9704 asmln = func_chunk_ret_ln;
9710 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
9711 func_chunks_used = 1;
9713 if (IS_START(g_func, "sub_")) {
9714 unsigned long addr = strtoul(p, NULL, 16);
9715 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
9716 if (addr > f_addr && !scanned_ahead) {
9717 //anote("scan_ahead caused by '%s', addr %lx\n",
9719 scan_ahead_for_chunks(fasm);
9721 func_chunks_sorted = 0;
9729 for (i = wordc; i < ARRAY_SIZE(words); i++)
9731 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9732 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9733 if (*p == 0 || *p == ';') {
9738 if (*p != 0 && *p != ';')
9739 aerr("too many words\n");
9741 if (skip_code_end) {
9746 // allow asm patches in comments
9748 // skip IDA's forced non-removable comment
9749 if (!IS_START(p, "; sct") && (p2 = strchr(p + 1, ';')))
9752 if (*p == ';' && IS_START(p, "; sct")) {
9753 if (IS_START(p, "; sctpatch:")) {
9755 if (*p == 0 || *p == ';')
9757 goto parse_words; // lame
9759 else if (IS_START(p, "; sctend")) {
9764 else if (g_skip_func)
9765 /* ignore remaining attrs */;
9766 else if (IS_START(p, "; sctproto:")) {
9767 sctproto = strdup(p + 11);
9769 else if (IS_START(p, "; sctskip_start")) {
9772 ops[pi].op = OPP_ABORT;
9773 ops[pi].asmln = asmln;
9779 else if (IS_START(p, "; sctskip_end")) {
9787 awarn("wordc == 0?\n");
9791 // don't care about this:
9792 if (words[0][0] == '.'
9793 || IS(words[0], "include")
9794 || IS(words[0], "assume") || IS(words[1], "segment")
9795 || IS(words[0], "align"))
9801 // do delayed endp processing to collect switch jumptables
9803 if (in_func && !g_skip_func && !end && wordc >= 2
9804 && ((words[0][0] == 'd' && words[0][2] == 0)
9805 || (words[1][0] == 'd' && words[1][2] == 0)))
9808 if (words[1][0] == 'd' && words[1][2] == 0) {
9810 if (g_func_pd_cnt >= pd_alloc) {
9811 pd_alloc = pd_alloc * 2 + 16;
9812 g_func_pd = realloc(g_func_pd,
9813 sizeof(g_func_pd[0]) * pd_alloc);
9814 my_assert_not(g_func_pd, NULL);
9816 pd = &g_func_pd[g_func_pd_cnt];
9818 memset(pd, 0, sizeof(*pd));
9819 strcpy(pd->label, words[0]);
9820 pd->type = OPT_CONST;
9821 pd->lmod = lmod_from_directive(words[1]);
9827 anote("skipping alignment byte?\n");
9830 lmod = lmod_from_directive(words[0]);
9831 if (lmod != pd->lmod)
9832 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
9835 if (pd->count_alloc < pd->count + wordc) {
9836 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
9837 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
9838 my_assert_not(pd->d, NULL);
9840 for (; i < wordc; i++) {
9841 if (IS(words[i], "offset")) {
9842 pd->type = OPT_OFFSET;
9845 p = strchr(words[i], ',');
9848 if (pd->type == OPT_OFFSET)
9849 pd->d[pd->count].u.label = strdup(words[i]);
9851 pd->d[pd->count].u.val = parse_number(words[i], 0);
9852 pd->d[pd->count].bt_i = -1;
9858 if (in_func && !g_skip_func) {
9860 gen_hdr(g_func, pi);
9862 gen_func(fout, g_fhdr, g_func, pi);
9867 g_ida_func_attr = 0;
9868 g_sct_func_attr = 0;
9869 g_stack_clear_start = 0;
9870 g_stack_clear_len = 0;
9877 func_chunks_used = 0;
9880 memset(&ops, 0, pi * sizeof(ops[0]));
9885 for (i = 0; i < g_func_pd_cnt; i++) {
9887 if (pd->type == OPT_OFFSET) {
9888 for (j = 0; j < pd->count; j++)
9889 free(pd->d[j].u.label);
9904 if (IS(words[1], "proc")) {
9906 aerr("proc '%s' while in_func '%s'?\n",
9909 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9911 strcpy(g_func, words[0]);
9912 set_label(0, words[0]);
9917 if (IS(words[1], "endp"))
9920 aerr("endp '%s' while not in_func?\n", words[0]);
9921 if (!IS(g_func, words[0]))
9922 aerr("endp '%s' while in_func '%s'?\n",
9925 aerr("endp '%s' while skipping code\n", words[0]);
9927 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
9928 && ops[0].op == OP_JMP && ops[0].operand[0].segment)
9934 if (!g_skip_func && func_chunks_used) {
9935 // start processing chunks
9936 struct chunk_item *ci, key = { g_func, 0 };
9938 func_chunk_ret = ftell(fasm);
9939 func_chunk_ret_ln = asmln;
9940 if (!func_chunks_sorted) {
9941 qsort(func_chunks, func_chunk_cnt,
9942 sizeof(func_chunks[0]), cmp_chunks);
9943 func_chunks_sorted = 1;
9945 ci = bsearch(&key, func_chunks, func_chunk_cnt,
9946 sizeof(func_chunks[0]), cmp_chunks);
9948 aerr("'%s' needs chunks, but none found\n", g_func);
9949 func_chunk_i = ci - func_chunks;
9950 for (; func_chunk_i > 0; func_chunk_i--)
9951 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
9954 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9956 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
9957 asmln = func_chunks[func_chunk_i].asmln;
9965 if (wordc == 2 && IS(words[1], "ends")) {
9969 goto do_pending_endp;
9973 // scan for next text segment
9974 while (my_fgets(line, sizeof(line), fasm)) {
9977 if (*p == 0 || *p == ';')
9980 if (strstr(p, "segment para public 'CODE' use32"))
9987 p = strchr(words[0], ':');
9989 set_label(pi, words[0]);
9993 if (!in_func || g_skip_func || skip_code) {
9994 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
9996 anote("skipping from '%s'\n", g_labels[pi]);
10000 g_labels[pi] = NULL;
10004 if (wordc > 1 && IS(words[1], "="))
10007 aerr("unhandled equ, wc=%d\n", wordc);
10008 if (g_eqcnt >= eq_alloc) {
10010 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
10011 my_assert_not(g_eqs, NULL);
10014 len = strlen(words[0]);
10015 if (len > sizeof(g_eqs[0].name) - 1)
10016 aerr("equ name too long: %d\n", len);
10017 strcpy(g_eqs[g_eqcnt].name, words[0]);
10019 if (!IS(words[3], "ptr"))
10020 aerr("unhandled equ\n");
10021 if (IS(words[2], "dword"))
10022 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
10023 else if (IS(words[2], "word"))
10024 g_eqs[g_eqcnt].lmod = OPLM_WORD;
10025 else if (IS(words[2], "byte"))
10026 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
10027 else if (IS(words[2], "qword"))
10028 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
10030 aerr("bad lmod: '%s'\n", words[2]);
10032 g_eqs[g_eqcnt].offset = parse_number(words[4], 0);
10037 if (pi >= ARRAY_SIZE(ops))
10038 aerr("too many ops\n");
10040 parse_op(&ops[pi], words, wordc);
10042 ops[pi].datap = sctproto;
10057 // vim:ts=2:shiftwidth=2:expandtab