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_quiet_pp;
342 static int g_header_mode;
344 #define ferr(op_, fmt, ...) do { \
345 printf("%s:%d: error %u: [%s] '%s': " fmt, asmfn, (op_)->asmln, \
346 __LINE__, g_func, dump_op(op_), ##__VA_ARGS__); \
350 #define fnote(op_, fmt, ...) \
351 printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
352 dump_op(op_), ##__VA_ARGS__)
354 #define ferr_assert(op_, cond) do { \
355 if (!(cond)) ferr(op_, "assertion '%s' failed\n", #cond); \
358 #define IS_OP_INDIRECT_CALL(op_) \
359 ((op_)->op == OP_CALL && (op_)->operand[0].type != OPT_LABEL)
361 const char *regs_r32[] = {
362 "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
363 // not r32, but list here for easy parsing and printing
364 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
365 "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"
367 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
368 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
369 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
375 xMM0, xMM1, xMM2, xMM3, // mmx
376 xMM4, xMM5, xMM6, xMM7,
377 xST0, xST1, xST2, xST3, // x87
378 xST4, xST5, xST6, xST7,
381 #define mxAX (1 << xAX)
382 #define mxBX (1 << xBX)
383 #define mxCX (1 << xCX)
384 #define mxDX (1 << xDX)
385 #define mxSP (1 << xSP)
386 #define mxST0 (1 << xST0)
387 #define mxST1 (1 << xST1)
388 #define mxST1_0 (mxST1 | mxST0)
389 #define mxST7_2 (0xfc << xST0)
390 #define mxSTa (0xff << xST0)
392 // possible basic comparison types (without inversion)
393 enum parsed_flag_op {
397 PFO_BE, // 6 CF=1||ZF=1
401 PFO_LE, // e ZF=1||SF!=OF
404 #define PFOB_O (1 << PFO_O)
405 #define PFOB_C (1 << PFO_C)
406 #define PFOB_Z (1 << PFO_Z)
407 #define PFOB_S (1 << PFO_S)
409 static const char *parsed_flag_op_names[] = {
410 "o", "c", "z", "be", "s", "p", "l", "le"
413 static int char_array_i(const char *array[], size_t len, const char *s)
417 for (i = 0; i < len; i++)
424 static void printf_number(char *buf, size_t buf_size,
425 unsigned long number)
427 // output in C-friendly form
428 snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
431 static int check_segment_prefix(const char *s)
433 if (s[0] == 0 || s[1] != 's' || s[2] != ':')
437 case 'c': return SEG_CS;
438 case 'd': return SEG_DS;
439 case 's': return SEG_SS;
440 case 'e': return SEG_ES;
441 case 'f': return SEG_FS;
442 case 'g': return SEG_GS;
447 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
451 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
453 *reg_lmod = OPLM_QWORD;
457 *reg_lmod = OPLM_DWORD;
460 reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
462 *reg_lmod = OPLM_WORD;
465 reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
467 *reg_lmod = OPLM_BYTE;
470 reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
472 *reg_lmod = OPLM_BYTE;
479 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
481 enum opr_lenmod lmod;
494 while (my_isblank(*s))
496 for (; my_issep(*s); d++, s++)
498 while (my_isblank(*s))
502 // skip '?s:' prefixes
503 if (check_segment_prefix(s))
506 s = next_idt(w, sizeof(w), s);
511 reg = parse_reg(&lmod, w);
513 *regmask |= 1 << reg;
517 if ('0' <= w[0] && w[0] <= '9') {
518 number = parse_number(w, 0);
519 printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
523 // probably some label/identifier - pass
526 snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
530 strcpy(name, cvtbuf);
535 static int is_reg_in_str(const char *s)
539 if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
542 for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
543 if (!strncmp(s, regs_r32[i], 3))
549 static const char *parse_stack_el(const char *name, char *extra_reg,
550 int *base_val, int early_try)
552 const char *p, *p2, *s;
558 if (g_bp_frame || early_try)
561 if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
563 if (extra_reg != NULL) {
564 strncpy(extra_reg, name, 3);
569 if (IS_START(p, "ebp+")) {
573 if (p2 != NULL && is_reg_in_str(p)) {
574 if (extra_reg != NULL) {
575 strncpy(extra_reg, p, p2 - p);
576 extra_reg[p2 - p] = 0;
581 if (!('0' <= *p && *p <= '9'))
588 if (!IS_START(name, "esp+"))
594 if (is_reg_in_str(s)) {
595 if (extra_reg != NULL) {
596 strncpy(extra_reg, s, p - s);
597 extra_reg[p - s] = 0;
602 aerr("%s IDA stackvar not set?\n", __func__);
604 if ('0' <= *s && *s <= '9') {
605 if (s[0] == '0' && s[1] == 'x')
608 if (len < sizeof(buf) - 1) {
609 strncpy(buf, s, len);
612 val = strtol(buf, &endp, 16);
613 if (val == 0 || *endp != 0 || errno != 0) {
614 aerr("%s num parse fail for '%s'\n", __func__, buf);
621 // probably something like [esp+arg_4+2]
629 if ('0' <= *p && *p <= '9')
632 if (base_val != NULL)
637 static int guess_lmod_from_name(struct parsed_opr *opr)
639 if (IS_START(opr->name, "dword_") || IS_START(opr->name, "off_")) {
640 opr->lmod = OPLM_DWORD;
643 if (IS_START(opr->name, "word_")) {
644 opr->lmod = OPLM_WORD;
647 if (IS_START(opr->name, "byte_")) {
648 opr->lmod = OPLM_BYTE;
651 if (IS_START(opr->name, "qword_")) {
652 opr->lmod = OPLM_QWORD;
658 static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
659 const struct parsed_type *c_type)
661 static const char *qword_types[] = {
662 "uint64_t", "int64_t", "__int64",
664 static const char *dword_types[] = {
665 "uint32_t", "int", "_DWORD", "UINT_PTR", "DWORD",
666 "WPARAM", "LPARAM", "UINT", "__int32",
667 "LONG", "HIMC", "BOOL", "size_t",
670 static const char *word_types[] = {
671 "uint16_t", "int16_t", "_WORD", "WORD",
672 "unsigned __int16", "__int16",
674 static const char *byte_types[] = {
675 "uint8_t", "int8_t", "char",
676 "unsigned __int8", "__int8", "BYTE", "_BYTE",
678 // structures.. deal the same as with _UNKNOWN for now
684 if (c_type->is_ptr) {
689 n = skip_type_mod(c_type->name);
691 for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
692 if (IS(n, dword_types[i])) {
698 for (i = 0; i < ARRAY_SIZE(word_types); i++) {
699 if (IS(n, word_types[i])) {
705 for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
706 if (IS(n, byte_types[i])) {
712 for (i = 0; i < ARRAY_SIZE(qword_types); i++) {
713 if (IS(n, qword_types[i])) {
722 static char *default_cast_to(char *buf, size_t buf_size,
723 struct parsed_opr *opr)
727 if (!opr->is_ptr || strchr(opr->name, '['))
729 if (opr->pp == NULL || opr->pp->type.name == NULL
732 snprintf(buf, buf_size, "%s", "(void *)");
736 snprintf(buf, buf_size, "(%s)", opr->pp->type.name);
740 static enum opr_type lmod_from_directive(const char *d)
744 else if (IS(d, "dw"))
746 else if (IS(d, "db"))
749 aerr("unhandled directive: '%s'\n", d);
753 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
759 *regmask |= 1 << reg;
762 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
765 static int parse_operand(struct parsed_opr *opr,
766 int *regmask, int *regmask_indirect,
767 char words[16][256], int wordc, int w, unsigned int op_flags)
769 const struct parsed_proto *pp = NULL;
770 enum opr_lenmod tmplmod;
771 unsigned long number;
779 aerr("parse_operand w %d, wordc %d\n", w, wordc);
783 for (i = w; i < wordc; i++) {
784 len = strlen(words[i]);
785 if (words[i][len - 1] == ',') {
786 words[i][len - 1] = 0;
792 wordc_in = wordc - w;
794 if ((op_flags & OPF_JMP) && wordc_in > 0
795 && !('0' <= words[w][0] && words[w][0] <= '9'))
797 const char *label = NULL;
799 if (wordc_in == 3 && !strncmp(words[w], "near", 4)
800 && IS(words[w + 1], "ptr"))
801 label = words[w + 2];
802 else if (wordc_in == 2 && IS(words[w], "short"))
803 label = words[w + 1];
804 else if (wordc_in == 1
805 && strchr(words[w], '[') == NULL
806 && parse_reg(&tmplmod, words[w]) < 0)
810 opr->type = OPT_LABEL;
811 ret = check_segment_prefix(label);
816 strcpy(opr->name, label);
822 if (IS(words[w + 1], "ptr")) {
823 if (IS(words[w], "dword"))
824 opr->lmod = OPLM_DWORD;
825 else if (IS(words[w], "word"))
826 opr->lmod = OPLM_WORD;
827 else if (IS(words[w], "byte"))
828 opr->lmod = OPLM_BYTE;
829 else if (IS(words[w], "qword"))
830 opr->lmod = OPLM_QWORD;
832 aerr("type parsing failed\n");
834 wordc_in = wordc - w;
839 if (IS(words[w], "offset")) {
840 opr->type = OPT_OFFSET;
841 opr->lmod = OPLM_DWORD;
842 strcpy(opr->name, words[w + 1]);
843 pp = proto_parse(g_fhdr, opr->name, 1);
846 if (IS(words[w], "(offset")) {
847 p = strchr(words[w + 1], ')');
849 aerr("parse of bracketed offset failed\n");
851 opr->type = OPT_OFFSET;
852 strcpy(opr->name, words[w + 1]);
858 aerr("parse_operand 1 word expected\n");
860 ret = check_segment_prefix(words[w]);
863 memmove(words[w], words[w] + 3, strlen(words[w]) - 2);
864 if (ret == SEG_FS && IS(words[w], "0"))
867 strcpy(opr->name, words[w]);
869 if (words[w][0] == '[') {
870 opr->type = OPT_REGMEM;
871 ret = sscanf(words[w], "[%[^]]]", opr->name);
873 aerr("[] parse failure\n");
875 parse_indmode(opr->name, regmask_indirect, 1);
876 if (opr->lmod == OPLM_UNSPEC
877 && parse_stack_el(opr->name, NULL, NULL, 1))
880 struct parsed_equ *eq =
881 equ_find(NULL, parse_stack_el(opr->name, NULL, NULL, 1), &i);
883 opr->lmod = eq->lmod;
885 // might be unaligned access
886 g_func_lmods |= 1 << OPLM_BYTE;
890 else if (strchr(words[w], '[')) {
892 p = strchr(words[w], '[');
893 opr->type = OPT_REGMEM;
894 parse_indmode(p, regmask_indirect, 0);
895 strncpy(buf, words[w], p - words[w]);
896 buf[p - words[w]] = 0;
897 pp = proto_parse(g_fhdr, buf, 1);
900 else if (('0' <= words[w][0] && words[w][0] <= '9')
901 || words[w][0] == '-')
903 number = parse_number(words[w], 0);
904 opr->type = OPT_CONST;
906 printf_number(opr->name, sizeof(opr->name), number);
910 ret = parse_reg(&tmplmod, opr->name);
912 setup_reg_opr(opr, ret, tmplmod, regmask);
916 // most likely var in data segment
917 opr->type = OPT_LABEL;
918 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
922 if (pp->is_fptr || pp->is_func) {
923 opr->lmod = OPLM_DWORD;
927 tmplmod = OPLM_UNSPEC;
928 if (!guess_lmod_from_c_type(&tmplmod, &pp->type))
929 anote("unhandled C type '%s' for '%s'\n",
930 pp->type.name, opr->name);
932 if (opr->lmod == OPLM_UNSPEC) {
934 opr->type_from_var = 1;
936 else if (opr->lmod != tmplmod) {
937 opr->size_mismatch = 1;
938 if (tmplmod < opr->lmod)
941 opr->is_ptr = pp->type.is_ptr;
943 opr->is_array = pp->type.is_array;
947 if (opr->lmod == OPLM_UNSPEC)
948 guess_lmod_from_name(opr);
952 static const struct {
957 { "repe", OPF_REP|OPF_REPZ },
958 { "repz", OPF_REP|OPF_REPZ },
959 { "repne", OPF_REP|OPF_REPNZ },
960 { "repnz", OPF_REP|OPF_REPNZ },
961 { "lock", OPF_LOCK },
964 #define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
966 static const struct {
969 unsigned short minopr;
970 unsigned short maxopr;
973 unsigned char pfo_inv;
975 { "nop", OP_NOP, 0, 0, 0 },
976 { "push", OP_PUSH, 1, 1, 0 },
977 { "pop", OP_POP, 1, 1, OPF_DATA },
978 { "pusha",OP_PUSHA, 0, 0, 0 },
979 { "popa", OP_POPA, 0, 0, OPF_DATA },
980 { "leave",OP_LEAVE, 0, 0, OPF_DATA },
981 { "mov" , OP_MOV, 2, 2, OPF_DATA },
982 { "lea", OP_LEA, 2, 2, OPF_DATA },
983 { "movzx",OP_MOVZX, 2, 2, OPF_DATA },
984 { "movsx",OP_MOVSX, 2, 2, OPF_DATA },
985 { "xchg", OP_XCHG, 2, 2, OPF_DATA },
986 { "not", OP_NOT, 1, 1, OPF_DATA },
987 { "xlat", OP_XLAT, 0, 0, OPF_DATA },
988 { "cdq", OP_CDQ, 0, 0, OPF_DATA },
989 { "bswap",OP_BSWAP, 1, 1, OPF_DATA },
990 { "lodsb",OP_LODS, 0, 0, OPF_DATA },
991 { "lodsw",OP_LODS, 0, 0, OPF_DATA },
992 { "lodsd",OP_LODS, 0, 0, OPF_DATA },
993 { "stosb",OP_STOS, 0, 0, OPF_DATA },
994 { "stosw",OP_STOS, 0, 0, OPF_DATA },
995 { "stosd",OP_STOS, 0, 0, OPF_DATA },
996 { "movsb",OP_MOVS, 0, 0, OPF_DATA },
997 { "movsw",OP_MOVS, 0, 0, OPF_DATA },
998 { "movsd",OP_MOVS, 0, 0, OPF_DATA },
999 { "cmpsb",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
1000 { "cmpsw",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
1001 { "cmpsd",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
1002 { "scasb",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
1003 { "scasw",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
1004 { "scasd",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
1005 { "rdtsc",OP_RDTSC, 0, 0, OPF_DATA },
1006 { "cpuid",OP_CPUID, 0, 0, OPF_DATA },
1007 { "std", OP_STD, 0, 0, OPF_DATA }, // special flag
1008 { "cld", OP_CLD, 0, 0, OPF_DATA },
1009 { "add", OP_ADD, 2, 2, OPF_DATA|OPF_FLAGS },
1010 { "sub", OP_SUB, 2, 2, OPF_DATA|OPF_FLAGS },
1011 { "and", OP_AND, 2, 2, OPF_DATA|OPF_FLAGS },
1012 { "or", OP_OR, 2, 2, OPF_DATA|OPF_FLAGS },
1013 { "xor", OP_XOR, 2, 2, OPF_DATA|OPF_FLAGS },
1014 { "shl", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
1015 { "shr", OP_SHR, 2, 2, OPF_DATA|OPF_FLAGS },
1016 { "sal", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
1017 { "sar", OP_SAR, 2, 2, OPF_DATA|OPF_FLAGS },
1018 { "shld", OP_SHLD, 3, 3, OPF_DATA|OPF_FLAGS },
1019 { "shrd", OP_SHRD, 3, 3, OPF_DATA|OPF_FLAGS },
1020 { "rol", OP_ROL, 2, 2, OPF_DATA|OPF_FLAGS },
1021 { "ror", OP_ROR, 2, 2, OPF_DATA|OPF_FLAGS },
1022 { "rcl", OP_RCL, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1023 { "rcr", OP_RCR, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1024 { "adc", OP_ADC, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1025 { "sbb", OP_SBB, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1026 { "bsf", OP_BSF, 2, 2, OPF_DATA|OPF_FLAGS },
1027 { "bsr", OP_BSR, 2, 2, OPF_DATA|OPF_FLAGS },
1028 { "inc", OP_INC, 1, 1, OPF_DATA|OPF_FLAGS },
1029 { "dec", OP_DEC, 1, 1, OPF_DATA|OPF_FLAGS },
1030 { "neg", OP_NEG, 1, 1, OPF_DATA|OPF_FLAGS },
1031 { "mul", OP_MUL, 1, 1, OPF_DATA|OPF_FLAGS },
1032 { "imul", OP_IMUL, 1, 3, OPF_DATA|OPF_FLAGS },
1033 { "div", OP_DIV, 1, 1, OPF_DATA|OPF_FLAGS },
1034 { "idiv", OP_IDIV, 1, 1, OPF_DATA|OPF_FLAGS },
1035 { "test", OP_TEST, 2, 2, OPF_FLAGS },
1036 { "cmp", OP_CMP, 2, 2, OPF_FLAGS },
1037 { "retn", OP_RET, 0, 1, OPF_TAIL },
1038 { "call", OP_CALL, 1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
1039 { "jmp", OP_JMP, 1, 1, OPF_JMP },
1040 { "jecxz",OP_JECXZ, 1, 1, OPF_JMP|OPF_CJMP },
1041 { "loop", OP_LOOP, 1, 1, OPF_JMP|OPF_CJMP|OPF_DATA },
1042 { "jo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 0 }, // 70 OF=1
1043 { "jno", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 1 }, // 71 OF=0
1044 { "jc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72 CF=1
1045 { "jb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72
1046 { "jnc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73 CF=0
1047 { "jnb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1048 { "jae", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1049 { "jz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74 ZF=1
1050 { "je", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74
1051 { "jnz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75 ZF=0
1052 { "jne", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75
1053 { "jbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76 CF=1||ZF=1
1054 { "jna", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76
1055 { "ja", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77 CF=0&&ZF=0
1056 { "jnbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77
1057 { "js", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 0 }, // 78 SF=1
1058 { "jns", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 1 }, // 79 SF=0
1059 { "jp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a PF=1
1060 { "jpe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a
1061 { "jnp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b PF=0
1062 { "jpo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b
1063 { "jl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c SF!=OF
1064 { "jnge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c
1065 { "jge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d SF=OF
1066 { "jnl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d
1067 { "jle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e ZF=1||SF!=OF
1068 { "jng", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e
1069 { "jg", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f ZF=0&&SF=OF
1070 { "jnle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f
1071 { "seto", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 0 },
1072 { "setno", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 1 },
1073 { "setc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1074 { "setb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1075 { "setnc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1076 { "setae", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1077 { "setnb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1078 { "setz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1079 { "sete", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1080 { "setnz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1081 { "setne", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1082 { "setbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1083 { "setna", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1084 { "seta", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1085 { "setnbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1086 { "sets", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 0 },
1087 { "setns", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 1 },
1088 { "setp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1089 { "setpe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1090 { "setnp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1091 { "setpo", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1092 { "setl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1093 { "setnge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1094 { "setge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1095 { "setnl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1096 { "setle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1097 { "setng", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1098 { "setg", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1099 { "setnle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1101 { "fld", OP_FLD, 1, 1, OPF_FPUSH },
1102 { "fild", OP_FILD, 1, 1, OPF_FPUSH|OPF_FINT },
1103 { "fld1", OP_FLDc, 0, 0, OPF_FPUSH },
1104 { "fldl2t", OP_FLDc, 0, 0, OPF_FPUSH },
1105 { "fldl2e", OP_FLDc, 0, 0, OPF_FPUSH },
1106 { "fldpi", OP_FLDc, 0, 0, OPF_FPUSH },
1107 { "fldlg2", OP_FLDc, 0, 0, OPF_FPUSH },
1108 { "fldln2", OP_FLDc, 0, 0, OPF_FPUSH },
1109 { "fldz", OP_FLDc, 0, 0, OPF_FPUSH },
1110 { "fst", OP_FST, 1, 1, 0 },
1111 { "fstp", OP_FST, 1, 1, OPF_FPOP },
1112 { "fist", OP_FIST, 1, 1, OPF_FINT },
1113 { "fistp", OP_FIST, 1, 1, OPF_FPOP|OPF_FINT },
1114 { "fadd", OP_FADD, 0, 2, 0 },
1115 { "faddp", OP_FADD, 0, 2, OPF_FPOP },
1116 { "fdiv", OP_FDIV, 0, 2, 0 },
1117 { "fdivp", OP_FDIV, 0, 2, OPF_FPOP },
1118 { "fmul", OP_FMUL, 0, 2, 0 },
1119 { "fmulp", OP_FMUL, 0, 2, OPF_FPOP },
1120 { "fsub", OP_FSUB, 0, 2, 0 },
1121 { "fsubp", OP_FSUB, 0, 2, OPF_FPOP },
1122 { "fdivr", OP_FDIVR, 0, 2, 0 },
1123 { "fdivrp", OP_FDIVR, 0, 2, OPF_FPOP },
1124 { "fsubr", OP_FSUBR, 0, 2, 0 },
1125 { "fsubrp", OP_FSUBR, 0, 2, OPF_FPOP },
1126 { "fiadd", OP_FIADD, 1, 1, OPF_FINT },
1127 { "fidiv", OP_FIDIV, 1, 1, OPF_FINT },
1128 { "fimul", OP_FIMUL, 1, 1, OPF_FINT },
1129 { "fisub", OP_FISUB, 1, 1, OPF_FINT },
1130 { "fidivr", OP_FIDIVR, 1, 1, OPF_FINT },
1131 { "fisubr", OP_FISUBR, 1, 1, OPF_FINT },
1132 { "fcom", OP_FCOM, 0, 1, 0 },
1133 { "fcomp", OP_FCOM, 0, 1, OPF_FPOP },
1134 { "fcompp", OP_FCOM, 0, 0, OPF_FPOPP },
1135 { "fucom", OP_FCOM, 0, 1, 0 },
1136 { "fucomp", OP_FCOM, 0, 1, OPF_FPOP },
1137 { "fucompp",OP_FCOM, 0, 0, OPF_FPOPP },
1138 { "fnstsw", OP_FNSTSW, 1, 1, OPF_DATA },
1139 { "fchs", OP_FCHS, 0, 0, 0 },
1140 { "fcos", OP_FCOS, 0, 0, 0 },
1141 { "fpatan", OP_FPATAN, 0, 0, OPF_FPOP },
1142 { "fptan", OP_FPTAN, 0, 0, OPF_FPUSH },
1143 { "fsin", OP_FSIN, 0, 0, 0 },
1144 { "fsqrt", OP_FSQRT, 0, 0, 0 },
1145 { "fxch", OP_FXCH, 1, 1, 0 },
1146 { "fyl2x", OP_FYL2X, 0, 0, OPF_FPOP },
1148 { "emms", OP_EMMS, 0, 0, OPF_DATA },
1149 { "movq", OP_MOV, 2, 2, OPF_DATA },
1150 // pseudo-ops for lib calls
1151 { "_allshl",OPP_ALLSHL },
1152 { "_allshr",OPP_ALLSHR },
1153 { "_ftol", OPP_FTOL },
1154 { "_CIpow", OPP_CIPOW },
1155 { "abort", OPP_ABORT },
1160 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
1162 enum opr_lenmod lmod = OPLM_UNSPEC;
1163 int prefix_flags = 0;
1171 for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
1172 if (IS(words[w], pref_table[i].name)) {
1173 prefix_flags = pref_table[i].flags;
1180 aerr("lone prefix: '%s'\n", words[0]);
1185 for (i = 0; i < ARRAY_SIZE(op_table); i++) {
1186 if (IS(words[w], op_table[i].name))
1190 if (i == ARRAY_SIZE(op_table)) {
1192 aerr("unhandled op: '%s'\n", words[0]);
1197 op->op = op_table[i].op;
1198 op->flags = op_table[i].flags | prefix_flags;
1199 op->pfo = op_table[i].pfo;
1200 op->pfo_inv = op_table[i].pfo_inv;
1201 op->regmask_src = op->regmask_dst = 0;
1204 if (op->op == OP_UD2)
1207 for (opr = 0; opr < op_table[i].maxopr; opr++) {
1208 if (opr >= op_table[i].minopr && w >= wordc)
1211 regmask = regmask_ind = 0;
1212 w = parse_operand(&op->operand[opr], ®mask, ®mask_ind,
1213 words, wordc, w, op->flags);
1215 if (opr == 0 && (op->flags & OPF_DATA))
1216 op->regmask_dst = regmask;
1218 op->regmask_src |= regmask;
1219 op->regmask_src |= regmask_ind;
1221 if (op->operand[opr].lmod != OPLM_UNSPEC)
1222 g_func_lmods |= 1 << op->operand[opr].lmod;
1226 aerr("parse_op %s incomplete: %d/%d\n",
1227 words[0], w, wordc);
1230 op->operand_cnt = opr;
1231 if (!strncmp(op_table[i].name, "set", 3))
1232 op->operand[0].lmod = OPLM_BYTE;
1235 // first operand is not dst
1238 op->regmask_src |= op->regmask_dst;
1239 op->regmask_dst = 0;
1242 // first operand is src too
1255 op->regmask_src |= op->regmask_dst;
1260 op->regmask_src |= op->regmask_dst;
1261 op->regmask_dst |= op->regmask_src;
1267 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1268 && op->operand[0].lmod == op->operand[1].lmod
1269 && op->operand[0].reg == op->operand[1].reg
1270 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1272 op->regmask_src = 0;
1275 op->regmask_src |= op->regmask_dst;
1278 // ops with implicit argumets
1280 op->operand_cnt = 2;
1281 setup_reg_opr(&op->operand[0], xAX, OPLM_BYTE, &op->regmask_src);
1282 op->regmask_dst = op->regmask_src;
1283 setup_reg_opr(&op->operand[1], xBX, OPLM_DWORD, &op->regmask_src);
1287 op->operand_cnt = 2;
1288 setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
1289 setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
1295 if (words[op_w][4] == 'b')
1297 else if (words[op_w][4] == 'w')
1299 else if (words[op_w][4] == 'd')
1302 op->regmask_src = 0;
1303 setup_reg_opr(&op->operand[j++], op->op == OP_LODS ? xSI : xDI,
1304 OPLM_DWORD, &op->regmask_src);
1305 op->regmask_dst = op->regmask_src;
1306 setup_reg_opr(&op->operand[j++], xAX, lmod,
1307 op->op == OP_LODS ? &op->regmask_dst : &op->regmask_src);
1308 if (op->flags & OPF_REP) {
1309 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1310 op->regmask_dst |= 1 << xCX;
1312 op->operand_cnt = j;
1317 if (words[op_w][4] == 'b')
1319 else if (words[op_w][4] == 'w')
1321 else if (words[op_w][4] == 'd')
1324 op->regmask_src = 0;
1325 // note: lmod is not correct, don't have where to place it
1326 setup_reg_opr(&op->operand[j++], xDI, lmod, &op->regmask_src);
1327 setup_reg_opr(&op->operand[j++], xSI, OPLM_DWORD, &op->regmask_src);
1328 if (op->flags & OPF_REP)
1329 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1330 op->operand_cnt = j;
1331 op->regmask_dst = op->regmask_src;
1335 op->regmask_dst = mxAX | mxDX;
1339 // for now, ignore ecx dep for eax={4,7,b,d}
1340 op->regmask_src = mxAX;
1341 op->regmask_dst = mxAX | mxBX | mxCX | mxDX;
1345 op->regmask_dst = 1 << xCX;
1348 op->operand_cnt = 2;
1349 op->regmask_src = 1 << xCX;
1350 op->operand[1].type = OPT_REG;
1351 op->operand[1].reg = xCX;
1352 op->operand[1].lmod = OPLM_DWORD;
1356 if (op->operand_cnt == 2) {
1357 if (op->operand[0].type != OPT_REG)
1358 aerr("reg expected\n");
1359 op->regmask_src |= 1 << op->operand[0].reg;
1361 if (op->operand_cnt != 1)
1366 if (op->operand[0].lmod == OPLM_UNSPEC)
1367 op->operand[0].lmod = OPLM_DWORD;
1368 op->regmask_src = mxAX | op->regmask_dst;
1369 op->regmask_dst = mxAX;
1370 if (op->operand[0].lmod != OPLM_BYTE)
1371 op->regmask_dst |= mxDX;
1376 // we could set up operands for edx:eax, but there is no real need to
1377 // (see is_opr_modified())
1378 if (op->operand[0].lmod == OPLM_UNSPEC)
1379 op->operand[0].lmod = OPLM_DWORD;
1380 op->regmask_src = mxAX | op->regmask_dst;
1381 op->regmask_dst = mxAX;
1382 if (op->operand[0].lmod != OPLM_BYTE) {
1383 op->regmask_src |= mxDX;
1384 op->regmask_dst |= mxDX;
1393 op->regmask_src |= op->regmask_dst;
1394 if (op->operand[1].lmod == OPLM_UNSPEC)
1395 op->operand[1].lmod = OPLM_BYTE;
1400 op->regmask_src |= op->regmask_dst;
1401 if (op->operand[2].lmod == OPLM_UNSPEC)
1402 op->operand[2].lmod = OPLM_BYTE;
1406 op->regmask_src |= op->regmask_dst;
1407 op->regmask_dst = 0;
1408 if (op->operand[0].lmod == OPLM_UNSPEC
1409 && (op->operand[0].type == OPT_CONST
1410 || op->operand[0].type == OPT_OFFSET
1411 || op->operand[0].type == OPT_LABEL))
1412 op->operand[0].lmod = OPLM_DWORD;
1418 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1419 && op->operand[0].lmod == op->operand[1].lmod
1420 && op->operand[0].reg == op->operand[1].reg
1421 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1423 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1424 op->regmask_src = op->regmask_dst = 0;
1429 if (op->operand[0].type == OPT_REG
1430 && op->operand[1].type == OPT_REGMEM)
1433 snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1434 if (IS(buf, op->operand[1].name))
1435 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1440 // needed because of OPF_DATA
1441 op->regmask_src |= op->regmask_dst;
1442 // trashed regs must be explicitly detected later
1443 op->regmask_dst = 0;
1447 op->regmask_dst = (1 << xBP) | (1 << xSP);
1448 op->regmask_src = 1 << xBP;
1453 op->regmask_dst |= mxST0;
1457 op->regmask_dst |= mxST0;
1458 if (IS(words[op_w] + 3, "1"))
1459 op->operand[0].val = X87_CONST_1;
1460 else if (IS(words[op_w] + 3, "l2t"))
1461 op->operand[0].val = X87_CONST_L2T;
1462 else if (IS(words[op_w] + 3, "l2e"))
1463 op->operand[0].val = X87_CONST_L2E;
1464 else if (IS(words[op_w] + 3, "pi"))
1465 op->operand[0].val = X87_CONST_PI;
1466 else if (IS(words[op_w] + 3, "lg2"))
1467 op->operand[0].val = X87_CONST_LG2;
1468 else if (IS(words[op_w] + 3, "ln2"))
1469 op->operand[0].val = X87_CONST_LN2;
1470 else if (IS(words[op_w] + 3, "z"))
1471 op->operand[0].val = X87_CONST_Z;
1473 aerr("fld what?\n");
1478 op->regmask_src |= mxST0;
1487 op->regmask_src |= mxST0;
1488 if (op->operand_cnt == 2)
1489 op->regmask_src |= op->regmask_dst;
1490 else if (op->operand_cnt == 1) {
1491 memcpy(&op->operand[1], &op->operand[0], sizeof(op->operand[1]));
1492 op->operand[0].type = OPT_REG;
1493 op->operand[0].lmod = OPLM_QWORD;
1494 op->operand[0].reg = xST0;
1495 op->regmask_dst |= mxST0;
1498 // IDA doesn't use this
1499 aerr("no operands?\n");
1513 op->regmask_src |= mxST0;
1514 op->regmask_dst |= mxST0;
1519 op->regmask_src |= mxST0 | mxST1;
1520 op->regmask_dst |= mxST0;
1528 op->regmask_src |= mxST0;
1529 if (op->operand_cnt == 0) {
1530 op->operand_cnt = 1;
1531 op->operand[0].type = OPT_REG;
1532 op->operand[0].lmod = OPLM_QWORD;
1533 op->operand[0].reg = xST1;
1534 op->regmask_src |= mxST1;
1542 if (op->operand[0].type == OPT_REG
1543 && op->operand[1].type == OPT_CONST)
1545 struct parsed_opr *op1 = &op->operand[1];
1546 if ((op->op == OP_AND && op1->val == 0)
1549 || (op->operand[0].lmod == OPLM_WORD && op1->val == 0xffff)
1550 || (op->operand[0].lmod == OPLM_BYTE && op1->val == 0xff))))
1552 op->regmask_src = 0;
1557 static const char *op_name(struct parsed_op *po)
1559 static char buf[16];
1563 if (po->op == OP_JCC || po->op == OP_SCC) {
1565 *p++ = (po->op == OP_JCC) ? 'j' : 's';
1568 strcpy(p, parsed_flag_op_names[po->pfo]);
1572 for (i = 0; i < ARRAY_SIZE(op_table); i++)
1573 if (op_table[i].op == po->op)
1574 return op_table[i].name;
1580 static const char *dump_op(struct parsed_op *po)
1582 static char out[128];
1589 snprintf(out, sizeof(out), "%s", op_name(po));
1590 for (i = 0; i < po->operand_cnt; i++) {
1594 snprintf(p, sizeof(out) - (p - out),
1595 po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1596 po->operand[i].name);
1602 static const char *lmod_type_u(struct parsed_op *po,
1603 enum opr_lenmod lmod)
1615 ferr(po, "invalid lmod: %d\n", lmod);
1616 return "(_invalid_)";
1620 static const char *lmod_cast_u(struct parsed_op *po,
1621 enum opr_lenmod lmod)
1633 ferr(po, "invalid lmod: %d\n", lmod);
1634 return "(_invalid_)";
1638 static const char *lmod_cast_u_ptr(struct parsed_op *po,
1639 enum opr_lenmod lmod)
1651 ferr(po, "invalid lmod: %d\n", lmod);
1652 return "(_invalid_)";
1656 static const char *lmod_cast_s(struct parsed_op *po,
1657 enum opr_lenmod lmod)
1669 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1670 return "(_invalid_)";
1674 static const char *lmod_cast(struct parsed_op *po,
1675 enum opr_lenmod lmod, int is_signed)
1678 lmod_cast_s(po, lmod) :
1679 lmod_cast_u(po, lmod);
1682 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1694 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1699 static const char *opr_name(struct parsed_op *po, int opr_num)
1701 if (opr_num >= po->operand_cnt)
1702 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1703 return po->operand[opr_num].name;
1706 static unsigned int opr_const(struct parsed_op *po, int opr_num)
1708 if (opr_num >= po->operand_cnt)
1709 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1710 if (po->operand[opr_num].type != OPT_CONST)
1711 ferr(po, "opr %d: const expected\n", opr_num);
1712 return po->operand[opr_num].val;
1715 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1717 if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
1718 ferr(po, "invalid reg: %d\n", popr->reg);
1719 return regs_r32[popr->reg];
1722 static int check_simple_cast(const char *cast, int *bits, int *is_signed)
1724 if (IS_START(cast, "(s8)") || IS_START(cast, "(u8)"))
1726 else if (IS_START(cast, "(s16)") || IS_START(cast, "(u16)"))
1728 else if (IS_START(cast, "(s32)") || IS_START(cast, "(u32)"))
1730 else if (IS_START(cast, "(s64)") || IS_START(cast, "(u64)"))
1735 *is_signed = cast[1] == 's' ? 1 : 0;
1739 static int check_deref_cast(const char *cast, int *bits)
1741 if (IS_START(cast, "*(u8 *)"))
1743 else if (IS_START(cast, "*(u16 *)"))
1745 else if (IS_START(cast, "*(u32 *)"))
1747 else if (IS_START(cast, "*(u64 *)"))
1755 // cast1 is the "final" cast
1756 static const char *simplify_cast(const char *cast1, const char *cast2)
1758 static char buf[256];
1766 if (IS(cast1, cast2))
1769 if (check_simple_cast(cast1, &bits1, &s1) == 0
1770 && check_simple_cast(cast2, &bits2, &s2) == 0)
1775 if (check_simple_cast(cast1, &bits1, &s1) == 0
1776 && check_deref_cast(cast2, &bits2) == 0)
1778 if (bits1 == bits2) {
1779 snprintf(buf, sizeof(buf), "*(%c%d *)", s1 ? 's' : 'u', bits1);
1784 if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1787 snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1791 static const char *simplify_cast_num(const char *cast, unsigned int val)
1793 if (IS(cast, "(u8)") && val < 0x100)
1795 if (IS(cast, "(s8)") && val < 0x80)
1797 if (IS(cast, "(u16)") && val < 0x10000)
1799 if (IS(cast, "(s16)") && val < 0x8000)
1801 if (IS(cast, "(s32)") && val < 0x80000000)
1807 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1816 namelen = strlen(name);
1818 p = strpbrk(name, "+-");
1822 ferr(po, "equ parse failed for '%s'\n", name);
1825 *extra_offs = strtol(p, &endp, 16);
1826 if (*endp != 0 || errno != 0)
1827 ferr(po, "equ parse failed for '%s'\n", name);
1830 for (i = 0; i < g_eqcnt; i++)
1831 if (strncmp(g_eqs[i].name, name, namelen) == 0
1832 && g_eqs[i].name[namelen] == 0)
1836 ferr(po, "unresolved equ name: '%s'\n", name);
1843 static int is_stack_access(struct parsed_op *po,
1844 const struct parsed_opr *popr)
1846 return (parse_stack_el(popr->name, NULL, NULL, 0)
1847 || (g_bp_frame && !(po->flags & OPF_EBP_S)
1848 && IS_START(popr->name, "ebp")));
1851 static void parse_stack_access(struct parsed_op *po,
1852 const char *name, char *ofs_reg, int *offset_out,
1853 int *stack_ra_out, const char **bp_arg_out, int is_lea)
1855 const char *bp_arg = "";
1856 const char *p = NULL;
1857 struct parsed_equ *eq;
1864 if (IS_START(name, "ebp-")
1865 || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1868 if (IS_START(p, "0x"))
1871 offset = strtoul(p, &endp, 16);
1874 if (*endp != 0 || errno != 0)
1875 ferr(po, "ebp- parse of '%s' failed\n", name);
1878 bp_arg = parse_stack_el(name, ofs_reg, NULL, 0);
1879 eq = equ_find(po, bp_arg, &offset);
1881 ferr(po, "detected but missing eq\n");
1882 offset += eq->offset;
1885 if (!strncmp(name, "ebp", 3))
1888 // yes it sometimes LEAs ra for compares..
1889 if (!is_lea && ofs_reg[0] == 0
1890 && stack_ra <= offset && offset < stack_ra + 4)
1892 ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1895 *offset_out = offset;
1897 *stack_ra_out = stack_ra;
1899 *bp_arg_out = bp_arg;
1902 static int parse_stack_esp_offset(struct parsed_op *po,
1903 const char *name, int *offset_out)
1905 char ofs_reg[16] = { 0, };
1906 struct parsed_equ *eq;
1912 if (strstr(name, "esp") == NULL)
1914 bp_arg = parse_stack_el(name, ofs_reg, &base_val, 0);
1915 if (bp_arg == NULL) {
1916 // just plain offset?
1917 if (!IS_START(name, "esp+"))
1920 offset = strtol(name + 4, &endp, 0);
1921 if (endp == NULL || *endp != 0 || errno != 0)
1923 *offset_out = offset;
1927 if (ofs_reg[0] != 0)
1929 eq = equ_find(po, bp_arg, &offset);
1931 ferr(po, "detected but missing eq\n");
1932 offset += eq->offset;
1933 *offset_out = base_val + offset;
1937 static int stack_frame_access(struct parsed_op *po,
1938 struct parsed_opr *popr, char *buf, size_t buf_size,
1939 const char *name, const char *cast, int is_src, int is_lea)
1941 enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1942 const char *prefix = "";
1943 const char *bp_arg = NULL;
1944 char ofs_reg[16] = { 0, };
1946 int i, arg_i, arg_s;
1953 if (g_bp_frame && (po->flags & OPF_EBP_S)
1954 && !(po->regmask_src & mxSP))
1955 ferr(po, "stack_frame_access while ebp is scratch\n");
1957 parse_stack_access(po, name, ofs_reg, &offset,
1958 &stack_ra, &bp_arg, is_lea);
1960 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1962 if (offset > stack_ra)
1964 arg_i = (offset - stack_ra - 4) / 4;
1965 if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1967 if (g_func_pp->is_vararg
1968 && arg_i == g_func_pp->argc_stack && is_lea)
1970 // should be va_list
1973 snprintf(buf, buf_size, "%sap", cast);
1976 ferr(po, "offset 0x%x (%s,%d) doesn't map to any arg\n",
1977 offset, bp_arg, arg_i);
1979 if (ofs_reg[0] != 0)
1980 ferr(po, "offset reg on arg access?\n");
1982 for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1983 if (g_func_pp->arg[i].reg != NULL)
1989 if (i == g_func_pp->argc)
1990 ferr(po, "arg %d not in prototype?\n", arg_i);
1992 popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
1995 snprintf(argname, sizeof(argname), "%sa%d",
1996 g_sct_func_attr & SCTFA_ARGFRAME ? "af." : "", i + 1);
2002 ferr(po, "lea/byte to arg?\n");
2003 if (is_src && (offset & 3) == 0)
2004 snprintf(buf, buf_size, "%s%s",
2005 simplify_cast(cast, "(u8)"), argname);
2007 snprintf(buf, buf_size, "%sBYTE%d(%s)",
2008 cast, offset & 3, argname);
2013 ferr(po, "lea/word to arg?\n");
2018 ferr(po, "problematic arg store\n");
2019 snprintf(buf, buf_size, "%s((char *)&%s + 1)",
2020 simplify_cast(cast, "*(u16 *)"), argname);
2023 ferr(po, "unaligned arg word load\n");
2025 else if (is_src && (offset & 2) == 0)
2026 snprintf(buf, buf_size, "%s%s",
2027 simplify_cast(cast, "(u16)"), argname);
2029 snprintf(buf, buf_size, "%s%sWORD(%s)",
2030 cast, (offset & 2) ? "HI" : "LO", argname);
2042 snprintf(buf, buf_size, "(u32)&%s + %d",
2043 argname, offset & 3);
2045 ferr(po, "unaligned arg store\n");
2047 // mov edx, [ebp+arg_4+2]; movsx ecx, dx
2048 snprintf(buf, buf_size, "%s(%s >> %d)",
2049 prefix, argname, (offset & 3) * 8);
2053 snprintf(buf, buf_size, "%s%s%s",
2054 prefix, is_lea ? "&" : "", argname);
2059 ferr_assert(po, !(offset & 7));
2062 snprintf(buf, buf_size, "%s%s%s",
2063 prefix, is_lea ? "&" : "", argname);
2067 ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
2071 strcat(g_comment, " unaligned");
2074 guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
2075 if (tmp_lmod != OPLM_DWORD
2076 && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
2077 < lmod_bytes(po, popr->lmod) + (offset & 3))))
2079 ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
2080 i + 1, offset, g_func_pp->arg[i].type.name);
2082 // can't check this because msvc likes to reuse
2083 // arg space for scratch..
2084 //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
2085 // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
2089 if (g_stack_fsz == 0)
2090 ferr(po, "stack var access without stackframe\n");
2091 g_stack_frame_used = 1;
2093 sf_ofs = g_stack_fsz + offset;
2094 if (ofs_reg[0] == 0 && (offset > 0 || sf_ofs < 0))
2095 ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
2105 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2106 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2110 if ((sf_ofs & 1) || ofs_reg[0] != 0) {
2111 // known unaligned or possibly unaligned
2112 strcat(g_comment, " unaligned");
2114 prefix = "*(u16 *)&";
2115 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2116 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2119 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
2123 if ((sf_ofs & 3) || ofs_reg[0] != 0) {
2124 // known unaligned or possibly unaligned
2125 strcat(g_comment, " unaligned");
2127 prefix = "*(u32 *)&";
2128 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2129 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2132 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
2136 ferr_assert(po, !(sf_ofs & 7));
2137 ferr_assert(po, ofs_reg[0] == 0);
2138 // only used for x87 int64/float, float sets is_lea
2139 if (!is_lea && (po->flags & OPF_FINT))
2140 prefix = "*(s64 *)&";
2141 snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
2145 ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
2152 static void check_func_pp(struct parsed_op *po,
2153 const struct parsed_proto *pp, const char *pfx)
2155 enum opr_lenmod tmp_lmod;
2159 if (pp->argc_reg != 0) {
2160 if (!g_allow_user_icall && !pp->is_fastcall) {
2161 pp_print(buf, sizeof(buf), pp);
2162 ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
2164 if (pp->argc_stack > 0 && pp->argc_reg != 2)
2165 ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
2166 pfx, pp->argc_reg, pp->argc_stack);
2169 // fptrs must use 32bit args, callsite might have no information and
2170 // lack a cast to smaller types, which results in incorrectly masked
2171 // args passed (callee may assume masked args, it does on ARM)
2172 if (!pp->is_osinc) {
2173 for (i = 0; i < pp->argc; i++) {
2174 ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
2175 if (ret && tmp_lmod != OPLM_DWORD)
2176 ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
2177 i + 1, pp->arg[i].type.name);
2182 static const char *check_label_read_ref(struct parsed_op *po,
2183 const char *name, int *is_import)
2185 const struct parsed_proto *pp;
2187 pp = proto_parse(g_fhdr, name, 0);
2189 ferr(po, "proto_parse failed for ref '%s'\n", name);
2192 check_func_pp(po, pp, "ref");
2194 if (is_import != NULL)
2195 *is_import = pp->is_import;
2200 static void check_opr(struct parsed_op *po, struct parsed_opr *popr)
2202 if (popr->segment == SEG_FS)
2203 ferr(po, "fs: used\n");
2204 if (popr->segment == SEG_GS)
2205 ferr(po, "gs: used\n");
2208 static char *out_src_opr(char *buf, size_t buf_size,
2209 struct parsed_op *po, struct parsed_opr *popr, const char *cast,
2212 char tmp1[256], tmp2[256];
2219 check_opr(po, popr);
2224 switch (popr->type) {
2227 ferr(po, "lea from reg?\n");
2229 switch (popr->lmod) {
2231 snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2234 snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2237 snprintf(buf, buf_size, "%s%s",
2238 simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2241 if (popr->name[1] == 'h') // XXX..
2242 snprintf(buf, buf_size, "%s(%s >> 8)",
2243 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2245 snprintf(buf, buf_size, "%s%s",
2246 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2249 ferr(po, "invalid src lmod: %d\n", popr->lmod);
2254 if (is_stack_access(po, popr)) {
2255 stack_frame_access(po, popr, buf, buf_size,
2256 popr->name, cast, 1, is_lea);
2260 strcpy(expr, popr->name);
2261 if (strchr(expr, '[')) {
2262 // special case: '[' can only be left for label[reg] form
2263 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2265 ferr(po, "parse failure for '%s'\n", expr);
2266 if (tmp1[0] == '(') {
2267 // (off_4FFF50+3)[eax]
2268 p = strchr(tmp1 + 1, ')');
2269 if (p == NULL || p[1] != 0)
2270 ferr(po, "parse failure (2) for '%s'\n", expr);
2272 memmove(tmp1, tmp1 + 1, strlen(tmp1));
2274 snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2277 // XXX: do we need more parsing?
2279 snprintf(buf, buf_size, "%s", expr);
2283 snprintf(buf, buf_size, "%s(%s)",
2284 simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2288 name = check_label_read_ref(po, popr->name, &is_import);
2290 // for imported data, asm is loading the offset
2293 if (cast[0] == 0 && popr->is_ptr)
2297 snprintf(buf, buf_size, "(u32)&%s", name);
2298 else if (popr->size_lt)
2299 snprintf(buf, buf_size, "%s%s%s%s", cast,
2300 lmod_cast_u_ptr(po, popr->lmod),
2301 popr->is_array ? "" : "&", name);
2303 snprintf(buf, buf_size, "%s%s%s", cast, name,
2304 popr->is_array ? "[0]" : "");
2309 name = check_label_read_ref(po, popr->name, NULL);
2313 ferr(po, "lea an offset?\n");
2314 snprintf(buf, buf_size, "%s&%s", cast, name);
2319 ferr(po, "lea from const?\n");
2321 printf_number(tmp1, sizeof(tmp1), popr->val);
2322 if (popr->val == 0 && strchr(cast, '*'))
2323 snprintf(buf, buf_size, "NULL");
2325 snprintf(buf, buf_size, "%s%s",
2326 simplify_cast_num(cast, popr->val), tmp1);
2330 ferr(po, "invalid src type: %d\n", popr->type);
2336 // note: may set is_ptr (we find that out late for ebp frame..)
2337 static char *out_dst_opr(char *buf, size_t buf_size,
2338 struct parsed_op *po, struct parsed_opr *popr)
2340 check_opr(po, popr);
2342 switch (popr->type) {
2344 switch (popr->lmod) {
2346 snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2349 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2353 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2357 if (popr->name[1] == 'h') // XXX..
2358 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2360 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2363 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2368 if (is_stack_access(po, popr)) {
2369 stack_frame_access(po, popr, buf, buf_size,
2370 popr->name, "", 0, 0);
2374 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2377 if (popr->size_mismatch)
2378 snprintf(buf, buf_size, "%s%s%s",
2379 lmod_cast_u_ptr(po, popr->lmod),
2380 popr->is_array ? "" : "&", popr->name);
2382 snprintf(buf, buf_size, "%s%s", popr->name,
2383 popr->is_array ? "[0]" : "");
2387 ferr(po, "invalid dst type: %d\n", popr->type);
2393 static char *out_src_opr_u32(char *buf, size_t buf_size,
2394 struct parsed_op *po, struct parsed_opr *popr)
2396 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2399 static char *out_opr_float(char *buf, size_t buf_size,
2400 struct parsed_op *po, struct parsed_opr *popr, int is_src,
2401 int need_float_stack)
2403 const char *cast = NULL;
2410 switch (popr->type) {
2412 if (popr->reg < xST0 || popr->reg > xST7) {
2414 ferr_assert(po, po->op == OP_PUSH);
2415 ferr_assert(po, popr->lmod == OPLM_DWORD);
2416 snprintf(buf, buf_size, "*(float *)&%s", opr_reg_p(po, popr));
2420 if (need_float_stack) {
2421 if (popr->reg == xST0)
2422 snprintf(buf, buf_size, "f_st[f_stp & 7]");
2424 snprintf(buf, buf_size, "f_st[(f_stp + %d) & 7]",
2428 snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2432 if (popr->lmod == OPLM_QWORD && is_stack_access(po, popr)) {
2433 stack_frame_access(po, popr, buf, buf_size,
2434 popr->name, "", is_src, 0);
2440 switch (popr->lmod) {
2448 ferr(po, "unhandled lmod: %d\n", popr->lmod);
2451 out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2452 snprintf(buf, buf_size, "*(%s *)(%s)", cast, tmp);
2456 // only for func float args pushes
2457 ferr_assert(po, po->op == OP_PUSH);
2458 u.i = po->operand[0].val;
2459 if (ceilf(u.f) == u.f)
2460 snprintf(buf, buf_size, "%.1ff", u.f);
2462 snprintf(buf, buf_size, "%.8ff", u.f);
2466 ferr(po, "invalid float type: %d\n", popr->type);
2472 static char *out_src_opr_float(char *buf, size_t buf_size,
2473 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2475 return out_opr_float(buf, buf_size, po, popr, 1, need_float_stack);
2478 static char *out_dst_opr_float(char *buf, size_t buf_size,
2479 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2481 return out_opr_float(buf, buf_size, po, popr, 0, need_float_stack);
2484 static void out_test_for_cc(char *buf, size_t buf_size,
2485 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2486 enum opr_lenmod lmod, const char *expr)
2488 const char *cast, *scast;
2490 cast = lmod_cast_u(po, lmod);
2491 scast = lmod_cast_s(po, lmod);
2495 case PFO_BE: // CF==1||ZF==1; CF=0
2496 snprintf(buf, buf_size, "(%s%s %s 0)",
2497 cast, expr, is_inv ? "!=" : "==");
2501 case PFO_L: // SF!=OF; OF=0
2502 snprintf(buf, buf_size, "(%s%s %s 0)",
2503 scast, expr, is_inv ? ">=" : "<");
2506 case PFO_LE: // ZF==1||SF!=OF; OF=0
2507 snprintf(buf, buf_size, "(%s%s %s 0)",
2508 scast, expr, is_inv ? ">" : "<=");
2513 snprintf(buf, buf_size, "(%d)", !!is_inv);
2516 case PFO_P: // PF==1
2517 snprintf(buf, buf_size, "(%sdo_parity(%s))",
2518 is_inv ? "!" : "", expr);
2522 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2526 static void out_cmp_for_cc(char *buf, size_t buf_size,
2527 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2530 const char *cast, *scast, *cast_use;
2531 char buf1[256], buf2[256];
2532 enum opr_lenmod lmod;
2534 if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2535 ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2536 po->operand[0].lmod, po->operand[1].lmod);
2537 lmod = po->operand[0].lmod;
2539 cast = lmod_cast_u(po, lmod);
2540 scast = lmod_cast_s(po, lmod);
2556 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2559 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2560 if (po->op == OP_DEC)
2561 snprintf(buf2, sizeof(buf2), "1");
2564 snprintf(cast_op2, sizeof(cast_op2) - 1, "%s", cast_use);
2566 strcat(cast_op2, "-");
2567 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_op2, 0);
2572 // note: must be unsigned compare
2573 snprintf(buf, buf_size, "(%s %s %s)",
2574 buf1, is_inv ? ">=" : "<", buf2);
2578 snprintf(buf, buf_size, "(%s %s %s)",
2579 buf1, is_inv ? "!=" : "==", buf2);
2583 // note: must be unsigned compare
2584 snprintf(buf, buf_size, "(%s %s %s)",
2585 buf1, is_inv ? ">" : "<=", buf2);
2588 if (is_inv && lmod == OPLM_BYTE
2589 && po->operand[1].type == OPT_CONST
2590 && po->operand[1].val == 0xff)
2592 snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2593 snprintf(buf, buf_size, "(0)");
2597 // note: must be signed compare
2599 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2600 scast, buf1, buf2, is_inv ? ">=" : "<");
2604 snprintf(buf, buf_size, "(%s %s %s)",
2605 buf1, is_inv ? ">=" : "<", buf2);
2609 snprintf(buf, buf_size, "(%s %s %s)",
2610 buf1, is_inv ? ">" : "<=", buf2);
2618 static void out_cmp_test(char *buf, size_t buf_size,
2619 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2621 char buf1[256], buf2[256], buf3[256];
2623 if (po->op == OP_TEST) {
2624 if (IS(opr_name(po, 0), opr_name(po, 1))) {
2625 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2628 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2629 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2630 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2632 out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2633 po->operand[0].lmod, buf3);
2635 else if (po->op == OP_CMP) {
2636 out_cmp_for_cc(buf, buf_size, po, pfo, is_inv, 0);
2639 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2642 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2643 struct parsed_opr *popr2)
2645 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2646 ferr(po, "missing lmod for both operands\n");
2648 if (popr1->lmod == OPLM_UNSPEC)
2649 popr1->lmod = popr2->lmod;
2650 else if (popr2->lmod == OPLM_UNSPEC)
2651 popr2->lmod = popr1->lmod;
2652 else if (popr1->lmod != popr2->lmod) {
2653 if (popr1->type_from_var) {
2654 popr1->size_mismatch = 1;
2655 if (popr1->lmod < popr2->lmod)
2657 popr1->lmod = popr2->lmod;
2659 else if (popr2->type_from_var) {
2660 popr2->size_mismatch = 1;
2661 if (popr2->lmod < popr1->lmod)
2663 popr2->lmod = popr1->lmod;
2666 ferr(po, "conflicting lmods: %d vs %d\n",
2667 popr1->lmod, popr2->lmod);
2671 static const char *op_to_c(struct parsed_op *po)
2695 ferr(po, "op_to_c was supplied with %d\n", po->op);
2699 // last op in stream - unconditional branch or ret
2700 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2701 || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2702 && ops[_i].op != OP_CALL))
2704 #define check_i(po, i) \
2706 ferr(po, "bad " #i ": %d\n", i)
2708 // note: this skips over calls and rm'd stuff assuming they're handled
2709 // so it's intended to use at one of final passes
2710 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2711 int depth, int seen_noreturn, int flags_set)
2713 struct parsed_op *po;
2718 for (; i < opcnt; i++) {
2720 if (po->cc_scratch == magic)
2721 return ret; // already checked
2722 po->cc_scratch = magic;
2724 if (po->flags & OPF_TAIL) {
2725 if (po->op == OP_CALL) {
2726 if (po->pp != NULL && po->pp->is_noreturn)
2735 if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
2738 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2739 if (po->btj != NULL) {
2741 for (j = 0; j < po->btj->count; j++) {
2742 check_i(po, po->btj->d[j].bt_i);
2743 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2744 depth, seen_noreturn, flags_set);
2746 return ret; // dead end
2751 check_i(po, po->bt_i);
2752 if (po->flags & OPF_CJMP) {
2753 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2754 depth, seen_noreturn, flags_set);
2756 return ret; // dead end
2765 if ((po->op == OP_POP || po->op == OP_PUSH)
2766 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2771 if (po->op == OP_PUSH) {
2774 else if (po->op == OP_POP) {
2775 if (relevant && depth == 0) {
2776 po->flags |= flags_set;
2784 // for noreturn, assume msvc skipped stack cleanup
2785 return seen_noreturn ? 1 : -1;
2788 // scan for 'reg' pop backwards starting from i
2789 // intended to use for register restore search, so other reg
2790 // references are considered an error
2791 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2793 struct parsed_op *po;
2794 struct label_ref *lr;
2797 ops[i].cc_scratch = magic;
2801 if (g_labels[i] != NULL) {
2802 lr = &g_label_refs[i];
2803 for (; lr != NULL; lr = lr->next) {
2804 check_i(&ops[i], lr->i);
2805 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2809 if (i > 0 && LAST_OP(i - 1))
2817 if (ops[i].cc_scratch == magic)
2819 ops[i].cc_scratch = magic;
2822 if (po->op == OP_POP && po->operand[0].reg == reg) {
2823 if (po->flags & (OPF_RMD|OPF_DONE))
2826 po->flags |= set_flags;
2830 // this also covers the case where we reach corresponding push
2831 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2835 // nothing interesting on this path,
2836 // still return ret for something recursive calls could find
2840 static void find_reachable_exits(int i, int opcnt, int magic,
2841 int *exits, int *exit_count)
2843 struct parsed_op *po;
2846 for (; i < opcnt; i++)
2849 if (po->cc_scratch == magic)
2851 po->cc_scratch = magic;
2853 if (po->flags & OPF_TAIL) {
2854 ferr_assert(po, *exit_count < MAX_EXITS);
2855 exits[*exit_count] = i;
2860 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2861 if (po->flags & OPF_RMD)
2864 if (po->btj != NULL) {
2865 for (j = 0; j < po->btj->count; j++) {
2866 check_i(po, po->btj->d[j].bt_i);
2867 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2873 check_i(po, po->bt_i);
2874 if (po->flags & OPF_CJMP)
2875 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2883 // scan for 'reg' pop backwards starting from exits (all paths)
2884 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2886 static int exits[MAX_EXITS];
2887 static int exit_count;
2893 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2895 ferr_assert(&ops[i], exit_count > 0);
2898 for (j = 0; j < exit_count; j++) {
2900 ret = scan_for_rsave_pop_reg(e, i + opcnt * 16 + set_flags,
2906 if (ops[e].op == OP_CALL && ops[e].pp != NULL
2907 && ops[e].pp->is_noreturn)
2909 // assume stack cleanup was skipped
2918 // scan for one or more pop of push <const>
2919 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2920 int push_i, int is_probe)
2922 struct parsed_op *po;
2923 struct label_ref *lr;
2927 for (; i < opcnt; i++)
2930 if (po->cc_scratch == magic)
2931 return ret; // already checked
2932 po->cc_scratch = magic;
2934 if (po->flags & OPF_JMP) {
2935 if (po->flags & OPF_RMD)
2937 if (po->op == OP_CALL)
2940 if (po->btj != NULL) {
2941 for (j = 0; j < po->btj->count; j++) {
2942 check_i(po, po->btj->d[j].bt_i);
2943 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2951 check_i(po, po->bt_i);
2952 if (po->flags & OPF_CJMP) {
2953 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2964 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2967 if (g_labels[i] != NULL) {
2968 // all refs must be visited
2969 lr = &g_label_refs[i];
2970 for (; lr != NULL; lr = lr->next) {
2972 if (ops[lr->i].cc_scratch != magic)
2975 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2979 if (po->op == OP_POP)
2981 if (po->flags & (OPF_RMD|OPF_DONE))
2985 po->flags |= OPF_DONE;
2986 po->datap = &ops[push_i];
2995 static void scan_for_pop_const(int i, int opcnt, int magic)
2999 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
3001 ops[i].flags |= OPF_RMD | OPF_DONE;
3002 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
3006 // check if all branch targets within a marked path are also marked
3007 // note: the path checked must not be empty or end with a branch
3008 static int check_path_branches(int opcnt, int magic)
3010 struct parsed_op *po;
3013 for (i = 0; i < opcnt; i++) {
3015 if (po->cc_scratch != magic)
3018 if (po->flags & OPF_JMP) {
3019 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
3022 if (po->btj != NULL) {
3023 for (j = 0; j < po->btj->count; j++) {
3024 check_i(po, po->btj->d[j].bt_i);
3025 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
3030 check_i(po, po->bt_i);
3031 if (ops[po->bt_i].cc_scratch != magic)
3033 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
3041 // scan for multiple pushes for given pop
3042 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
3045 int reg = ops[pop_i].operand[0].reg;
3046 struct parsed_op *po;
3047 struct label_ref *lr;
3050 ops[i].cc_scratch = magic;
3054 if (g_labels[i] != NULL) {
3055 lr = &g_label_refs[i];
3056 for (; lr != NULL; lr = lr->next) {
3057 check_i(&ops[i], lr->i);
3058 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
3062 if (i > 0 && LAST_OP(i - 1))
3070 if (ops[i].cc_scratch == magic)
3072 ops[i].cc_scratch = magic;
3075 if (po->op == OP_CALL)
3077 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
3080 if (po->op == OP_PUSH)
3082 if (po->datap != NULL)
3084 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
3085 // leave this case for reg save/restore handlers
3089 po->flags |= OPF_PPUSH | OPF_DONE;
3090 po->datap = &ops[pop_i];
3099 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
3101 int magic = i + opcnt * 14;
3104 ret = scan_pushes_for_pop_r(i, magic, i, 1);
3106 ret = check_path_branches(opcnt, magic);
3108 ops[i].flags |= OPF_PPUSH | OPF_DONE;
3109 *regmask_pp |= 1 << ops[i].operand[0].reg;
3110 scan_pushes_for_pop_r(i, magic + 1, i, 0);
3115 static void scan_propagate_df(int i, int opcnt)
3117 struct parsed_op *po = &ops[i];
3120 for (; i < opcnt; i++) {
3122 if (po->flags & OPF_DF)
3123 return; // already resolved
3124 po->flags |= OPF_DF;
3126 if (po->op == OP_CALL)
3127 ferr(po, "call with DF set?\n");
3129 if (po->flags & OPF_JMP) {
3130 if (po->btj != NULL) {
3132 for (j = 0; j < po->btj->count; j++) {
3133 check_i(po, po->btj->d[j].bt_i);
3134 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
3139 if (po->flags & OPF_RMD)
3141 check_i(po, po->bt_i);
3142 if (po->flags & OPF_CJMP)
3143 scan_propagate_df(po->bt_i, opcnt);
3149 if (po->flags & OPF_TAIL)
3152 if (po->op == OP_CLD) {
3153 po->flags |= OPF_RMD | OPF_DONE;
3158 ferr(po, "missing DF clear?\n");
3161 // is operand 'opr' referenced by parsed_op 'po'?
3162 static int is_opr_referenced(const struct parsed_opr *opr,
3163 const struct parsed_op *po)
3167 if (opr->type == OPT_REG) {
3168 mask = po->regmask_dst | po->regmask_src;
3169 if (po->op == OP_CALL)
3170 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
3171 if ((1 << opr->reg) & mask)
3177 for (i = 0; i < po->operand_cnt; i++)
3178 if (IS(po->operand[0].name, opr->name))
3184 // is operand 'opr' read by parsed_op 'po'?
3185 static int is_opr_read(const struct parsed_opr *opr,
3186 const struct parsed_op *po)
3188 if (opr->type == OPT_REG) {
3189 if (po->regmask_src & (1 << opr->reg))
3199 // is operand 'opr' modified by parsed_op 'po'?
3200 static int is_opr_modified(const struct parsed_opr *opr,
3201 const struct parsed_op *po)
3205 if (opr->type == OPT_REG) {
3206 if (po->op == OP_CALL) {
3207 mask = po->regmask_dst;
3208 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
3209 if (mask & (1 << opr->reg))
3215 if (po->regmask_dst & (1 << opr->reg))
3221 return IS(po->operand[0].name, opr->name);
3224 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
3225 static int is_any_opr_modified(const struct parsed_op *po_test,
3226 const struct parsed_op *po, int c_mode)
3231 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
3234 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3237 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
3240 // in reality, it can wreck any register, but in decompiled C
3241 // version it can only overwrite eax or edx:eax
3242 mask = (1 << xAX) | (1 << xDX);
3246 if (po->op == OP_CALL
3247 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
3250 for (i = 0; i < po_test->operand_cnt; i++)
3251 if (IS(po_test->operand[i].name, po->operand[0].name))
3257 // scan for any po_test operand modification in range given
3258 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
3261 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3264 for (; i < opcnt; i++) {
3265 if (is_any_opr_modified(po_test, &ops[i], c_mode))
3272 // scan for po_test operand[0] modification in range given
3273 static int scan_for_mod_opr0(struct parsed_op *po_test,
3276 for (; i < opcnt; i++) {
3277 if (is_opr_modified(&po_test->operand[0], &ops[i]))
3284 static int try_resolve_const(int i, const struct parsed_opr *opr,
3285 int magic, unsigned int *val);
3287 static int scan_for_flag_set(int i, int opcnt, int magic,
3288 int *branched, int *setters, int *setter_cnt)
3290 struct label_ref *lr;
3294 if (ops[i].cc_scratch == magic) {
3295 // is this a problem?
3296 //ferr(&ops[i], "%s looped\n", __func__);
3299 ops[i].cc_scratch = magic;
3301 if (g_labels[i] != NULL) {
3304 lr = &g_label_refs[i];
3305 for (; lr->next; lr = lr->next) {
3306 check_i(&ops[i], lr->i);
3307 ret = scan_for_flag_set(lr->i, opcnt, magic,
3308 branched, setters, setter_cnt);
3313 check_i(&ops[i], lr->i);
3314 if (i > 0 && LAST_OP(i - 1)) {
3318 ret = scan_for_flag_set(lr->i, opcnt, magic,
3319 branched, setters, setter_cnt);
3325 if (ops[i].flags & OPF_FLAGS) {
3326 setters[*setter_cnt] = i;
3329 if (ops[i].flags & OPF_REP) {
3330 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
3333 ret = try_resolve_const(i, &opr, i + opcnt * 7, &uval);
3334 if (ret != 1 || uval == 0) {
3335 // can't treat it as full setter because of ecx=0 case,
3336 // also disallow delayed compare
3345 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3352 // scan back for cdq, if anything modifies edx, fail
3353 static int scan_for_cdq_edx(int i)
3356 if (g_labels[i] != NULL) {
3357 if (g_label_refs[i].next != NULL)
3359 if (i > 0 && LAST_OP(i - 1)) {
3360 i = g_label_refs[i].i;
3367 if (ops[i].op == OP_CDQ)
3370 if (ops[i].regmask_dst & (1 << xDX))
3377 static int scan_for_reg_clear(int i, int reg)
3380 if (g_labels[i] != NULL) {
3381 if (g_label_refs[i].next != NULL)
3383 if (i > 0 && LAST_OP(i - 1)) {
3384 i = g_label_refs[i].i;
3391 if (ops[i].op == OP_XOR
3392 && ops[i].operand[0].lmod == OPLM_DWORD
3393 && ops[i].operand[0].reg == ops[i].operand[1].reg
3394 && ops[i].operand[0].reg == reg)
3397 if (ops[i].regmask_dst & (1 << reg))
3404 static void patch_esp_adjust(struct parsed_op *po, int adj)
3406 ferr_assert(po, po->op == OP_ADD);
3407 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3408 ferr_assert(po, po->operand[1].type == OPT_CONST);
3410 // this is a bit of a hack, but deals with use of
3411 // single adj for multiple calls
3412 po->operand[1].val -= adj;
3413 po->flags |= OPF_RMD;
3414 if (po->operand[1].val == 0)
3415 po->flags |= OPF_DONE;
3416 ferr_assert(po, (int)po->operand[1].val >= 0);
3419 // scan for positive, constant esp adjust
3420 // multipath case is preliminary
3421 static int scan_for_esp_adjust(int i, int opcnt,
3422 int adj_expect, int *adj, int *is_multipath, int do_update)
3424 int adj_expect_unknown = 0;
3425 struct parsed_op *po;
3429 *adj = *is_multipath = 0;
3430 if (adj_expect < 0) {
3431 adj_expect_unknown = 1;
3432 adj_expect = 32 * 4; // enough?
3435 for (; i < opcnt && *adj < adj_expect; i++) {
3436 if (g_labels[i] != NULL)
3440 if (po->flags & OPF_DONE)
3443 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3444 if (po->operand[1].type != OPT_CONST)
3445 ferr(&ops[i], "non-const esp adjust?\n");
3446 *adj += po->operand[1].val;
3448 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3451 patch_esp_adjust(po, adj_expect);
3453 po->flags |= OPF_RMD;
3457 else if (po->op == OP_PUSH) {
3458 //if (first_pop == -1)
3459 // first_pop = -2; // none
3460 *adj -= lmod_bytes(po, po->operand[0].lmod);
3462 else if (po->op == OP_POP) {
3463 if (!(po->flags & OPF_DONE)) {
3464 // seems like msvc only uses 'pop ecx' for stack realignment..
3465 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3467 if (first_pop == -1 && *adj >= 0)
3470 if (do_update && *adj >= 0) {
3471 po->flags |= OPF_RMD;
3473 po->flags |= OPF_DONE | OPF_NOREGS;
3476 *adj += lmod_bytes(po, po->operand[0].lmod);
3477 if (*adj > adj_best)
3480 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3481 if (po->op == OP_JMP && po->btj == NULL) {
3487 if (po->op != OP_CALL)
3489 if (po->operand[0].type != OPT_LABEL)
3491 if (po->pp != NULL && po->pp->is_stdcall)
3493 if (adj_expect_unknown && first_pop >= 0)
3495 // assume it's another cdecl call
3499 if (first_pop >= 0) {
3500 // probably only 'pop ecx' was used
3508 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3510 struct parsed_op *po;
3514 ferr(ops, "%s: followed bad branch?\n", __func__);
3516 for (; i < opcnt; i++) {
3518 if (po->cc_scratch == magic)
3520 po->cc_scratch = magic;
3523 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3524 if (po->btj != NULL) {
3526 for (j = 0; j < po->btj->count; j++)
3527 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3531 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3532 if (!(po->flags & OPF_CJMP))
3535 if (po->flags & OPF_TAIL)
3540 static const struct parsed_proto *try_recover_pp(
3541 struct parsed_op *po, const struct parsed_opr *opr,
3542 int is_call, int *search_instead)
3544 const struct parsed_proto *pp = NULL;
3548 if (po->pp != NULL && (po->flags & OPF_DATA)) {
3549 // hint given in asm
3553 // maybe an arg of g_func?
3554 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3556 char ofs_reg[16] = { 0, };
3557 int arg, arg_s, arg_i;
3564 parse_stack_access(po, opr->name, ofs_reg,
3565 &offset, &stack_ra, NULL, 0);
3566 if (ofs_reg[0] != 0)
3567 ferr(po, "offset reg on arg access?\n");
3568 if (offset <= stack_ra) {
3569 // search who set the stack var instead
3570 if (search_instead != NULL)
3571 *search_instead = 1;
3575 arg_i = (offset - stack_ra - 4) / 4;
3576 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3577 if (g_func_pp->arg[arg].reg != NULL)
3583 if (arg == g_func_pp->argc)
3584 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3586 pp = g_func_pp->arg[arg].pp;
3589 ferr(po, "icall arg: arg%d has no pp\n", arg + 1);
3590 check_func_pp(po, pp, "icall arg");
3593 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3595 p = strchr(opr->name + 1, '[');
3596 memcpy(buf, opr->name, p - opr->name);
3597 buf[p - opr->name] = 0;
3598 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3600 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3601 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3604 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3607 check_func_pp(po, pp, "reg-fptr ref");
3613 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3614 int magic, const struct parsed_proto **pp_found, int *pp_i,
3617 const struct parsed_proto *pp = NULL;
3618 struct parsed_op *po;
3619 struct label_ref *lr;
3621 ops[i].cc_scratch = magic;
3624 if (g_labels[i] != NULL) {
3625 lr = &g_label_refs[i];
3626 for (; lr != NULL; lr = lr->next) {
3627 check_i(&ops[i], lr->i);
3628 scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3630 if (i > 0 && LAST_OP(i - 1))
3638 if (ops[i].cc_scratch == magic)
3640 ops[i].cc_scratch = magic;
3642 if (!(ops[i].flags & OPF_DATA))
3644 if (!is_opr_modified(opr, &ops[i]))
3646 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3647 // most probably trashed by some processing
3652 opr = &ops[i].operand[1];
3653 if (opr->type != OPT_REG)
3657 po = (i >= 0) ? &ops[i] : ops;
3660 // reached the top - can only be an arg-reg
3661 if (opr->type != OPT_REG || g_func_pp == NULL)
3664 for (i = 0; i < g_func_pp->argc; i++) {
3665 if (g_func_pp->arg[i].reg == NULL)
3667 if (IS(opr->name, g_func_pp->arg[i].reg))
3670 if (i == g_func_pp->argc)
3672 pp = g_func_pp->arg[i].pp;
3674 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3675 i + 1, g_func_pp->arg[i].reg);
3676 check_func_pp(po, pp, "icall reg-arg");
3679 pp = try_recover_pp(po, opr, 1, NULL);
3681 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3682 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3683 || (*pp_found)->is_stdcall != pp->is_stdcall
3684 //|| (*pp_found)->is_fptr != pp->is_fptr
3685 || (*pp_found)->argc != pp->argc
3686 || (*pp_found)->argc_reg != pp->argc_reg
3687 || (*pp_found)->argc_stack != pp->argc_stack)
3689 ferr(po, "icall: parsed_proto mismatch\n");
3699 static void add_label_ref(struct label_ref *lr, int op_i)
3701 struct label_ref *lr_new;
3708 lr_new = calloc(1, sizeof(*lr_new));
3710 lr_new->next = lr->next;
3714 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3716 struct parsed_op *po = &ops[i];
3717 struct parsed_data *pd;
3718 char label[NAMELEN], *p;
3721 p = strchr(po->operand[0].name, '[');
3725 len = p - po->operand[0].name;
3726 strncpy(label, po->operand[0].name, len);
3729 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3730 if (IS(g_func_pd[j].label, label)) {
3736 //ferr(po, "label '%s' not parsed?\n", label);
3739 if (pd->type != OPT_OFFSET)
3740 ferr(po, "label '%s' with non-offset data?\n", label);
3742 // find all labels, link
3743 for (j = 0; j < pd->count; j++) {
3744 for (l = 0; l < opcnt; l++) {
3745 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3746 add_label_ref(&g_label_refs[l], i);
3756 static void clear_labels(int count)
3760 for (i = 0; i < count; i++) {
3761 if (g_labels[i] != NULL) {
3768 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3773 for (i = 0; i < pp->argc; i++) {
3774 if (pp->arg[i].reg != NULL) {
3775 reg = char_array_i(regs_r32,
3776 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3778 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3779 pp->arg[i].reg, pp->name);
3780 regmask |= 1 << reg;
3787 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3792 if (pp->has_retreg) {
3793 for (i = 0; i < pp->argc; i++) {
3794 if (pp->arg[i].type.is_retreg) {
3795 reg = char_array_i(regs_r32,
3796 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3797 ferr_assert(ops, reg >= 0);
3798 regmask |= 1 << reg;
3803 if (strstr(pp->ret_type.name, "int64"))
3804 return regmask | (1 << xAX) | (1 << xDX);
3805 if (IS(pp->ret_type.name, "float")
3806 || IS(pp->ret_type.name, "double"))
3808 return regmask | mxST0;
3810 if (strcasecmp(pp->ret_type.name, "void") == 0)
3813 return regmask | mxAX;
3816 static int are_ops_same(struct parsed_op *po1, struct parsed_op *po2)
3818 return po1->op == po2->op && po1->operand_cnt == po2->operand_cnt
3819 && memcmp(po1->operand, po2->operand,
3820 sizeof(po1->operand[0]) * po1->operand_cnt) == 0;
3823 static void resolve_branches_parse_calls(int opcnt)
3825 static const struct {
3829 unsigned int regmask_src;
3830 unsigned int regmask_dst;
3832 { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3833 { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3834 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3835 // more precise? Wine gets away with just __ftol handler
3836 { "__ftol2", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3837 { "__CIpow", OPP_CIPOW, OPF_FPOP, mxST0|mxST1, mxST0 },
3839 const struct parsed_proto *pp_c;
3840 struct parsed_proto *pp;
3841 struct parsed_data *pd;
3842 struct parsed_op *po;
3843 const char *tmpname;
3848 for (i = 0; i < opcnt; i++)
3854 if (po->datap != NULL) {
3855 pp = calloc(1, sizeof(*pp));
3856 my_assert_not(pp, NULL);
3858 ret = parse_protostr(po->datap, pp);
3860 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3866 if (po->op == OP_CALL) {
3871 else if (po->operand[0].type == OPT_LABEL)
3873 tmpname = opr_name(po, 0);
3874 if (IS_START(tmpname, "loc_")) {
3876 ferr(po, "call to loc_*\n");
3877 // eliminate_seh() must take care of it
3880 if (IS(tmpname, "__alloca_probe"))
3882 if (IS(tmpname, "__SEH_prolog")) {
3883 ferr_assert(po, g_seh_found == 0);
3887 if (IS(tmpname, "__SEH_epilog"))
3890 // convert some calls to pseudo-ops
3891 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3892 if (!IS(tmpname, pseudo_ops[l].name))
3895 po->op = pseudo_ops[l].op;
3896 po->operand_cnt = 0;
3897 po->regmask_src = pseudo_ops[l].regmask_src;
3898 po->regmask_dst = pseudo_ops[l].regmask_dst;
3899 po->flags = pseudo_ops[l].flags;
3900 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3903 if (l < ARRAY_SIZE(pseudo_ops))
3906 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3907 if (!g_header_mode && pp_c == NULL)
3908 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3911 pp = proto_clone(pp_c);
3912 my_assert_not(pp, NULL);
3918 check_func_pp(po, pp, "fptr var call");
3919 if (pp->is_noreturn) {
3920 po->flags |= OPF_TAIL;
3921 po->flags &= ~OPF_ATAIL; // most likely...
3928 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3931 if (po->operand[0].type == OPT_REGMEM) {
3932 pd = try_resolve_jumptab(i, opcnt);
3940 for (l = 0; l < opcnt; l++) {
3941 if (g_labels[l] != NULL
3942 && IS(po->operand[0].name, g_labels[l]))
3944 if (l == i + 1 && po->op == OP_JMP) {
3945 // yet another alignment type...
3946 po->flags |= OPF_RMD | OPF_DONE;
3947 po->flags &= ~OPF_JMP;
3951 add_label_ref(&g_label_refs[l], i);
3957 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3960 if (po->operand[0].type == OPT_LABEL)
3964 ferr(po, "unhandled branch\n");
3968 po->flags |= OPF_TAIL;
3969 prev_op = i > 0 ? ops[i - 1].op : OP_UD2;
3970 if (prev_op == OP_POP)
3971 po->flags |= OPF_ATAIL;
3972 if (g_stack_fsz + g_bp_frame == 0 && prev_op != OP_PUSH
3973 && (g_func_pp == NULL || g_func_pp->argc_stack > 0))
3975 po->flags |= OPF_ATAIL;
3981 static int resolve_origin(int i, const struct parsed_opr *opr,
3982 int magic, int *op_i, int *is_caller);
3983 static void set_label(int i, const char *name);
3985 static void eliminate_seh_writes(int opcnt)
3987 const struct parsed_opr *opr;
3992 // assume all sf writes above g_seh_size to be seh related
3993 // (probably unsafe but oh well)
3994 for (i = 0; i < opcnt; i++) {
3995 if (ops[i].op != OP_MOV)
3997 opr = &ops[i].operand[0];
3998 if (opr->type != OPT_REGMEM)
4000 if (!is_stack_access(&ops[i], opr))
4004 parse_stack_access(&ops[i], opr->name, ofs_reg, &offset,
4006 if (offset < 0 && offset >= -g_seh_size)
4007 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4011 static void eliminate_seh_finally(int opcnt)
4013 const char *target_name = NULL;
4014 const char *return_name = NULL;
4015 int exits[MAX_EXITS];
4023 for (i = 0; i < opcnt; i++) {
4024 if (ops[i].op != OP_CALL)
4026 if (!IS_START(opr_name(&ops[i], 0), "loc_"))
4028 if (target_name != NULL)
4029 ferr(&ops[i], "multiple finally calls? (last was %s)\n",
4031 target_name = opr_name(&ops[i], 0);
4034 if (g_labels[i + 1] == NULL)
4035 set_label(i + 1, "seh_fin_done");
4036 return_name = g_labels[i + 1];
4044 // find finally code (bt_i is not set because it's call)
4045 for (i = 0; i < opcnt; i++) {
4046 if (g_labels[i] == NULL)
4048 if (!IS(g_labels[i], target_name))
4051 ferr_assert(&ops[i], target_i == -1);
4054 ferr_assert(&ops[0], target_i != -1);
4056 find_reachable_exits(target_i, opcnt, target_i + opcnt * 24,
4057 exits, &exit_count);
4058 ferr_assert(&ops[target_i], exit_count == 1);
4059 ferr_assert(&ops[target_i], ops[exits[0]].op == OP_RET);
4062 // convert to jumps, link
4063 ops[call_i].op = OP_JMP;
4064 ops[call_i].bt_i = target_i;
4065 add_label_ref(&g_label_refs[target_i], call_i);
4067 ops[tgend_i].op = OP_JMP;
4068 ops[tgend_i].flags &= ~OPF_TAIL;
4069 ops[tgend_i].flags |= OPF_JMP;
4070 ops[tgend_i].bt_i = return_i;
4071 ops[tgend_i].operand_cnt = 1;
4072 ops[tgend_i].operand[0].type = OPT_LABEL;
4073 snprintf(ops[tgend_i].operand[0].name, NAMELEN, "%s", return_name);
4074 add_label_ref(&g_label_refs[return_i], tgend_i);
4076 // rm seh finally entry code
4077 for (i = target_i - 1; i >= 0; i--) {
4078 if (g_labels[i] != NULL && g_label_refs[i].i != -1)
4080 if (ops[i].flags & OPF_CJMP)
4082 if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4085 for (i = target_i - 1; i >= 0; i--) {
4086 if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4088 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4092 static void eliminate_seh(int opcnt)
4096 for (i = 0; i < opcnt; i++) {
4097 if (ops[i].op != OP_MOV)
4099 if (ops[i].operand[0].segment != SEG_FS)
4101 if (!IS(opr_name(&ops[i], 0), "0"))
4104 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4105 if (ops[i].operand[1].reg == xSP) {
4106 for (j = i - 1; j >= 0; j--) {
4107 if (ops[j].op != OP_PUSH)
4109 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4111 if (ops[j].operand[0].val == ~0)
4113 if (ops[j].operand[0].type == OPT_REG) {
4115 ret = resolve_origin(j, &ops[j].operand[0],
4116 j + opcnt * 22, &k, NULL);
4118 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4122 ferr(ops, "missing seh terminator\n");
4126 ret = resolve_origin(i, &ops[i].operand[1],
4127 i + opcnt * 23, &k, NULL);
4129 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4133 eliminate_seh_writes(opcnt);
4134 eliminate_seh_finally(opcnt);
4137 static void eliminate_seh_calls(int opcnt)
4139 int epilog_found = 0;
4146 ferr_assert(&ops[i], ops[i].op == OP_PUSH
4147 && ops[i].operand[0].type == OPT_CONST);
4148 g_stack_fsz = g_seh_size + ops[i].operand[0].val;
4149 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4152 ferr_assert(&ops[i], ops[i].op == OP_PUSH
4153 && ops[i].operand[0].type == OPT_OFFSET);
4154 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4157 ferr_assert(&ops[i], ops[i].op == OP_CALL
4158 && IS(opr_name(&ops[i], 0), "__SEH_prolog"));
4159 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4161 for (i++; i < opcnt; i++) {
4162 if (ops[i].op != OP_CALL)
4164 if (!IS(opr_name(&ops[i], 0), "__SEH_epilog"))
4167 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4170 ferr_assert(ops, epilog_found);
4172 eliminate_seh_writes(opcnt);
4173 eliminate_seh_finally(opcnt);
4176 // check for prologue of many pushes and epilogue with pops
4177 static void check_simple_sequence(int opcnt, int *fsz)
4186 for (i = 0; i < opcnt && i < ARRAY_SIZE(seq); i++) {
4187 if (ops[i].op != OP_PUSH || ops[i].operand[0].type != OPT_REG)
4189 reg = ops[i].operand[0].reg;
4190 if (reg != xBX && reg != xSI && reg != xDI && reg != xBP)
4192 for (j = 0; j < i; j++)
4196 // probably something else is going on here
4204 for (; i < opcnt && seq_len > 0; i++) {
4205 if (!(ops[i].flags & OPF_TAIL))
4208 for (j = i - 1, seq_p = 0; j >= 0 && seq_p < seq_len; j--) {
4209 if (ops[j].op != OP_POP || ops[j].operand[0].type != OPT_REG)
4211 if (ops[j].operand[0].reg != seq[seq_p])
4215 found = seq_len = seq_p;
4220 for (i = 0; i < seq_len; i++)
4221 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4223 for (; i < opcnt && seq_len > 0; i++) {
4224 if (!(ops[i].flags & OPF_TAIL))
4227 for (j = i - 1, seq_p = 0; j >= 0 && seq_p < seq_len; j--) {
4228 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4233 // unlike pushes after sub esp,
4234 // IDA treats pushed like this as part of var area
4235 *fsz += seq_len * 4;
4238 static int scan_prologue(int i, int opcnt, int *ecx_push, int *esp_sub)
4243 for (; i < opcnt; i++)
4244 if (!(ops[i].flags & OPF_DONE))
4247 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4248 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4254 for (; i < opcnt; i++) {
4255 if (i > 0 && g_labels[i] != NULL)
4257 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
4259 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
4260 && ops[i].operand[1].type == OPT_CONST)
4262 g_stack_fsz += opr_const(&ops[i], 1);
4263 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4268 if (ops[i].op == OP_LEA && ops[i].operand[0].reg == xSP
4269 && ops[i].operand[1].type == OPT_REGMEM
4270 && IS_START(ops[i].operand[1].name, "esp-"))
4272 name = ops[i].operand[1].name;
4273 ret = sscanf(name, "esp-%x%n", &j, &len);
4274 ferr_assert(&ops[i], ret == 1 && len == strlen(name));
4276 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4281 if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
4282 && ops[i].operand[1].type == OPT_CONST)
4284 for (j = i + 1; j < opcnt; j++)
4285 if (!(ops[j].flags & OPF_DONE))
4287 if (ops[j].op == OP_CALL
4288 && IS(opr_name(&ops[j], 0), "__alloca_probe"))
4290 g_stack_fsz += opr_const(&ops[i], 1);
4291 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4292 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4303 static void scan_prologue_epilogue(int opcnt, int *stack_align)
4305 int ecx_push = 0, esp_sub = 0, pusha = 0;
4306 int sandard_epilogue;
4307 int found, ret, len;
4311 if (g_seh_found == 2) {
4312 eliminate_seh_calls(opcnt);
4316 eliminate_seh(opcnt);
4317 // ida treats seh as part of sf
4318 g_stack_fsz = g_seh_size;
4322 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
4323 && ops[1].op == OP_MOV
4324 && IS(opr_name(&ops[1], 0), "ebp")
4325 && IS(opr_name(&ops[1], 1), "esp"))
4328 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4329 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4331 for (i = 2; i < opcnt; i++)
4332 if (!(ops[i].flags & OPF_DONE))
4335 if (ops[i].op == OP_PUSHA) {
4336 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4341 if (ops[i].op == OP_AND && ops[i].operand[0].reg == xSP
4342 && ops[i].operand[1].type == OPT_CONST)
4344 l = ops[i].operand[1].val;
4346 if (j == -1 || (l >> j) != -1)
4347 ferr(&ops[i], "unhandled esp align: %x\n", l);
4348 if (stack_align != NULL)
4349 *stack_align = 1 << j;
4350 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4354 i = scan_prologue(i, opcnt, &ecx_push, &esp_sub);
4358 for (; i < opcnt; i++)
4359 if (ops[i].flags & OPF_TAIL)
4362 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4363 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4369 sandard_epilogue = 0;
4370 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
4372 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4373 // the standard epilogue is sometimes even used without a sf
4374 if (ops[j - 1].op == OP_MOV
4375 && IS(opr_name(&ops[j - 1], 0), "esp")
4376 && IS(opr_name(&ops[j - 1], 1), "ebp"))
4377 sandard_epilogue = 1;
4379 else if (ops[j].op == OP_LEAVE)
4381 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4382 sandard_epilogue = 1;
4384 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
4385 && ops[i].pp->is_noreturn)
4387 // on noreturn, msvc sometimes cleans stack, sometimes not
4392 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4393 ferr(&ops[j], "'pop ebp' expected\n");
4395 if (g_stack_fsz != 0 || sandard_epilogue) {
4396 if (ops[j].op == OP_LEAVE)
4398 else if (sandard_epilogue) // mov esp, ebp
4400 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4403 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4405 ferr(&ops[j], "esp restore expected\n");
4408 if (ecx_push && j >= 0 && ops[j].op == OP_POP
4409 && IS(opr_name(&ops[j], 0), "ecx"))
4411 ferr(&ops[j], "unexpected ecx pop\n");
4416 if (ops[j].op == OP_POPA)
4417 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4419 ferr(&ops[j], "popa expected\n");
4424 } while (i < opcnt);
4427 ferr(ops, "missing ebp epilogue\n");
4432 check_simple_sequence(opcnt, &push_fsz);
4433 i = scan_prologue(0, opcnt, &ecx_push, &esp_sub);
4435 if (ecx_push && !esp_sub) {
4436 // could actually be args for a call..
4437 for (; i < opcnt; i++)
4438 if (ops[i].op != OP_PUSH)
4441 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
4442 const struct parsed_proto *pp;
4443 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
4444 j = pp ? pp->argc_stack : 0;
4445 while (i > 0 && j > 0) {
4447 if (ops[i].op == OP_PUSH) {
4448 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
4453 ferr(&ops[i], "unhandled prologue\n");
4457 g_stack_fsz = g_seh_size;
4458 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4459 if (!(ops[i].flags & OPF_RMD))
4469 if (ecx_push || esp_sub)
4474 for (; i < opcnt; i++)
4475 if (ops[i].flags & OPF_TAIL)
4479 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4480 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4485 else if (i < opcnt && (ops[i].flags & OPF_ATAIL)) {
4486 // skip arg updates for arg-reuse tailcall
4487 for (; j >= 0; j--) {
4488 if (ops[j].op != OP_MOV)
4490 if (ops[j].operand[0].type != OPT_REGMEM)
4492 if (strstr(ops[j].operand[0].name, "arg_") == NULL)
4497 for (; j >= 0; j--) {
4498 if ((ops[j].flags & (OPF_RMD | OPF_DONE | OPF_NOREGS)) !=
4499 (OPF_RMD | OPF_DONE | OPF_NOREGS))
4503 if (ecx_push > 0 && !esp_sub) {
4504 for (l = 0; l < ecx_push && j >= 0; l++) {
4505 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
4507 else if (ops[j].op == OP_ADD
4508 && IS(opr_name(&ops[j], 0), "esp")
4509 && ops[j].operand[1].type == OPT_CONST)
4512 l += ops[j].operand[1].val / 4 - 1;
4517 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4520 if (l != ecx_push) {
4521 if (i < opcnt && ops[i].op == OP_CALL
4522 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4524 // noreturn tailcall with no epilogue
4529 ferr(&ops[j], "epilogue scan failed\n");
4536 if (ops[j].op == OP_ADD
4537 && IS(opr_name(&ops[j], 0), "esp")
4538 && ops[j].operand[1].type == OPT_CONST)
4540 if (ops[j].operand[1].val < g_stack_fsz)
4541 ferr(&ops[j], "esp adj is too low (need %d)\n", g_stack_fsz);
4543 ops[j].operand[1].val -= g_stack_fsz; // for stack arg scanner
4544 if (ops[j].operand[1].val == 0)
4545 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4548 else if (ops[j].op == OP_LEA && ops[j].operand[0].reg == xSP
4549 && ops[j].operand[1].type == OPT_REGMEM
4550 && IS_START(ops[j].operand[1].name, "esp+"))
4552 const char *name = ops[j].operand[1].name;
4553 ret = sscanf(name, "esp+%x%n", &l, &len);
4554 ferr_assert(&ops[j], ret == 1 && len == strlen(name));
4555 ferr_assert(&ops[j], l <= g_stack_fsz);
4556 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4559 else if (i < opcnt && ops[i].op == OP_CALL
4560 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4562 // noreturn tailcall with no epilogue
4566 ferr(&ops[j], "'add esp' expected\n");
4570 } while (i < opcnt);
4573 ferr(ops, "missing esp epilogue\n");
4576 if (g_stack_fsz != 0)
4577 // see check_simple_sequence
4578 g_stack_fsz += push_fsz;
4581 // find an instruction that changed opr before i op
4582 // *op_i must be set to -1 by the caller
4583 // *is_caller is set to 1 if one source is determined to be g_func arg
4584 // returns 1 if found, *op_i is then set to origin
4585 // returns -1 if multiple origins are found
4586 static int resolve_origin(int i, const struct parsed_opr *opr,
4587 int magic, int *op_i, int *is_caller)
4589 struct label_ref *lr;
4593 if (g_labels[i] != NULL) {
4594 lr = &g_label_refs[i];
4595 for (; lr != NULL; lr = lr->next) {
4596 check_i(&ops[i], lr->i);
4597 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4599 if (i > 0 && LAST_OP(i - 1))
4605 if (is_caller != NULL)
4610 if (ops[i].cc_scratch == magic)
4612 ops[i].cc_scratch = magic;
4614 if (!(ops[i].flags & OPF_DATA))
4616 if (!is_opr_modified(opr, &ops[i]))
4620 if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4631 // find an instruction that previously referenced opr
4632 // if multiple results are found - fail
4633 // *op_i must be set to -1 by the caller
4634 // returns 1 if found, *op_i is then set to referencer insn
4635 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4636 int magic, int *op_i)
4638 struct label_ref *lr;
4642 if (g_labels[i] != NULL) {
4643 lr = &g_label_refs[i];
4644 for (; lr != NULL; lr = lr->next) {
4645 check_i(&ops[i], lr->i);
4646 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4648 if (i > 0 && LAST_OP(i - 1))
4656 if (ops[i].cc_scratch == magic)
4658 ops[i].cc_scratch = magic;
4660 if (!is_opr_referenced(opr, &ops[i]))
4671 // adjust datap of all reachable 'op' insns when moving back
4672 // returns 1 if at least 1 op was found
4673 // returns -1 if path without an op was found
4674 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4676 struct label_ref *lr;
4679 if (ops[i].cc_scratch == magic)
4681 ops[i].cc_scratch = magic;
4684 if (g_labels[i] != NULL) {
4685 lr = &g_label_refs[i];
4686 for (; lr != NULL; lr = lr->next) {
4687 check_i(&ops[i], lr->i);
4688 ret |= adjust_prev_op(lr->i, op, magic, datap);
4690 if (i > 0 && LAST_OP(i - 1))
4698 if (ops[i].cc_scratch == magic)
4700 ops[i].cc_scratch = magic;
4702 if (ops[i].op != op)
4705 ops[i].datap = datap;
4710 // find next instruction that reads opr
4711 // *op_i must be set to -1 by the caller
4712 // on return, *op_i is set to first referencer insn
4713 // returns 1 if exactly 1 referencer is found
4714 static int find_next_read(int i, int opcnt,
4715 const struct parsed_opr *opr, int magic, int *op_i)
4717 struct parsed_op *po;
4720 for (; i < opcnt; i++)
4722 if (ops[i].cc_scratch == magic)
4724 ops[i].cc_scratch = magic;
4727 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4728 if (po->btj != NULL) {
4730 for (j = 0; j < po->btj->count; j++) {
4731 check_i(po, po->btj->d[j].bt_i);
4732 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4738 if (po->flags & OPF_RMD)
4740 check_i(po, po->bt_i);
4741 if (po->flags & OPF_CJMP) {
4742 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4751 if (!is_opr_read(opr, po)) {
4753 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4754 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4756 full_opr = po->operand[0].lmod >= opr->lmod;
4758 if (is_opr_modified(opr, po) && full_opr) {
4762 if (po->flags & OPF_TAIL)
4777 static int find_next_read_reg(int i, int opcnt, int reg,
4778 enum opr_lenmod lmod, int magic, int *op_i)
4780 struct parsed_opr opr = OPR_INIT(OPT_REG, lmod, reg);
4783 return find_next_read(i, opcnt, &opr, magic, op_i);
4786 // find next instruction that reads opr
4787 // *op_i must be set to -1 by the caller
4788 // on return, *op_i is set to first flag user insn
4789 // returns 1 if exactly 1 flag user is found
4790 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4792 struct parsed_op *po;
4795 for (; i < opcnt; i++)
4797 if (ops[i].cc_scratch == magic)
4799 ops[i].cc_scratch = magic;
4802 if (po->op == OP_CALL)
4804 if (po->flags & OPF_JMP) {
4805 if (po->btj != NULL) {
4807 for (j = 0; j < po->btj->count; j++) {
4808 check_i(po, po->btj->d[j].bt_i);
4809 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4815 if (po->flags & OPF_RMD)
4817 check_i(po, po->bt_i);
4818 if (po->flags & OPF_CJMP)
4825 if (!(po->flags & OPF_CC)) {
4826 if (po->flags & OPF_FLAGS)
4829 if (po->flags & OPF_TAIL)
4845 static int try_resolve_const(int i, const struct parsed_opr *opr,
4846 int magic, unsigned int *val)
4851 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4854 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4857 *val = ops[i].operand[1].val;
4864 static int resolve_used_bits(int i, int opcnt, int reg,
4865 int *mask, int *is_z_check)
4867 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4871 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4875 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4877 fnote(&ops[j], "(first read)\n");
4878 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4881 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4882 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4884 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4885 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4887 *mask = ops[j].operand[1].val;
4888 if (ops[j].operand[0].lmod == OPLM_BYTE
4889 && ops[j].operand[0].name[1] == 'h')
4893 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4896 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4898 *is_z_check = ops[k].pfo == PFO_Z;
4903 static const struct parsed_proto *resolve_deref(int i, int magic,
4904 struct parsed_opr *opr, int level)
4906 struct parsed_opr opr_s = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
4907 const struct parsed_proto *pp = NULL;
4908 int from_caller = 0;
4917 ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4918 if (ret != 2 || len != strlen(opr->name)) {
4919 ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4920 if (ret != 1 || len != strlen(opr->name))
4924 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4929 ret = resolve_origin(i, &opr_s, i + magic, &j, NULL);
4933 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4934 && strlen(ops[j].operand[1].name) == 3
4935 && ops[j].operand[0].lmod == OPLM_DWORD
4936 && ops[j].pp == NULL // no hint
4939 // allow one simple dereference (com/directx)
4940 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4941 ops[j].operand[1].name);
4945 ret = resolve_origin(j, &opr_s, j + magic, &k, NULL);
4950 if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
4953 if (ops[j].pp != NULL) {
4957 else if (ops[j].operand[1].type == OPT_REGMEM) {
4958 pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
4960 // maybe structure ptr in structure
4961 pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
4964 else if (ops[j].operand[1].type == OPT_LABEL)
4965 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4966 else if (ops[j].operand[1].type == OPT_REG) {
4969 ret = resolve_origin(j, &ops[j].operand[1], i + magic,
4971 if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
4972 for (k = 0; k < g_func_pp->argc; k++) {
4973 if (g_func_pp->arg[k].reg == NULL)
4975 if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
4976 pp = g_func_pp->arg[k].pp;
4985 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4987 ferr(&ops[j], "expected struct, got '%s %s'\n",
4988 pp->type.name, pp->name);
4992 return proto_lookup_struct(g_fhdr, pp->type.name, offset);
4995 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4996 int *pp_i, int *multi_src)
4998 const struct parsed_proto *pp = NULL;
4999 int search_advice = 0;
5004 switch (ops[i].operand[0].type) {
5006 // try to resolve struct member calls
5007 pp = resolve_deref(i, i + opcnt * 19, &ops[i].operand[0], 0);
5013 pp = try_recover_pp(&ops[i], &ops[i].operand[0],
5019 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
5027 static struct parsed_proto *process_call_early(int i, int opcnt,
5030 struct parsed_op *po = &ops[i];
5031 struct parsed_proto *pp;
5037 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
5041 // look for and make use of esp adjust
5043 if (!pp->is_stdcall && pp->argc_stack > 0)
5044 ret = scan_for_esp_adjust(i + 1, opcnt,
5045 pp->argc_stack * 4, &adj, &multipath, 0);
5047 if (pp->argc_stack > adj / 4)
5051 if (ops[ret].op == OP_POP) {
5052 for (j = 1; j < adj / 4; j++) {
5053 if (ops[ret + j].op != OP_POP
5054 || ops[ret + j].operand[0].reg != xCX)
5066 static struct parsed_proto *process_call(int i, int opcnt)
5068 struct parsed_op *po = &ops[i];
5069 const struct parsed_proto *pp_c;
5070 struct parsed_proto *pp;
5071 const char *tmpname;
5072 int call_i = -1, ref_i = -1;
5073 int adj = 0, multipath = 0;
5076 tmpname = opr_name(po, 0);
5081 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
5083 if (!pp_c->is_func && !pp_c->is_fptr)
5084 ferr(po, "call to non-func: %s\n", pp_c->name);
5085 pp = proto_clone(pp_c);
5086 my_assert_not(pp, NULL);
5088 // not resolved just to single func
5091 switch (po->operand[0].type) {
5093 // we resolved this call and no longer need the register
5094 po->regmask_src &= ~(1 << po->operand[0].reg);
5096 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
5097 && ops[call_i].operand[1].type == OPT_LABEL)
5099 // no other source users?
5100 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
5102 if (ret == 1 && call_i == ref_i) {
5103 // and nothing uses it after us?
5105 find_next_read(i + 1, opcnt, &po->operand[0],
5106 i + opcnt * 11, &ref_i);
5108 // then also don't need the source mov
5109 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
5121 pp = calloc(1, sizeof(*pp));
5122 my_assert_not(pp, NULL);
5125 ret = scan_for_esp_adjust(i + 1, opcnt,
5126 -1, &adj, &multipath, 0);
5127 if (ret < 0 || adj < 0) {
5128 if (!g_allow_regfunc)
5129 ferr(po, "non-__cdecl indirect call unhandled yet\n");
5130 pp->is_unresolved = 1;
5134 if (adj > ARRAY_SIZE(pp->arg))
5135 ferr(po, "esp adjust too large: %d\n", adj);
5136 pp->ret_type.name = strdup("int");
5137 pp->argc = pp->argc_stack = adj;
5138 for (arg = 0; arg < pp->argc; arg++)
5139 pp->arg[arg].type.name = strdup("int");
5144 // look for and make use of esp adjust
5147 if (!pp->is_stdcall && pp->argc_stack > 0) {
5148 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
5149 ret = scan_for_esp_adjust(i + 1, opcnt,
5150 adj_expect, &adj, &multipath, 0);
5153 if (pp->is_vararg) {
5154 if (adj / 4 < pp->argc_stack) {
5155 fnote(po, "(this call)\n");
5156 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
5157 adj, pp->argc_stack * 4);
5159 // modify pp to make it have varargs as normal args
5161 pp->argc += adj / 4 - pp->argc_stack;
5162 for (; arg < pp->argc; arg++) {
5163 pp->arg[arg].type.name = strdup("int");
5166 if (pp->argc > ARRAY_SIZE(pp->arg))
5167 ferr(po, "too many args for '%s'\n", tmpname);
5169 if (pp->argc_stack > adj / 4) {
5170 if (pp->is_noreturn)
5171 // assume no stack adjust was emited
5173 fnote(po, "(this call)\n");
5174 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
5175 tmpname, pp->argc_stack * 4, adj);
5178 scan_for_esp_adjust(i + 1, opcnt,
5179 pp->argc_stack * 4, &adj, &multipath, 1);
5181 else if (pp->is_vararg)
5182 ferr(po, "missing esp_adjust for vararg func '%s'\n",
5189 static void mark_float_arg(struct parsed_op *po,
5190 struct parsed_proto *pp, int arg, int *regmask_ffca)
5193 po->p_argnum = arg + 1;
5194 ferr_assert(po, pp->arg[arg].datap == NULL);
5195 pp->arg[arg].datap = po;
5196 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
5197 if (regmask_ffca != NULL)
5198 *regmask_ffca |= 1 << arg;
5201 static int check_for_stp(int i, int i_to)
5203 struct parsed_op *po;
5205 for (; i < i_to; i++) {
5207 if (po->op == OP_FST)
5209 if (g_labels[i] != NULL || (po->flags & OPF_JMP))
5211 if (po->op == OP_CALL || po->op == OP_PUSH || po->op == OP_POP)
5213 if (po->op == OP_ADD && po->operand[0].reg == xSP)
5220 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
5223 struct parsed_op *po;
5229 for (base_arg = 0; base_arg < pp->argc; base_arg++)
5230 if (pp->arg[base_arg].reg == NULL)
5233 for (j = i; j > 0; )
5235 ferr_assert(&ops[j], g_labels[j] == NULL);
5239 ferr_assert(po, po->op != OP_PUSH);
5240 if (po->op == OP_FST)
5242 if (po->operand[0].type != OPT_REGMEM)
5244 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
5247 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3)) {
5248 //ferr(po, "offset %d, %d args\n", offset, pp->argc_stack);
5252 arg = base_arg + offset / 4;
5253 mark_float_arg(po, pp, arg, regmask_ffca);
5255 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5256 && po->operand[1].type == OPT_CONST)
5258 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5263 for (arg = base_arg; arg < pp->argc; arg++) {
5264 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
5265 po = pp->arg[arg].datap;
5267 ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
5268 if (po->operand[0].lmod == OPLM_QWORD)
5275 static int collect_call_args_early(int i, struct parsed_proto *pp,
5276 int *regmask, int *regmask_ffca)
5278 struct parsed_op *po;
5283 for (arg = 0; arg < pp->argc; arg++)
5284 if (pp->arg[arg].reg == NULL)
5287 // first see if it can be easily done
5288 for (j = i; j > 0 && arg < pp->argc; )
5290 if (g_labels[j] != NULL)
5295 if (po->op == OP_CALL)
5297 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
5299 else if (po->op == OP_POP)
5301 else if (po->flags & OPF_CJMP)
5303 else if (po->op == OP_PUSH) {
5304 if (po->flags & (OPF_FARG|OPF_FARGNR))
5306 if (!g_header_mode) {
5307 ret = scan_for_mod(po, j + 1, i, 1);
5312 if (pp->arg[arg].type.is_va_list)
5316 for (arg++; arg < pp->argc; arg++)
5317 if (pp->arg[arg].reg == NULL)
5320 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5321 && po->operand[1].type == OPT_CONST)
5323 if (po->flags & (OPF_RMD|OPF_DONE))
5325 if (po->operand[1].val != pp->argc_stack * 4)
5326 ferr(po, "unexpected esp adjust: %d\n",
5327 po->operand[1].val * 4);
5328 ferr_assert(po, pp->argc - arg == pp->argc_stack);
5329 return collect_call_args_no_push(i, pp, regmask_ffca);
5337 for (arg = 0; arg < pp->argc; arg++)
5338 if (pp->arg[arg].reg == NULL)
5341 for (j = i; j > 0 && arg < pp->argc; )
5345 if (ops[j].op == OP_PUSH)
5347 ops[j].p_argnext = -1;
5348 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
5350 k = check_for_stp(j + 1, i);
5352 // push ecx; fstp dword ptr [esp]
5353 ret = parse_stack_esp_offset(&ops[k],
5354 ops[k].operand[0].name, &offset);
5355 if (ret == 0 && offset == 0) {
5356 if (!pp->arg[arg].type.is_float)
5357 ferr(&ops[i], "arg %d should be float\n", arg + 1);
5358 mark_float_arg(&ops[k], pp, arg, regmask_ffca);
5362 if (pp->arg[arg].datap == NULL) {
5363 pp->arg[arg].datap = &ops[j];
5364 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
5365 *regmask |= 1 << ops[j].operand[0].reg;
5368 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5369 ops[j].flags &= ~OPF_RSAVE;
5372 for (arg++; arg < pp->argc; arg++)
5373 if (pp->arg[arg].reg == NULL)
5381 static int sync_argnum(struct parsed_op *po, int argnum)
5383 struct parsed_op *po_tmp;
5385 // see if other branches don't have higher argnum
5386 for (po_tmp = po; po_tmp != NULL; ) {
5387 if (argnum < po_tmp->p_argnum)
5388 argnum = po_tmp->p_argnum;
5389 // note: p_argnext is active on current collect_call_args only
5390 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5393 // make all argnums consistent
5394 for (po_tmp = po; po_tmp != NULL; ) {
5395 if (po_tmp->p_argnum != 0)
5396 po_tmp->p_argnum = argnum;
5397 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5403 static int collect_call_args_r(struct parsed_op *po, int i,
5404 struct parsed_proto *pp, int *regmask, int *arg_grp,
5405 int arg, int argnum, int magic, int need_op_saving, int may_reuse)
5407 struct parsed_proto *pp_tmp;
5408 struct parsed_op *po_tmp;
5409 struct label_ref *lr;
5410 int need_to_save_current;
5411 int arg_grp_current = 0;
5412 int save_args_seen = 0;
5419 ferr(po, "dead label encountered\n");
5423 for (; arg < pp->argc; arg++, argnum++)
5424 if (pp->arg[arg].reg == NULL)
5426 magic = (magic & 0xffffff) | (arg << 24);
5428 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
5430 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
5431 if (ops[j].cc_scratch != magic) {
5432 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
5436 // ok: have already been here
5439 ops[j].cc_scratch = magic;
5441 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
5442 lr = &g_label_refs[j];
5443 if (lr->next != NULL)
5445 for (; lr->next; lr = lr->next) {
5446 check_i(&ops[j], lr->i);
5447 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5449 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5450 arg, argnum, magic, need_op_saving, may_reuse);
5455 check_i(&ops[j], lr->i);
5456 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5458 if (j > 0 && LAST_OP(j - 1)) {
5459 // follow last branch in reverse
5464 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5465 arg, argnum, magic, need_op_saving, may_reuse);
5471 if (ops[j].op == OP_CALL)
5473 if (pp->is_unresolved)
5478 ferr(po, "arg collect %d/%d hit unparsed call '%s'\n",
5479 arg, pp->argc, ops[j].operand[0].name);
5480 if (may_reuse && pp_tmp->argc_stack > 0)
5481 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
5482 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
5484 // esp adjust of 0 means we collected it before
5485 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
5486 && (ops[j].operand[1].type != OPT_CONST
5487 || ops[j].operand[1].val != 0))
5489 if (pp->is_unresolved)
5492 fnote(po, "(this call)\n");
5493 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
5494 arg, pp->argc, ops[j].operand[1].val);
5496 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
5498 if (pp->is_unresolved)
5501 fnote(po, "(this call)\n");
5502 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
5504 else if (ops[j].flags & OPF_CJMP)
5506 if (pp->is_unresolved)
5511 else if (ops[j].op == OP_PUSH
5512 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
5514 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
5517 ops[j].p_argnext = -1;
5518 po_tmp = pp->arg[arg].datap;
5520 ops[j].p_argnext = po_tmp - ops;
5521 pp->arg[arg].datap = &ops[j];
5523 argnum = sync_argnum(&ops[j], argnum);
5525 need_to_save_current = 0;
5527 if (ops[j].operand[0].type == OPT_REG)
5528 reg = ops[j].operand[0].reg;
5530 if (!need_op_saving) {
5531 ret = scan_for_mod(&ops[j], j + 1, i, 1);
5532 need_to_save_current = (ret >= 0);
5534 if (need_op_saving || need_to_save_current) {
5535 // mark this arg as one that needs operand saving
5536 pp->arg[arg].is_saved = 1;
5538 if (save_args_seen & (1 << (argnum - 1))) {
5541 if (arg_grp_current >= MAX_ARG_GRP)
5542 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
5546 else if (ops[j].p_argnum == 0)
5547 ops[j].flags |= OPF_RMD;
5549 // some PUSHes are reused by different calls on other branches,
5550 // but that can't happen if we didn't branch, so they
5551 // can be removed from future searches (handles nested calls)
5553 ops[j].flags |= OPF_FARGNR;
5555 ops[j].flags |= OPF_FARG;
5556 ops[j].flags &= ~OPF_RSAVE;
5558 // check for __VALIST
5559 if (!pp->is_unresolved && g_func_pp != NULL
5560 && pp->arg[arg].type.is_va_list)
5563 ret = resolve_origin(j, &ops[j].operand[0],
5564 magic + 1, &k, NULL);
5565 if (ret == 1 && k >= 0)
5567 if (ops[k].op == OP_LEA) {
5568 if (!g_func_pp->is_vararg)
5569 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
5572 snprintf(buf, sizeof(buf), "arg_%X",
5573 g_func_pp->argc_stack * 4);
5574 if (strstr(ops[k].operand[1].name, buf)
5575 || strstr(ops[k].operand[1].name, "arglist"))
5577 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
5578 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
5579 pp->arg[arg].is_saved = 0;
5583 ferr(&ops[k], "va_list arg detection failed\n");
5585 // check for va_list from g_func_pp arg too
5586 else if (ops[k].op == OP_MOV
5587 && is_stack_access(&ops[k], &ops[k].operand[1]))
5589 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5590 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5592 ops[k].flags |= OPF_RMD | OPF_DONE;
5593 ops[j].flags |= OPF_RMD;
5594 ops[j].p_argpass = ret + 1;
5595 pp->arg[arg].is_saved = 0;
5602 if (pp->arg[arg].is_saved) {
5603 ops[j].flags &= ~OPF_RMD;
5604 ops[j].p_argnum = argnum;
5607 // tracking reg usage
5609 *regmask |= 1 << reg;
5613 if (!pp->is_unresolved) {
5615 for (; arg < pp->argc; arg++, argnum++)
5616 if (pp->arg[arg].reg == NULL)
5619 magic = (magic & 0xffffff) | (arg << 24);
5622 if (ops[j].p_arggrp > arg_grp_current) {
5624 arg_grp_current = ops[j].p_arggrp;
5626 if (ops[j].p_argnum > 0)
5627 save_args_seen |= 1 << (ops[j].p_argnum - 1);
5630 if (arg < pp->argc) {
5631 ferr(po, "arg collect failed for '%s': %d/%d\n",
5632 pp->name, arg, pp->argc);
5636 if (arg_grp_current > *arg_grp)
5637 *arg_grp = arg_grp_current;
5642 static int collect_call_args(struct parsed_op *po, int i,
5643 struct parsed_proto *pp, int *regmask, int magic)
5645 // arg group is for cases when pushes for
5646 // multiple funcs are going on
5647 struct parsed_op *po_tmp;
5652 ret = collect_call_args_r(po, i, pp, regmask, &arg_grp,
5658 // propagate arg_grp
5659 for (a = 0; a < pp->argc; a++) {
5660 if (pp->arg[a].reg != NULL)
5663 po_tmp = pp->arg[a].datap;
5664 while (po_tmp != NULL) {
5665 po_tmp->p_arggrp = arg_grp;
5666 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5671 if (pp->is_unresolved) {
5673 pp->argc_stack += ret;
5674 for (a = 0; a < pp->argc; a++)
5675 if (pp->arg[a].type.name == NULL)
5676 pp->arg[a].type.name = strdup("int");
5682 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5683 int regmask_now, int *regmask,
5684 int regmask_save_now, int *regmask_save,
5685 int *regmask_init, int regmask_arg)
5687 struct parsed_op *po;
5695 for (; i < opcnt; i++)
5698 if (cbits[i >> 3] & (1 << (i & 7)))
5700 cbits[i >> 3] |= (1 << (i & 7));
5702 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5703 if (po->flags & (OPF_RMD|OPF_DONE))
5705 if (po->btj != NULL) {
5706 for (j = 0; j < po->btj->count; j++) {
5707 check_i(po, po->btj->d[j].bt_i);
5708 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5709 regmask_now, regmask, regmask_save_now, regmask_save,
5710 regmask_init, regmask_arg);
5715 check_i(po, po->bt_i);
5716 if (po->flags & OPF_CJMP)
5717 reg_use_pass(po->bt_i, opcnt, cbits,
5718 regmask_now, regmask, regmask_save_now, regmask_save,
5719 regmask_init, regmask_arg);
5725 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5726 && !g_func_pp->is_userstack
5727 && po->operand[0].type == OPT_REG)
5729 reg = po->operand[0].reg;
5730 ferr_assert(po, reg >= 0);
5733 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5734 if (regmask_now & (1 << reg)) {
5735 already_saved = regmask_save_now & (1 << reg);
5736 flags_set = OPF_RSAVE | OPF_DONE;
5739 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, 0);
5741 scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5742 reg, 0, 0, flags_set);
5745 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5747 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5752 ferr_assert(po, !already_saved);
5753 po->flags |= flags_set;
5755 if (regmask_now & (1 << reg)) {
5756 regmask_save_now |= (1 << reg);
5757 *regmask_save |= regmask_save_now;
5762 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5763 reg = po->operand[0].reg;
5764 ferr_assert(po, reg >= 0);
5766 if (regmask_save_now & (1 << reg))
5767 regmask_save_now &= ~(1 << reg);
5769 regmask_now &= ~(1 << reg);
5772 else if (po->op == OP_CALL) {
5773 if ((po->regmask_dst & (1 << xAX))
5774 && !(po->regmask_dst & (1 << xDX)))
5776 if (po->flags & OPF_TAIL)
5777 // don't need eax, will do "return f();" or "f(); return;"
5778 po->regmask_dst &= ~(1 << xAX);
5780 find_next_read_reg(i + 1, opcnt, xAX, OPLM_DWORD,
5781 i + opcnt * 17, &j);
5784 po->regmask_dst &= ~(1 << xAX);
5788 // not "full stack" mode and have something in stack
5789 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5790 ferr(po, "float stack is not empty on func call\n");
5793 if (po->flags & OPF_NOREGS)
5796 // if incomplete register is used, clear it on init to avoid
5797 // later use of uninitialized upper part in some situations
5798 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5799 && po->operand[0].lmod != OPLM_DWORD)
5801 reg = po->operand[0].reg;
5802 ferr_assert(po, reg >= 0);
5804 if (!(regmask_now & (1 << reg)))
5805 *regmask_init |= 1 << reg;
5808 regmask_op = po->regmask_src | po->regmask_dst;
5810 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5811 regmask_new &= ~(1 << xSP);
5812 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5813 regmask_new &= ~(1 << xBP);
5815 if (regmask_new != 0)
5816 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5818 if (regmask_op & (1 << xBP)) {
5819 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5820 if (po->regmask_dst & (1 << xBP))
5821 // compiler decided to drop bp frame and use ebp as scratch
5822 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5824 regmask_op &= ~(1 << xBP);
5828 if (po->flags & OPF_FPUSH) {
5829 if (regmask_now & mxST1)
5830 regmask_now |= mxSTa; // switch to "full stack" mode
5831 if (regmask_now & mxSTa)
5832 po->flags |= OPF_FSHIFT;
5833 if (!(regmask_now & mxST7_2)) {
5835 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5839 regmask_now |= regmask_op;
5840 *regmask |= regmask_now;
5843 if (po->flags & OPF_FPOPP) {
5844 if ((regmask_now & mxSTa) == 0)
5845 ferr(po, "float pop on empty stack?\n");
5846 if (regmask_now & mxST7_2)
5847 po->flags |= OPF_FSHIFT;
5848 if (!(regmask_now & mxST7_2))
5849 regmask_now &= ~mxST1_0;
5851 else if (po->flags & OPF_FPOP) {
5852 if ((regmask_now & mxSTa) == 0)
5853 ferr(po, "float pop on empty stack?\n");
5854 if (regmask_now & (mxST7_2 | mxST1))
5855 po->flags |= OPF_FSHIFT;
5856 if (!(regmask_now & mxST7_2)) {
5858 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5862 if (po->flags & OPF_TAIL) {
5863 if (!(regmask_now & mxST7_2)) {
5864 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5865 if (!(regmask_now & mxST0))
5866 ferr(po, "no st0 on float return, mask: %x\n",
5869 else if (regmask_now & mxST1_0)
5870 ferr(po, "float regs on tail: %x\n", regmask_now);
5873 // there is support for "conditional tailcall", sort of
5874 if (!(po->flags & OPF_CC))
5880 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5884 for (i = 0; i < pp->argc; i++)
5885 if (pp->arg[i].reg == NULL)
5889 memmove(&pp->arg[i + 1], &pp->arg[i],
5890 sizeof(pp->arg[0]) * pp->argc_stack);
5891 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5892 pp->arg[i].reg = strdup(reg);
5893 pp->arg[i].type.name = strdup("int");
5898 static void output_std_flag_z(FILE *fout, struct parsed_op *po,
5899 int *pfomask, const char *dst_opr_text)
5901 if (*pfomask & (1 << PFO_Z)) {
5902 fprintf(fout, "\n cond_z = (%s%s == 0);",
5903 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5904 *pfomask &= ~(1 << PFO_Z);
5908 static void output_std_flag_s(FILE *fout, struct parsed_op *po,
5909 int *pfomask, const char *dst_opr_text)
5911 if (*pfomask & (1 << PFO_S)) {
5912 fprintf(fout, "\n cond_s = (%s%s < 0);",
5913 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5914 *pfomask &= ~(1 << PFO_S);
5918 static void output_std_flags(FILE *fout, struct parsed_op *po,
5919 int *pfomask, const char *dst_opr_text)
5921 output_std_flag_z(fout, po, pfomask, dst_opr_text);
5922 output_std_flag_s(fout, po, pfomask, dst_opr_text);
5926 OPP_FORCE_NORETURN = (1 << 0),
5927 OPP_SIMPLE_ARGS = (1 << 1),
5928 OPP_ALIGN = (1 << 2),
5931 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
5934 const char *cconv = "";
5936 if (pp->is_fastcall)
5937 cconv = "__fastcall ";
5938 else if (pp->is_stdcall && pp->argc_reg == 0)
5939 cconv = "__stdcall ";
5941 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5943 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
5944 fprintf(fout, "noreturn ");
5947 static void output_pp(FILE *fout, const struct parsed_proto *pp,
5952 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5956 output_pp_attrs(fout, pp, flags);
5959 fprintf(fout, "%s", pp->name);
5964 for (i = 0; i < pp->argc; i++) {
5966 fprintf(fout, ", ");
5967 if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
5968 && !(flags & OPP_SIMPLE_ARGS))
5971 output_pp(fout, pp->arg[i].pp, 0);
5973 else if (pp->arg[i].type.is_retreg) {
5974 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
5977 fprintf(fout, "%s", pp->arg[i].type.name);
5979 fprintf(fout, " a%d", i + 1);
5982 if (pp->arg[i].type.is_64bit)
5985 if (pp->is_vararg) {
5987 fprintf(fout, ", ");
5988 fprintf(fout, "...");
5993 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
5999 snprintf(buf1, sizeof(buf1), "%d", grp);
6000 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
6005 static void gen_x_cleanup(int opcnt);
6007 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
6009 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
6010 struct parsed_opr *last_arith_dst = NULL;
6011 char buf1[256], buf2[256], buf3[256], cast[64];
6012 struct parsed_proto *pp, *pp_tmp;
6013 struct parsed_data *pd;
6014 int save_arg_vars[MAX_ARG_GRP] = { 0, };
6015 unsigned char cbits[MAX_OPS / 8];
6016 const char *float_type;
6017 const char *float_st0;
6018 const char *float_st1;
6019 int need_float_stack = 0;
6020 int need_float_sw = 0; // status word
6021 int need_tmp_var = 0;
6025 int label_pending = 0;
6026 int need_double = 0;
6027 int stack_align = 0;
6028 int stack_fsz_adj = 0;
6029 int lock_handled = 0;
6030 int regmask_save = 0; // used regs saved/restored in this func
6031 int regmask_arg; // regs from this function args (fastcall, etc)
6032 int regmask_ret; // regs needed on ret
6033 int regmask_now; // temp
6034 int regmask_init = 0; // regs that need zero initialization
6035 int regmask_pp = 0; // regs used in complex push-pop graph
6036 int regmask_ffca = 0; // float function call args
6037 int regmask = 0; // used regs
6047 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
6048 g_stack_frame_used = 0;
6050 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
6051 regmask_init = g_regmask_init;
6053 g_func_pp = proto_parse(fhdr, funcn, 0);
6054 if (g_func_pp == NULL)
6055 ferr(ops, "proto_parse failed for '%s'\n", funcn);
6057 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
6058 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
6061 // - resolve all branches
6062 // - parse calls with labels
6063 resolve_branches_parse_calls(opcnt);
6066 // - handle ebp/esp frame, remove ops related to it
6067 scan_prologue_epilogue(opcnt, &stack_align);
6069 // handle a case where sf size is unalignment, but is
6070 // placed in a way that elements are still aligned
6071 if (g_stack_fsz & 4) {
6072 for (i = 0; i < g_eqcnt; i++) {
6073 if (g_eqs[i].lmod != OPLM_QWORD)
6075 if (!(g_eqs[i].offset & 4)) {
6084 // - remove dead labels
6085 // - set regs needed at ret
6086 for (i = 0; i < opcnt; i++)
6088 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
6093 if (ops[i].op == OP_RET)
6094 ops[i].regmask_src |= regmask_ret;
6098 // - process trivial calls
6099 for (i = 0; i < opcnt; i++)
6102 if (po->flags & (OPF_RMD|OPF_DONE))
6105 if (po->op == OP_CALL)
6107 pp = process_call_early(i, opcnt, &j);
6109 if (!(po->flags & OPF_ATAIL)) {
6110 // since we know the args, try to collect them
6111 ret = collect_call_args_early(i, pp, ®mask, ®mask_ffca);
6119 // commit esp adjust
6120 if (ops[j].op != OP_POP)
6121 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
6123 for (l = 0; l < pp->argc_stack; l++)
6124 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
6128 if (strstr(pp->ret_type.name, "int64"))
6131 po->flags |= OPF_DONE;
6137 // - process calls, stage 2
6138 // - handle some push/pop pairs
6139 // - scan for STD/CLD, propagate DF
6140 // - try to resolve needed x87 status word bits
6141 for (i = 0; i < opcnt; i++)
6146 if (po->flags & OPF_RMD)
6149 if (po->op == OP_CALL)
6151 if (!(po->flags & OPF_DONE)) {
6152 pp = process_call(i, opcnt);
6154 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
6155 // since we know the args, collect them
6156 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
6158 // for unresolved, collect after other passes
6162 ferr_assert(po, pp != NULL);
6164 po->regmask_src |= get_pp_arg_regmask_src(pp);
6165 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
6167 if (po->regmask_dst & mxST0)
6168 po->flags |= OPF_FPUSH;
6170 if (strstr(pp->ret_type.name, "int64"))
6176 if (po->flags & OPF_DONE)
6181 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
6182 && po->operand[0].type == OPT_CONST)
6184 scan_for_pop_const(i, opcnt, i + opcnt * 12);
6189 scan_pushes_for_pop(i, opcnt, ®mask_pp);
6193 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
6194 scan_propagate_df(i + 1, opcnt);
6199 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
6200 ferr(po, "TODO: fnstsw to mem\n");
6201 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
6203 ferr(po, "fnstsw resolve failed\n");
6204 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
6205 (void *)(long)(mask | (z_check << 16)));
6207 ferr(po, "failed to find fcom: %d\n", ret);
6216 // - find POPs for PUSHes, rm both
6217 // - scan for all used registers
6218 memset(cbits, 0, sizeof(cbits));
6219 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
6220 0, ®mask_save, ®mask_init, regmask_arg);
6222 need_float_stack = !!(regmask & mxST7_2);
6225 // - find flag set ops for their users
6226 // - do unresolved calls
6227 // - declare indirect functions
6228 // - other op specific processing
6229 for (i = 0; i < opcnt; i++)
6232 if (po->flags & (OPF_RMD|OPF_DONE))
6235 if (po->flags & OPF_CC)
6237 int setters[16], cnt = 0, branched = 0;
6239 ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
6240 &branched, setters, &cnt);
6241 if (ret < 0 || cnt <= 0)
6242 ferr(po, "unable to trace flag setter(s)\n");
6243 if (cnt > ARRAY_SIZE(setters))
6244 ferr(po, "too many flag setters\n");
6246 for (j = 0; j < cnt; j++)
6248 tmp_op = &ops[setters[j]]; // flag setter
6251 // to get nicer code, we try to delay test and cmp;
6252 // if we can't because of operand modification, or if we
6253 // have arith op, or branch, make it calculate flags explicitly
6254 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
6256 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
6257 pfomask = 1 << po->pfo;
6259 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
6260 pfomask = 1 << po->pfo;
6263 // see if we'll be able to handle based on op result
6264 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
6265 && po->pfo != PFO_Z && po->pfo != PFO_S
6266 && po->pfo != PFO_P)
6268 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
6270 pfomask = 1 << po->pfo;
6273 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
6274 propagate_lmod(tmp_op, &tmp_op->operand[0],
6275 &tmp_op->operand[1]);
6276 if (tmp_op->operand[0].lmod == OPLM_DWORD)
6281 tmp_op->pfomask |= pfomask;
6282 cond_vars |= pfomask;
6284 // note: may overwrite, currently not a problem
6288 if (po->op == OP_RCL || po->op == OP_RCR
6289 || po->op == OP_ADC || po->op == OP_SBB)
6290 cond_vars |= 1 << PFO_C;
6296 cond_vars |= 1 << PFO_Z;
6300 if (po->operand[0].lmod == OPLM_DWORD)
6305 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
6310 // note: resolved non-reg calls are OPF_DONE already
6312 ferr_assert(po, pp != NULL);
6314 if (pp->is_unresolved) {
6315 int regmask_stack = 0;
6316 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
6318 // this is pretty rough guess:
6319 // see ecx and edx were pushed (and not their saved versions)
6320 for (arg = 0; arg < pp->argc; arg++) {
6321 if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
6324 tmp_op = pp->arg[arg].datap;
6326 ferr(po, "parsed_op missing for arg%d\n", arg);
6327 if (tmp_op->operand[0].type == OPT_REG)
6328 regmask_stack |= 1 << tmp_op->operand[0].reg;
6331 if (!((regmask_stack & (1 << xCX))
6332 && (regmask_stack & (1 << xDX))))
6334 if (pp->argc_stack != 0
6335 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
6337 pp_insert_reg_arg(pp, "ecx");
6338 pp->is_fastcall = 1;
6339 regmask_init |= 1 << xCX;
6340 regmask |= 1 << xCX;
6342 if (pp->argc_stack != 0
6343 || ((regmask | regmask_arg) & (1 << xDX)))
6345 pp_insert_reg_arg(pp, "edx");
6346 regmask_init |= 1 << xDX;
6347 regmask |= 1 << xDX;
6351 // note: __cdecl doesn't fall into is_unresolved category
6352 if (pp->argc_stack > 0)
6355 if (!(po->flags & OPF_TAIL)
6356 && !(g_sct_func_attr & SCTFA_NOWARN))
6358 // treat al write as overwrite to avoid many false positives
6359 if (IS(pp->ret_type.name, "void") || pp->ret_type.is_float) {
6360 find_next_read_reg(i + 1, opcnt, xAX, OPLM_BYTE,
6361 i + opcnt * 25, &j);
6363 fnote(po, "eax used after void/float ret call\n");
6364 fnote(&ops[j], "(used here)\n");
6367 if (!strstr(pp->ret_type.name, "int64")) {
6368 find_next_read_reg(i + 1, opcnt, xDX, OPLM_BYTE,
6369 i + opcnt * 26, &j);
6370 // indirect calls are often guessed, don't warn
6371 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j])) {
6372 fnote(po, "edx used after 32bit ret call\n");
6373 fnote(&ops[j], "(used here)\n");
6377 // msvc often relies on callee not modifying 'this'
6378 for (arg = 0; arg < pp->argc; arg++) {
6379 if (pp->arg[arg].reg && IS(pp->arg[arg].reg, "ecx")) {
6385 find_next_read_reg(i + 1, opcnt, xCX, OPLM_BYTE,
6386 i + opcnt * 27, &j);
6387 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j])) {
6388 fnote(po, "ecx used after call\n");
6389 fnote(&ops[j], "(used here)\n");
6396 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
6398 // <var> = offset <something>
6399 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
6400 && !IS_START(po->operand[1].name, "off_"))
6402 if (!po->operand[0].pp->is_fptr)
6403 ferr(po, "%s not declared as fptr when it should be\n",
6404 po->operand[0].name);
6405 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
6406 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
6407 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
6408 fnote(po, "var: %s\n", buf1);
6409 fnote(po, "func: %s\n", buf2);
6410 ferr(po, "^ mismatch\n");
6418 if (po->operand[0].lmod == OPLM_DWORD) {
6419 // 32bit division is common, look for it
6420 if (po->op == OP_DIV)
6421 ret = scan_for_reg_clear(i, xDX);
6423 ret = scan_for_cdq_edx(i);
6425 po->flags |= OPF_32BIT;
6434 po->flags |= OPF_RMD | OPF_DONE;
6444 if (po->operand[0].lmod == OPLM_QWORD)
6455 find_next_read_reg(i + 1, opcnt, xDX, OPLM_DWORD,
6456 i + opcnt * 18, &j);
6458 po->flags |= OPF_32BIT;
6465 // this might need it's own pass...
6466 if (po->op != OP_FST && po->p_argnum > 0)
6467 save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
6469 // correct for "full stack" mode late enable
6470 if ((po->flags & (OPF_PPUSH|OPF_FPOP|OPF_FPOPP))
6471 && need_float_stack)
6472 po->flags |= OPF_FSHIFT;
6475 float_type = need_double ? "double" : "float";
6476 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
6477 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
6479 // output starts here
6482 fprintf(fout, "// had SEH\n");
6484 // define userstack size
6485 if (g_func_pp->is_userstack) {
6486 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
6487 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
6488 fprintf(fout, "#endif\n");
6491 // the function itself
6492 ferr_assert(ops, !g_func_pp->is_fptr);
6493 output_pp(fout, g_func_pp,
6494 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
6495 fprintf(fout, "\n{\n");
6497 // declare indirect functions
6498 for (i = 0; i < opcnt; i++) {
6500 if (po->flags & OPF_RMD)
6503 if (po->op == OP_CALL) {
6506 ferr(po, "NULL pp\n");
6508 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
6509 if (pp->name[0] != 0) {
6510 if (IS_START(pp->name, "guess"))
6513 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
6514 memcpy(pp->name, "i_", 2);
6516 // might be declared already
6518 for (j = 0; j < i; j++) {
6519 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
6520 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
6530 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
6533 output_pp(fout, pp, OPP_SIMPLE_ARGS);
6534 fprintf(fout, ";\n");
6539 // output LUTs/jumptables
6540 for (i = 0; i < g_func_pd_cnt; i++) {
6542 fprintf(fout, " static const ");
6543 if (pd->type == OPT_OFFSET) {
6544 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
6546 for (j = 0; j < pd->count; j++) {
6548 fprintf(fout, ", ");
6549 fprintf(fout, "&&%s", pd->d[j].u.label);
6553 fprintf(fout, "%s %s[] =\n { ",
6554 lmod_type_u(ops, pd->lmod), pd->label);
6556 for (j = 0; j < pd->count; j++) {
6558 fprintf(fout, ", ");
6559 fprintf(fout, "%u", pd->d[j].u.val);
6562 fprintf(fout, " };\n");
6566 // declare stack frame, va_arg
6569 fprintf(fout, " // stack_fsz_adj %d\n", stack_fsz_adj);
6571 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
6572 if (g_func_lmods & (1 << OPLM_WORD))
6573 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
6574 if (g_func_lmods & (1 << OPLM_BYTE))
6575 fprintf(fout, " u8 b[%d];", g_stack_fsz);
6576 if (g_func_lmods & (1 << OPLM_QWORD))
6577 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
6579 if (stack_align > 8)
6580 ferr(ops, "unhandled stack align of %d\n", stack_align);
6581 else if (stack_align == 8)
6582 fprintf(fout, " u64 align;");
6583 fprintf(fout, " } sf;\n");
6587 if ((g_sct_func_attr & SCTFA_ARGFRAME) && g_func_pp->argc_stack) {
6588 fprintf(fout, " struct { u32 ");
6589 for (i = j = 0; i < g_func_pp->argc; i++) {
6590 if (g_func_pp->arg[i].reg != NULL)
6593 fprintf(fout, ", ");
6594 fprintf(fout, "a%d", i + 1);
6596 fprintf(fout, "; } af = {\n ");
6597 for (i = j = 0; i < g_func_pp->argc; i++) {
6598 if (g_func_pp->arg[i].reg != NULL)
6601 fprintf(fout, ", ");
6602 if (g_func_pp->arg[i].type.is_ptr)
6603 fprintf(fout, "(u32)");
6604 fprintf(fout, "a%d", i + 1);
6606 fprintf(fout, "\n };\n");
6609 if (g_func_pp->is_userstack) {
6610 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
6611 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
6615 if (g_func_pp->is_vararg) {
6616 fprintf(fout, " va_list ap;\n");
6620 // declare arg-registers
6621 for (i = 0; i < g_func_pp->argc; i++) {
6622 if (g_func_pp->arg[i].reg != NULL) {
6623 reg = char_array_i(regs_r32,
6624 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
6625 if (regmask & (1 << reg)) {
6626 if (g_func_pp->arg[i].type.is_retreg)
6627 fprintf(fout, " u32 %s = *r_%s;\n",
6628 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
6630 fprintf(fout, " u32 %s = (u32)a%d;\n",
6631 g_func_pp->arg[i].reg, i + 1);
6634 if (g_func_pp->arg[i].type.is_retreg)
6635 ferr(ops, "retreg '%s' is unused?\n",
6636 g_func_pp->arg[i].reg);
6637 fprintf(fout, " // %s = a%d; // unused\n",
6638 g_func_pp->arg[i].reg, i + 1);
6644 // declare normal registers
6645 regmask_now = regmask & ~regmask_arg & ~g_regmask_rm;
6646 regmask_now &= ~(1 << xSP);
6647 if (regmask_now & 0x00ff) {
6648 for (reg = 0; reg < 8; reg++) {
6649 if (regmask_now & (1 << reg)) {
6650 fprintf(fout, " u32 %s", regs_r32[reg]);
6651 if (regmask_init & (1 << reg))
6652 fprintf(fout, " = 0");
6653 fprintf(fout, ";\n");
6659 if (regmask_now & 0xff00) {
6660 for (reg = 8; reg < 16; reg++) {
6661 if (regmask_now & (1 << reg)) {
6662 fprintf(fout, " mmxr %s", regs_r32[reg]);
6663 if (regmask_init & (1 << reg))
6664 fprintf(fout, " = { 0, }");
6665 fprintf(fout, ";\n");
6671 if (need_float_stack) {
6672 fprintf(fout, " %s f_st[8];\n", float_type);
6673 fprintf(fout, " int f_stp = 0;\n");
6677 if (regmask_now & 0xff0000) {
6678 for (reg = 16; reg < 24; reg++) {
6679 if (regmask_now & (1 << reg)) {
6680 fprintf(fout, " %s f_st%d", float_type, reg - 16);
6681 if (regmask_init & (1 << reg))
6682 fprintf(fout, " = 0");
6683 fprintf(fout, ";\n");
6690 if (need_float_sw) {
6691 fprintf(fout, " u16 f_sw;\n");
6696 for (reg = 0; reg < 8; reg++) {
6697 if (regmask_save & (1 << reg)) {
6698 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
6704 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6705 if (save_arg_vars[i] == 0)
6707 for (reg = 0; reg < 32; reg++) {
6708 if (save_arg_vars[i] & (1 << reg)) {
6709 fprintf(fout, " u32 %s;\n",
6710 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
6717 for (reg = 0; reg < 32; reg++) {
6718 if (regmask_ffca & (1 << reg)) {
6719 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
6725 // declare push-pop temporaries
6727 for (reg = 0; reg < 8; reg++) {
6728 if (regmask_pp & (1 << reg)) {
6729 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
6736 for (i = 0; i < 8; i++) {
6737 if (cond_vars & (1 << i)) {
6738 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
6745 fprintf(fout, " u32 tmp;\n");
6750 fprintf(fout, " u64 tmp64;\n");
6755 fprintf(fout, "\n");
6757 // do stack clear, if needed
6758 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6760 if (g_stack_clear_len != 0) {
6761 if (g_stack_clear_len <= 4) {
6762 for (i = 0; i < g_stack_clear_len; i++)
6763 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6764 fprintf(fout, "0;\n");
6767 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6768 g_stack_clear_start, g_stack_clear_len * 4);
6772 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6775 if (g_func_pp->is_vararg) {
6776 if (g_func_pp->argc_stack == 0)
6777 ferr(ops, "vararg func without stack args?\n");
6778 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
6782 for (i = 0; i < opcnt; i++)
6784 if (g_labels[i] != NULL) {
6785 fprintf(fout, "\n%s:\n", g_labels[i]);
6788 delayed_flag_op = NULL;
6789 last_arith_dst = NULL;
6793 if (po->flags & OPF_RMD)
6799 #define assert_operand_cnt(n_) \
6800 if (po->operand_cnt != n_) \
6801 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6803 // conditional/flag using op?
6804 if (po->flags & OPF_CC)
6810 // we go through all this trouble to avoid using parsed_flag_op,
6811 // which makes generated code much nicer
6812 if (delayed_flag_op != NULL)
6814 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6815 po->pfo, po->pfo_inv);
6818 else if (last_arith_dst != NULL
6819 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6820 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6823 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6824 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6825 last_arith_dst->lmod, buf3);
6828 else if (tmp_op != NULL) {
6829 // use preprocessed flag calc results
6830 if (!(tmp_op->pfomask & (1 << po->pfo)))
6831 ferr(po, "not prepared for pfo %d\n", po->pfo);
6833 // note: pfo_inv was not yet applied
6834 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6835 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6838 ferr(po, "all methods of finding comparison failed\n");
6841 if (po->flags & OPF_JMP) {
6842 fprintf(fout, " if %s", buf1);
6844 else if (po->op == OP_RCL || po->op == OP_RCR
6845 || po->op == OP_ADC || po->op == OP_SBB)
6848 fprintf(fout, " cond_%s = %s;\n",
6849 parsed_flag_op_names[po->pfo], buf1);
6851 else if (po->flags & OPF_DATA) { // SETcc
6852 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6853 fprintf(fout, " %s = %s;", buf2, buf1);
6856 ferr(po, "unhandled conditional op\n");
6860 pfomask = po->pfomask;
6865 assert_operand_cnt(2);
6866 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6867 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6868 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
6869 fprintf(fout, " %s = %s;", buf1,
6870 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6875 assert_operand_cnt(2);
6876 po->operand[1].lmod = OPLM_DWORD; // always
6877 fprintf(fout, " %s = %s;",
6878 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6879 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6884 assert_operand_cnt(2);
6885 fprintf(fout, " %s = %s;",
6886 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6887 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6891 assert_operand_cnt(2);
6892 switch (po->operand[1].lmod) {
6894 strcpy(buf3, "(s8)");
6897 strcpy(buf3, "(s16)");
6900 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6902 fprintf(fout, " %s = %s;",
6903 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6904 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6909 assert_operand_cnt(2);
6910 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6911 fprintf(fout, " tmp = %s;",
6912 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6913 fprintf(fout, " %s = %s;",
6914 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6915 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6916 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6917 fprintf(fout, " %s = %stmp;",
6918 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6919 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
6920 snprintf(g_comment, sizeof(g_comment), "xchg");
6924 assert_operand_cnt(1);
6925 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6926 fprintf(fout, " %s = ~%s;", buf1, buf1);
6930 assert_operand_cnt(2);
6931 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6932 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6933 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6934 strcpy(g_comment, "xlat");
6938 assert_operand_cnt(2);
6939 fprintf(fout, " %s = (s32)%s >> 31;",
6940 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6941 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6942 strcpy(g_comment, "cdq");
6946 assert_operand_cnt(1);
6947 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6948 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
6952 if (po->flags & OPF_REP) {
6953 assert_operand_cnt(3);
6958 assert_operand_cnt(2);
6959 fprintf(fout, " %s = %sesi; esi %c= %d;",
6960 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6961 lmod_cast_u_ptr(po, po->operand[1].lmod),
6962 (po->flags & OPF_DF) ? '-' : '+',
6963 lmod_bytes(po, po->operand[1].lmod));
6964 strcpy(g_comment, "lods");
6969 if (po->flags & OPF_REP) {
6970 assert_operand_cnt(3);
6971 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
6972 (po->flags & OPF_DF) ? '-' : '+',
6973 lmod_bytes(po, po->operand[1].lmod));
6974 fprintf(fout, " %sedi = eax;\n",
6975 lmod_cast_u_ptr(po, po->operand[1].lmod));
6976 fprintf(fout, " barrier();");
6977 strcpy(g_comment, "^ rep stos");
6980 assert_operand_cnt(2);
6981 fprintf(fout, " %sedi = eax; edi %c= %d;",
6982 lmod_cast_u_ptr(po, po->operand[1].lmod),
6983 (po->flags & OPF_DF) ? '-' : '+',
6984 lmod_bytes(po, po->operand[1].lmod));
6985 strcpy(g_comment, "stos");
6990 j = lmod_bytes(po, po->operand[0].lmod);
6991 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6992 l = (po->flags & OPF_DF) ? '-' : '+';
6993 if (po->flags & OPF_REP) {
6994 assert_operand_cnt(3);
6996 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
6999 " %sedi = %sesi;\n", buf1, buf1);
7000 // this can overwrite many variables
7001 fprintf(fout, " barrier();");
7002 strcpy(g_comment, "^ rep movs");
7005 assert_operand_cnt(2);
7006 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
7007 buf1, buf1, l, j, l, j);
7008 strcpy(g_comment, "movs");
7013 // repe ~ repeat while ZF=1
7014 j = lmod_bytes(po, po->operand[0].lmod);
7015 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
7016 l = (po->flags & OPF_DF) ? '-' : '+';
7017 if (po->flags & OPF_REP) {
7018 assert_operand_cnt(3);
7020 " while (ecx != 0) {\n");
7021 if (pfomask & (1 << PFO_C)) {
7024 " cond_c = %sesi < %sedi;\n", buf1, buf1);
7025 pfomask &= ~(1 << PFO_C);
7028 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
7029 buf1, buf1, l, j, l, j);
7032 " if (cond_z %s 0) break;\n",
7033 (po->flags & OPF_REPZ) ? "==" : "!=");
7036 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
7037 (po->flags & OPF_REPZ) ? "e" : "ne");
7040 assert_operand_cnt(2);
7042 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
7043 buf1, buf1, l, j, l, j);
7044 strcpy(g_comment, "cmps");
7046 pfomask &= ~(1 << PFO_Z);
7047 last_arith_dst = NULL;
7048 delayed_flag_op = NULL;
7052 // only does ZF (for now)
7053 // repe ~ repeat while ZF=1
7054 j = lmod_bytes(po, po->operand[1].lmod);
7055 l = (po->flags & OPF_DF) ? '-' : '+';
7056 if (po->flags & OPF_REP) {
7057 assert_operand_cnt(3);
7059 " while (ecx != 0) {\n");
7061 " cond_z = (%seax == %sedi); edi %c= %d;\n",
7062 lmod_cast_u(po, po->operand[1].lmod),
7063 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
7066 " if (cond_z %s 0) break;\n",
7067 (po->flags & OPF_REPZ) ? "==" : "!=");
7070 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
7071 (po->flags & OPF_REPZ) ? "e" : "ne");
7074 assert_operand_cnt(2);
7075 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
7076 lmod_cast_u(po, po->operand[1].lmod),
7077 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
7078 strcpy(g_comment, "scas");
7080 pfomask &= ~(1 << PFO_Z);
7081 last_arith_dst = NULL;
7082 delayed_flag_op = NULL;
7086 fprintf(fout, " tmp64 = ext_rdtsc();\n");
7087 fprintf(fout, " edx = tmp64 >> 32;\n");
7088 fprintf(fout, " eax = tmp64;");
7092 fprintf(fout, " ext_cpuid(&eax, &ebx, &ecx, &edx);");
7095 // arithmetic w/flags
7097 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
7098 goto dualop_arith_const;
7099 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7103 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7104 if (po->operand[1].type == OPT_CONST) {
7105 j = lmod_bytes(po, po->operand[0].lmod);
7106 if (((1ull << j * 8) - 1) == po->operand[1].val)
7107 goto dualop_arith_const;
7112 assert_operand_cnt(2);
7113 fprintf(fout, " %s %s= %s;",
7114 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7116 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7117 output_std_flags(fout, po, &pfomask, buf1);
7118 last_arith_dst = &po->operand[0];
7119 delayed_flag_op = NULL;
7123 // and 0, or ~0 used instead mov
7124 assert_operand_cnt(2);
7125 fprintf(fout, " %s = %s;",
7126 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7127 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
7128 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7129 output_std_flags(fout, po, &pfomask, buf1);
7130 last_arith_dst = &po->operand[0];
7131 delayed_flag_op = NULL;
7136 assert_operand_cnt(2);
7137 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7138 if (pfomask & (1 << PFO_C)) {
7139 if (po->operand[1].type == OPT_CONST) {
7140 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7141 j = po->operand[1].val;
7144 if (po->op == OP_SHL)
7148 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
7152 ferr(po, "zero shift?\n");
7156 pfomask &= ~(1 << PFO_C);
7158 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
7159 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7160 if (po->operand[1].type != OPT_CONST)
7161 fprintf(fout, " & 0x1f");
7163 output_std_flags(fout, po, &pfomask, buf1);
7164 last_arith_dst = &po->operand[0];
7165 delayed_flag_op = NULL;
7169 assert_operand_cnt(2);
7170 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7171 fprintf(fout, " %s = %s%s >> %s;", buf1,
7172 lmod_cast_s(po, po->operand[0].lmod), buf1,
7173 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7174 output_std_flags(fout, po, &pfomask, buf1);
7175 last_arith_dst = &po->operand[0];
7176 delayed_flag_op = NULL;
7181 assert_operand_cnt(3);
7182 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7183 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7184 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
7185 if (po->operand[2].type != OPT_CONST) {
7186 // no handling for "undefined" case, hopefully not needed
7187 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
7190 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7191 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7192 if (po->op == OP_SHLD) {
7193 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
7194 buf1, buf3, buf1, buf2, l, buf3);
7195 strcpy(g_comment, "shld");
7198 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
7199 buf1, buf3, buf1, buf2, l, buf3);
7200 strcpy(g_comment, "shrd");
7202 output_std_flags(fout, po, &pfomask, buf1);
7203 last_arith_dst = &po->operand[0];
7204 delayed_flag_op = NULL;
7209 assert_operand_cnt(2);
7210 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7211 if (po->operand[1].type == OPT_CONST) {
7212 j = po->operand[1].val;
7213 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
7214 fprintf(fout, po->op == OP_ROL ?
7215 " %s = (%s << %d) | (%s >> %d);" :
7216 " %s = (%s >> %d) | (%s << %d);",
7217 buf1, buf1, j, buf1,
7218 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
7222 output_std_flags(fout, po, &pfomask, buf1);
7223 last_arith_dst = &po->operand[0];
7224 delayed_flag_op = NULL;
7229 assert_operand_cnt(2);
7230 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7231 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7232 if (po->operand[1].type == OPT_CONST) {
7233 j = po->operand[1].val % l;
7235 ferr(po, "zero rotate\n");
7236 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
7237 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
7238 if (po->op == OP_RCL) {
7240 " %s = (%s << %d) | (cond_c << %d)",
7241 buf1, buf1, j, j - 1);
7243 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
7247 " %s = (%s >> %d) | (cond_c << %d)",
7248 buf1, buf1, j, l - j);
7250 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
7252 fprintf(fout, ";\n");
7253 fprintf(fout, " cond_c = tmp;");
7257 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
7258 output_std_flags(fout, po, &pfomask, buf1);
7259 last_arith_dst = &po->operand[0];
7260 delayed_flag_op = NULL;
7264 assert_operand_cnt(2);
7265 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7266 if (IS(opr_name(po, 0), opr_name(po, 1))) {
7267 // special case for XOR
7268 int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
7269 for (j = 0; j <= PFO_LE; j++) {
7270 if (pfomask & (1 << j)) {
7271 fprintf(fout, " cond_%s = %d;\n",
7272 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
7273 pfomask &= ~(1 << j);
7276 fprintf(fout, " %s = 0;",
7277 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7278 last_arith_dst = &po->operand[0];
7279 delayed_flag_op = NULL;
7285 assert_operand_cnt(2);
7286 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7287 if (pfomask & (1 << PFO_C)) {
7288 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7289 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7290 if (po->operand[0].lmod == OPLM_DWORD) {
7291 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
7292 fprintf(fout, " cond_c = tmp64 >> 32;\n");
7293 fprintf(fout, " %s = (u32)tmp64;",
7294 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7295 strcat(g_comment, " add64");
7298 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
7299 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
7300 fprintf(fout, " %s += %s;",
7301 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7304 pfomask &= ~(1 << PFO_C);
7305 output_std_flags(fout, po, &pfomask, buf1);
7306 last_arith_dst = &po->operand[0];
7307 delayed_flag_op = NULL;
7310 if (pfomask & (1 << PFO_LE)) {
7311 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
7312 fprintf(fout, " cond_%s = %s;\n",
7313 parsed_flag_op_names[PFO_LE], buf1);
7314 pfomask &= ~(1 << PFO_LE);
7319 assert_operand_cnt(2);
7320 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7321 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
7322 for (j = 0; j <= PFO_LE; j++) {
7323 if (!(pfomask & (1 << j)))
7325 if (j == PFO_Z || j == PFO_S)
7328 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7329 fprintf(fout, " cond_%s = %s;\n",
7330 parsed_flag_op_names[j], buf1);
7331 pfomask &= ~(1 << j);
7338 assert_operand_cnt(2);
7339 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7340 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7341 if (po->op == OP_SBB
7342 && IS(po->operand[0].name, po->operand[1].name))
7344 // avoid use of unitialized var
7345 fprintf(fout, " %s = -cond_c;", buf1);
7346 // carry remains what it was
7347 pfomask &= ~(1 << PFO_C);
7350 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
7351 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7353 output_std_flags(fout, po, &pfomask, buf1);
7354 last_arith_dst = &po->operand[0];
7355 delayed_flag_op = NULL;
7360 // on SKL, if src is 0, dst is left unchanged
7361 assert_operand_cnt(2);
7362 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7363 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7364 output_std_flag_z(fout, po, &pfomask, buf2);
7365 if (po->op == OP_BSF)
7366 snprintf(buf3, sizeof(buf3), "__builtin_ffs(%s) - 1", buf2);
7368 snprintf(buf3, sizeof(buf3), "31 - __builtin_clz(%s)", buf2);
7369 fprintf(fout, " if (%s) %s = %s;", buf2, buf1, buf3);
7370 last_arith_dst = &po->operand[0];
7371 delayed_flag_op = NULL;
7372 strcat(g_comment, po->op == OP_BSF ? " bsf" : " bsr");
7376 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
7377 for (j = 0; j <= PFO_LE; j++) {
7378 if (!(pfomask & (1 << j)))
7380 if (j == PFO_Z || j == PFO_S || j == PFO_C)
7383 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7384 fprintf(fout, " cond_%s = %s;\n",
7385 parsed_flag_op_names[j], buf1);
7386 pfomask &= ~(1 << j);
7392 if (pfomask & (1 << PFO_C))
7393 // carry is unaffected by inc/dec.. wtf?
7394 ferr(po, "carry propagation needed\n");
7396 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7397 if (po->operand[0].type == OPT_REG) {
7398 ferr_assert(po, !(po->flags & OPF_LOCK));
7399 strcpy(buf2, po->op == OP_INC ? "++" : "--");
7400 fprintf(fout, " %s%s;", buf1, buf2);
7402 else if (po->flags & OPF_LOCK) {
7403 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0], "", 1);
7404 fprintf(fout, " __sync_fetch_and_%s((%s *)(%s), 1);",
7405 po->op == OP_INC ? "add" : "sub",
7406 lmod_type_u(po, po->operand[0].lmod), buf2);
7407 strcat(g_comment, " lock");
7411 strcpy(buf2, po->op == OP_INC ? "+" : "-");
7412 fprintf(fout, " %s %s= 1;", buf1, buf2);
7414 output_std_flags(fout, po, &pfomask, buf1);
7415 last_arith_dst = &po->operand[0];
7416 delayed_flag_op = NULL;
7420 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7421 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
7422 fprintf(fout, " %s = -%s%s;", buf1,
7423 lmod_cast_s(po, po->operand[0].lmod), buf2);
7424 last_arith_dst = &po->operand[0];
7425 delayed_flag_op = NULL;
7426 if (pfomask & PFOB_C) {
7427 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
7430 output_std_flags(fout, po, &pfomask, buf1);
7434 if (po->operand_cnt == 2) {
7435 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7438 if (po->operand_cnt == 3)
7439 ferr(po, "TODO imul3\n");
7442 assert_operand_cnt(1);
7443 switch (po->operand[0].lmod) {
7445 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
7446 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
7447 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
7448 fprintf(fout, " edx = tmp64 >> 32;\n");
7449 fprintf(fout, " eax = tmp64;");
7452 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
7453 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
7454 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
7458 ferr(po, "TODO: unhandled mul type\n");
7461 last_arith_dst = NULL;
7462 delayed_flag_op = NULL;
7467 assert_operand_cnt(1);
7468 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7469 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
7470 po->op == OP_IDIV));
7471 switch (po->operand[0].lmod) {
7473 if (po->flags & OPF_32BIT)
7474 snprintf(buf2, sizeof(buf2), "%seax", cast);
7476 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7477 snprintf(buf2, sizeof(buf2), "%stmp64",
7478 (po->op == OP_IDIV) ? "(s64)" : "");
7480 if (po->operand[0].type == OPT_REG
7481 && po->operand[0].reg == xDX)
7483 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
7484 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
7487 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
7488 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
7492 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
7493 snprintf(buf2, sizeof(buf2), "%stmp",
7494 (po->op == OP_IDIV) ? "(s32)" : "");
7495 if (po->operand[0].type == OPT_REG
7496 && po->operand[0].reg == xDX)
7498 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
7500 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
7504 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
7506 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
7509 strcat(g_comment, " div16");
7512 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
7514 last_arith_dst = NULL;
7515 delayed_flag_op = NULL;
7520 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7522 for (j = 0; j < 8; j++) {
7523 if (pfomask & (1 << j)) {
7524 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
7525 fprintf(fout, " cond_%s = %s;",
7526 parsed_flag_op_names[j], buf1);
7533 last_arith_dst = NULL;
7534 delayed_flag_op = po;
7538 // SETcc - should already be handled
7541 // note: we reuse OP_Jcc for SETcc, only flags differ
7543 fprintf(fout, "\n goto %s;", po->operand[0].name);
7547 fprintf(fout, " if (ecx == 0)\n");
7548 fprintf(fout, " goto %s;", po->operand[0].name);
7549 strcat(g_comment, " jecxz");
7553 fprintf(fout, " if (--ecx != 0)\n");
7554 fprintf(fout, " goto %s;", po->operand[0].name);
7555 strcat(g_comment, " loop");
7559 assert_operand_cnt(1);
7560 last_arith_dst = NULL;
7561 delayed_flag_op = NULL;
7563 if (po->operand[0].type == OPT_REGMEM) {
7564 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
7567 ferr(po, "parse failure for jmp '%s'\n",
7568 po->operand[0].name);
7569 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
7572 else if (po->operand[0].type != OPT_LABEL)
7573 ferr(po, "unhandled jmp type\n");
7575 fprintf(fout, " goto %s;", po->operand[0].name);
7579 assert_operand_cnt(1);
7581 my_assert_not(pp, NULL);
7584 if (po->flags & OPF_CC) {
7585 // we treat conditional branch to another func
7586 // (yes such code exists..) as conditional tailcall
7588 fprintf(fout, " {\n");
7591 if (pp->is_fptr && !pp->is_arg) {
7592 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
7593 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7596 if (pp->is_fptr && (pp->is_unresolved || pp->is_guessed)) {
7597 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
7598 buf3, asmfn, po->asmln, pp->name);
7601 fprintf(fout, "%s", buf3);
7602 if (strstr(pp->ret_type.name, "int64")) {
7603 if (po->flags & OPF_TAIL)
7604 ferr(po, "int64 and tail?\n");
7605 fprintf(fout, "tmp64 = ");
7607 else if (!IS(pp->ret_type.name, "void")) {
7608 if (po->flags & OPF_TAIL) {
7609 if (regmask_ret & mxAX) {
7610 fprintf(fout, "return ");
7611 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
7612 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
7614 else if (regmask_ret & mxST0)
7615 ferr(po, "float tailcall\n");
7617 else if (po->regmask_dst & mxAX) {
7618 fprintf(fout, "eax = ");
7619 if (pp->ret_type.is_ptr)
7620 fprintf(fout, "(u32)");
7622 else if (po->regmask_dst & mxST0) {
7623 ferr_assert(po, po->flags & OPF_FPUSH);
7624 if (need_float_stack)
7625 fprintf(fout, "f_st[--f_stp & 7] = ");
7627 fprintf(fout, "f_st0 = ");
7631 if (pp->name[0] == 0)
7632 ferr(po, "missing pp->name\n");
7633 fprintf(fout, "%s%s(", pp->name,
7634 pp->has_structarg ? "_sa" : "");
7636 if (po->flags & OPF_ATAIL) {
7638 g_func_pp->is_stdcall && g_func_pp->argc_stack > 0;
7639 check_compat |= pp->argc_stack > 0;
7641 && (pp->argc_stack != g_func_pp->argc_stack
7642 || pp->is_stdcall != g_func_pp->is_stdcall))
7643 ferr(po, "incompatible arg-reuse tailcall\n");
7644 if (g_func_pp->has_retreg)
7645 ferr(po, "TODO: retreg+tailcall\n");
7647 for (arg = j = 0; arg < pp->argc; arg++) {
7649 fprintf(fout, ", ");
7652 if (pp->arg[arg].type.is_ptr)
7653 snprintf(cast, sizeof(cast), "(%s)",
7654 pp->arg[arg].type.name);
7656 if (pp->arg[arg].reg != NULL) {
7657 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7661 for (; j < g_func_pp->argc; j++)
7662 if (g_func_pp->arg[j].reg == NULL)
7664 fprintf(fout, "%sa%d", cast, j + 1);
7669 for (arg = 0; arg < pp->argc; arg++) {
7671 fprintf(fout, ", ");
7674 if (pp->arg[arg].type.is_ptr)
7675 snprintf(cast, sizeof(cast), "(%s)",
7676 pp->arg[arg].type.name);
7678 if (pp->arg[arg].reg != NULL) {
7679 if (pp->arg[arg].type.is_retreg)
7680 fprintf(fout, "&%s", pp->arg[arg].reg);
7681 else if (IS(pp->arg[arg].reg, "ebp")
7682 && g_bp_frame && !(po->flags & OPF_EBP_S))
7684 // rare special case
7685 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
7686 strcat(g_comment, " bp_ref");
7689 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7694 tmp_op = pp->arg[arg].datap;
7696 ferr(po, "parsed_op missing for arg%d\n", arg);
7698 if (tmp_op->flags & OPF_VAPUSH) {
7699 fprintf(fout, "ap");
7701 else if (tmp_op->op == OP_FST) {
7702 fprintf(fout, "fs_%d", tmp_op->p_argnum);
7703 if (tmp_op->operand[0].lmod == OPLM_QWORD)
7706 else if (pp->arg[arg].type.is_64bit) {
7707 ferr_assert(po, tmp_op->p_argpass == 0);
7708 ferr_assert(po, !pp->arg[arg].is_saved);
7709 ferr_assert(po, !pp->arg[arg].type.is_float);
7710 ferr_assert(po, cast[0] == 0);
7711 out_src_opr(buf1, sizeof(buf1),
7712 tmp_op, &tmp_op->operand[0], cast, 0);
7713 tmp_op = pp->arg[++arg].datap;
7714 ferr_assert(po, tmp_op != NULL);
7715 out_src_opr(buf2, sizeof(buf2),
7716 tmp_op, &tmp_op->operand[0], cast, 0);
7717 fprintf(fout, "((u64)(%s) << 32) | (%s)",
7720 else if (tmp_op->p_argpass != 0) {
7721 ferr_assert(po, !pp->arg[arg].type.is_float);
7722 fprintf(fout, "a%d", tmp_op->p_argpass);
7724 else if (pp->arg[arg].is_saved) {
7725 ferr_assert(po, tmp_op->p_argnum > 0);
7726 ferr_assert(po, !pp->arg[arg].type.is_float);
7727 fprintf(fout, "%s%s", cast,
7728 saved_arg_name(buf1, sizeof(buf1),
7729 tmp_op->p_arggrp, tmp_op->p_argnum));
7731 else if (pp->arg[arg].type.is_float) {
7732 ferr_assert(po, !pp->arg[arg].type.is_64bit);
7734 out_src_opr_float(buf1, sizeof(buf1),
7735 tmp_op, &tmp_op->operand[0], need_float_stack));
7739 out_src_opr(buf1, sizeof(buf1),
7740 tmp_op, &tmp_op->operand[0], cast, 0));
7744 fprintf(fout, ");");
7746 if (strstr(pp->ret_type.name, "int64")) {
7747 fprintf(fout, "\n");
7748 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7749 fprintf(fout, "%seax = tmp64;", buf3);
7752 if (pp->is_unresolved) {
7753 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
7755 strcat(g_comment, buf2);
7758 if (po->flags & OPF_TAIL) {
7760 if (i == opcnt - 1 || pp->is_noreturn)
7762 else if (IS(pp->ret_type.name, "void"))
7764 else if (!(regmask_ret & (1 << xAX)))
7766 // else already handled as 'return f()'
7769 fprintf(fout, "\n%sreturn;", buf3);
7770 strcat(g_comment, " ^ tailcall");
7773 strcat(g_comment, " tailcall");
7775 if ((regmask_ret & (1 << xAX))
7776 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7778 ferr(po, "int func -> void func tailcall?\n");
7781 if (pp->is_noreturn)
7782 strcat(g_comment, " noreturn");
7783 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7784 strcat(g_comment, " argframe");
7785 if (po->flags & OPF_CC)
7786 strcat(g_comment, " cond");
7788 if (po->flags & OPF_CC)
7789 fprintf(fout, "\n }");
7791 delayed_flag_op = NULL;
7792 last_arith_dst = NULL;
7796 if (g_func_pp->is_vararg)
7797 fprintf(fout, " va_end(ap);\n");
7798 if (g_func_pp->has_retreg) {
7799 for (arg = 0; arg < g_func_pp->argc; arg++)
7800 if (g_func_pp->arg[arg].type.is_retreg)
7801 fprintf(fout, " *r_%s = %s;\n",
7802 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7805 if (regmask_ret & mxST0) {
7806 fprintf(fout, " return %s;", float_st0);
7808 else if (!(regmask_ret & mxAX)) {
7809 if (i != opcnt - 1 || label_pending)
7810 fprintf(fout, " return;");
7812 else if (g_func_pp->ret_type.is_ptr) {
7813 fprintf(fout, " return (%s)eax;",
7814 g_func_pp->ret_type.name);
7816 else if (IS(g_func_pp->ret_type.name, "__int64"))
7817 fprintf(fout, " return ((u64)edx << 32) | eax;");
7819 fprintf(fout, " return eax;");
7821 last_arith_dst = NULL;
7822 delayed_flag_op = NULL;
7826 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7827 if (po->p_argnum != 0) {
7828 // special case - saved func arg
7829 fprintf(fout, " %s = %s;",
7830 saved_arg_name(buf2, sizeof(buf2),
7831 po->p_arggrp, po->p_argnum), buf1);
7834 else if (po->flags & OPF_RSAVE) {
7835 fprintf(fout, " s_%s = %s;", buf1, buf1);
7838 else if (po->flags & OPF_PPUSH) {
7840 ferr_assert(po, tmp_op != NULL);
7841 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7842 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7845 else if (g_func_pp->is_userstack) {
7846 fprintf(fout, " *(--esp) = %s;", buf1);
7849 if (!(g_ida_func_attr & IDAFA_NORETURN))
7850 ferr(po, "stray push encountered\n");
7855 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7856 if (po->flags & OPF_RSAVE) {
7857 fprintf(fout, " %s = s_%s;", buf1, buf1);
7860 else if (po->flags & OPF_PPUSH) {
7861 // push/pop graph / non-const
7862 ferr_assert(po, po->datap == NULL);
7863 fprintf(fout, " %s = pp_%s;", buf1, buf1);
7866 else if (po->datap != NULL) {
7869 fprintf(fout, " %s = %s;", buf1,
7870 out_src_opr(buf2, sizeof(buf2),
7871 tmp_op, &tmp_op->operand[0],
7872 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7875 else if (g_func_pp->is_userstack) {
7876 fprintf(fout, " %s = *esp++;", buf1);
7880 ferr(po, "stray pop encountered\n");
7890 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7891 fprintf(fout, " tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
7892 po->op == OPP_ALLSHL ? "<<" : ">>");
7893 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
7894 strcat(g_comment, po->op == OPP_ALLSHL
7895 ? " allshl" : " allshr");
7900 if (need_float_stack) {
7901 out_src_opr_float(buf1, sizeof(buf1),
7902 po, &po->operand[0], 1);
7903 if (po->regmask_src & mxSTa) {
7904 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7908 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
7911 if (po->flags & OPF_FSHIFT)
7912 fprintf(fout, " f_st1 = f_st0;");
7913 if (po->operand[0].type == OPT_REG
7914 && po->operand[0].reg == xST0)
7916 strcat(g_comment, " fld st");
7919 fprintf(fout, " f_st0 = %s;",
7920 out_src_opr_float(buf1, sizeof(buf1),
7921 po, &po->operand[0], 0));
7923 strcat(g_comment, " fld");
7927 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7928 lmod_cast(po, po->operand[0].lmod, 1), 0);
7929 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7930 if (need_float_stack) {
7931 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
7934 if (po->flags & OPF_FSHIFT)
7935 fprintf(fout, " f_st1 = f_st0;");
7936 fprintf(fout, " f_st0 = %s;", buf2);
7938 strcat(g_comment, " fild");
7942 if (need_float_stack)
7943 fprintf(fout, " f_st[--f_stp & 7] = ");
7945 if (po->flags & OPF_FSHIFT)
7946 fprintf(fout, " f_st1 = f_st0;");
7947 fprintf(fout, " f_st0 = ");
7949 switch (po->operand[0].val) {
7950 case X87_CONST_1: fprintf(fout, "1.0;"); break;
7951 case X87_CONST_L2T: fprintf(fout, "3.321928094887362;"); break;
7952 case X87_CONST_L2E: fprintf(fout, "M_LOG2E;"); break;
7953 case X87_CONST_PI: fprintf(fout, "M_PI;"); break;
7954 case X87_CONST_LG2: fprintf(fout, "0.301029995663981;"); break;
7955 case X87_CONST_LN2: fprintf(fout, "M_LN2;"); break;
7956 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
7957 default: ferr_assert(po, 0); break;
7962 if (po->flags & OPF_FARG) {
7963 // store to stack as func arg
7964 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7968 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7970 dead_dst = po->operand[0].type == OPT_REG
7971 && po->operand[0].reg == xST0;
7974 fprintf(fout, " %s = %s;", buf1, float_st0);
7975 if (po->flags & OPF_FSHIFT) {
7976 if (need_float_stack)
7977 fprintf(fout, " f_stp++;");
7979 fprintf(fout, " f_st0 = f_st1;");
7981 if (dead_dst && !(po->flags & OPF_FSHIFT))
7984 strcat(g_comment, " fst");
7988 fprintf(fout, " %s = %s%s;",
7989 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7990 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7991 if (po->flags & OPF_FSHIFT) {
7992 if (need_float_stack)
7993 fprintf(fout, " f_stp++;");
7995 fprintf(fout, " f_st0 = f_st1;");
7997 strcat(g_comment, " fist");
8004 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8006 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
8008 dead_dst = (po->flags & OPF_FPOP)
8009 && po->operand[0].type == OPT_REG
8010 && po->operand[0].reg == xST0;
8012 case OP_FADD: j = '+'; break;
8013 case OP_FDIV: j = '/'; break;
8014 case OP_FMUL: j = '*'; break;
8015 case OP_FSUB: j = '-'; break;
8016 default: j = 'x'; break;
8018 if (need_float_stack) {
8020 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
8021 if (po->flags & OPF_FSHIFT)
8022 fprintf(fout, " f_stp++;");
8025 if (po->flags & OPF_FSHIFT) {
8026 // note: assumes only 2 regs handled
8028 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
8030 fprintf(fout, " f_st0 = f_st1;");
8033 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
8035 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
8040 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8042 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
8044 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
8046 dead_dst = (po->flags & OPF_FPOP)
8047 && po->operand[0].type == OPT_REG
8048 && po->operand[0].reg == xST0;
8049 j = po->op == OP_FDIVR ? '/' : '-';
8050 if (need_float_stack) {
8052 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
8053 if (po->flags & OPF_FSHIFT)
8054 fprintf(fout, " f_stp++;");
8057 if (po->flags & OPF_FSHIFT) {
8059 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
8061 fprintf(fout, " f_st0 = f_st1;");
8064 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
8066 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
8074 case OP_FIADD: j = '+'; break;
8075 case OP_FIDIV: j = '/'; break;
8076 case OP_FIMUL: j = '*'; break;
8077 case OP_FISUB: j = '-'; break;
8078 default: j = 'x'; break;
8080 fprintf(fout, " %s %c= (%s)%s;", float_st0,
8082 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
8083 lmod_cast(po, po->operand[0].lmod, 1), 0));
8088 fprintf(fout, " %s = %s %c %s;", float_st0,
8089 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
8091 po->op == OP_FIDIVR ? '/' : '-', float_st0);
8096 ferr_assert(po, po->datap != NULL);
8097 mask = (long)po->datap & 0xffff;
8098 z_check = ((long)po->datap >> 16) & 1;
8099 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8101 if (mask == 0x0100 || mask == 0x0500) { // C0 -> <
8102 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
8105 else if (mask == 0x4000 || mask == 0x4400) { // C3 -> =
8106 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
8109 else if (mask == 0x4100) { // C3, C0
8111 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
8113 strcat(g_comment, " z_chk_det");
8116 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
8117 "(%s < %s ? 0x0100 : 0);",
8118 float_st0, buf1, float_st0, buf1);
8122 ferr(po, "unhandled sw mask: %x\n", mask);
8123 if (po->flags & OPF_FSHIFT) {
8124 if (need_float_stack) {
8125 if (po->flags & OPF_FPOPP)
8126 fprintf(fout, " f_stp += 2;");
8128 fprintf(fout, " f_stp++;");
8131 ferr_assert(po, !(po->flags & OPF_FPOPP));
8132 fprintf(fout, " f_st0 = f_st1;");
8139 fprintf(fout, " %s = f_sw;",
8140 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
8144 fprintf(fout, " %s = -%s;", float_st0, float_st0);
8148 fprintf(fout, " %s = cos%s(%s);", float_st0,
8149 need_double ? "" : "f", float_st0);
8153 if (need_float_stack) {
8154 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
8155 need_double ? "" : "f", float_st1, float_st0);
8156 fprintf(fout, " f_stp++;");
8159 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
8160 need_double ? "" : "f");
8165 if (need_float_stack) {
8166 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
8167 float_st1, need_double ? "" : "f", float_st0);
8168 fprintf(fout, " f_stp++;");
8171 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
8172 need_double ? "" : "f");
8174 strcat(g_comment, " fyl2x");
8178 fprintf(fout, " %s = sin%s(%s);", float_st0,
8179 need_double ? "" : "f", float_st0);
8183 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
8184 need_double ? "" : "f", float_st0);
8188 dead_dst = po->operand[0].type == OPT_REG
8189 && po->operand[0].reg == xST0;
8191 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8193 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
8194 float_st0, float_st0, buf1, buf1);
8195 strcat(g_comment, " fxch");
8202 ferr_assert(po, po->flags & OPF_32BIT);
8203 fprintf(fout, " eax = (s32)%s;", float_st0);
8204 if (po->flags & OPF_FSHIFT) {
8205 if (need_float_stack)
8206 fprintf(fout, " f_stp++;");
8208 fprintf(fout, " f_st0 = f_st1;");
8210 strcat(g_comment, " ftol");
8214 if (need_float_stack) {
8215 fprintf(fout, " %s = pow%s(%s, %s);", float_st1,
8216 need_double ? "" : "f", float_st1, float_st0);
8217 fprintf(fout, " f_stp++;");
8220 fprintf(fout, " f_st0 = pow%s(f_st1, f_st0);",
8221 need_double ? "" : "f");
8223 strcat(g_comment, " CIpow");
8227 fprintf(fout, " do_skip_code_abort();");
8232 fprintf(fout, " do_emms();");
8237 ferr(po, "unhandled op type %d, flags %x\n",
8242 if (g_comment[0] != 0) {
8243 char *p = g_comment;
8244 while (my_isblank(*p))
8246 fprintf(fout, " // %s", p);
8251 fprintf(fout, "\n");
8253 // some sanity checking
8254 if (po->flags & OPF_REP) {
8255 if (po->op != OP_STOS && po->op != OP_MOVS
8256 && po->op != OP_CMPS && po->op != OP_SCAS)
8257 ferr(po, "unexpected rep\n");
8258 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
8259 && (po->op == OP_CMPS || po->op == OP_SCAS))
8260 ferr(po, "cmps/scas with plain rep\n");
8262 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
8263 && po->op != OP_CMPS && po->op != OP_SCAS)
8264 ferr(po, "unexpected repz/repnz\n");
8267 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
8269 if ((po->flags & OPF_LOCK) && !lock_handled)
8270 ferr(po, "unhandled lock\n");
8272 // see is delayed flag stuff is still valid
8273 if (delayed_flag_op != NULL && delayed_flag_op != po) {
8274 if (is_any_opr_modified(delayed_flag_op, po, 0))
8275 delayed_flag_op = NULL;
8278 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
8279 if (is_opr_modified(last_arith_dst, po))
8280 last_arith_dst = NULL;
8287 if (g_stack_fsz && !g_stack_frame_used)
8288 fprintf(fout, " (void)sf;\n");
8290 fprintf(fout, "}\n\n");
8292 gen_x_cleanup(opcnt);
8295 static void gen_x_cleanup(int opcnt)
8299 for (i = 0; i < opcnt; i++) {
8300 struct label_ref *lr, *lr_del;
8302 lr = g_label_refs[i].next;
8303 while (lr != NULL) {
8308 g_label_refs[i].i = -1;
8309 g_label_refs[i].next = NULL;
8311 if (ops[i].op == OP_CALL) {
8313 proto_release(ops[i].pp);
8319 struct func_proto_dep;
8321 struct func_prototype {
8325 int regmask_dep; // likely register args
8326 int regmask_use; // used registers
8327 int has_ret:3; // -1, 0, 1: unresolved, no, yes
8328 unsigned int has_ret64:1;
8329 unsigned int dep_resolved:1;
8330 unsigned int is_stdcall:1;
8331 unsigned int eax_pass:1; // returns without touching eax
8332 struct func_proto_dep *dep_func;
8334 const struct parsed_proto *pp; // seed pp, if any
8337 struct func_proto_dep {
8339 struct func_prototype *proto;
8340 int regmask_live; // .. at the time of call
8341 unsigned int ret_dep:1; // return from this is caller's return
8342 unsigned int has_ret:1; // found from eax use after return
8343 unsigned int has_ret64:1;
8346 static struct func_prototype *hg_fp;
8347 static int hg_fp_cnt;
8349 static struct scanned_var {
8351 enum opr_lenmod lmod;
8352 unsigned int is_seeded:1;
8353 unsigned int is_c_str:1;
8354 const struct parsed_proto *pp; // seed pp, if any
8356 static int hg_var_cnt;
8358 static char **hg_refs;
8359 static int hg_ref_cnt;
8361 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8364 static struct func_prototype *hg_fp_add(const char *funcn)
8366 struct func_prototype *fp;
8368 if ((hg_fp_cnt & 0xff) == 0) {
8369 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
8370 my_assert_not(hg_fp, NULL);
8371 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
8374 fp = &hg_fp[hg_fp_cnt];
8375 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
8377 fp->argc_stack = -1;
8383 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
8388 for (i = 0; i < fp->dep_func_cnt; i++)
8389 if (IS(fp->dep_func[i].name, name))
8390 return &fp->dep_func[i];
8395 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
8398 if (hg_fp_find_dep(fp, name))
8401 if ((fp->dep_func_cnt & 0xff) == 0) {
8402 fp->dep_func = realloc(fp->dep_func,
8403 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
8404 my_assert_not(fp->dep_func, NULL);
8405 memset(&fp->dep_func[fp->dep_func_cnt], 0,
8406 sizeof(fp->dep_func[0]) * 0x100);
8408 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
8412 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
8414 const struct func_prototype *p1 = p1_, *p2 = p2_;
8415 return strcmp(p1->name, p2->name);
8419 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
8421 const struct func_prototype *p1 = p1_, *p2 = p2_;
8422 return p1->id - p2->id;
8426 static void hg_ref_add(const char *name)
8428 if ((hg_ref_cnt & 0xff) == 0) {
8429 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
8430 my_assert_not(hg_refs, NULL);
8431 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
8434 hg_refs[hg_ref_cnt] = strdup(name);
8435 my_assert_not(hg_refs[hg_ref_cnt], NULL);
8439 // recursive register dep pass
8440 // - track saved regs (part 2)
8441 // - try to figure out arg-regs
8442 // - calculate reg deps
8443 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
8444 struct func_prototype *fp, int regmask_save, int regmask_dst,
8445 int *regmask_dep, int *regmask_use, int *has_ret)
8447 struct func_proto_dep *dep;
8448 struct parsed_op *po;
8449 int from_caller = 0;
8454 for (; i < opcnt; i++)
8456 if (cbits[i >> 3] & (1 << (i & 7)))
8458 cbits[i >> 3] |= (1 << (i & 7));
8462 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
8463 if (po->flags & OPF_RMD)
8466 if (po->btj != NULL) {
8468 for (j = 0; j < po->btj->count; j++) {
8469 check_i(po, po->btj->d[j].bt_i);
8470 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
8471 regmask_save, regmask_dst, regmask_dep, regmask_use,
8477 check_i(po, po->bt_i);
8478 if (po->flags & OPF_CJMP) {
8479 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
8480 regmask_save, regmask_dst, regmask_dep, regmask_use,
8489 if (po->flags & OPF_FARG)
8490 /* (just calculate register deps) */;
8491 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
8493 reg = po->operand[0].reg;
8494 ferr_assert(po, reg >= 0);
8496 if (po->flags & OPF_RSAVE) {
8497 regmask_save |= 1 << reg;
8500 if (po->flags & OPF_DONE)
8503 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0, 0);
8505 regmask_save |= 1 << reg;
8506 po->flags |= OPF_RMD;
8507 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, OPF_RMD);
8511 else if (po->flags & OPF_RMD)
8513 else if (po->op == OP_CALL) {
8514 po->regmask_dst |= 1 << xAX;
8516 dep = hg_fp_find_dep(fp, po->operand[0].name);
8518 dep->regmask_live = regmask_save | regmask_dst;
8519 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8520 dep->regmask_live |= 1 << xBP;
8523 else if (po->op == OP_RET) {
8524 if (po->operand_cnt > 0) {
8526 if (fp->argc_stack >= 0
8527 && fp->argc_stack != po->operand[0].val / 4)
8528 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
8529 fp->argc_stack = po->operand[0].val / 4;
8533 if (!fp->eax_pass && (po->flags & OPF_TAIL)) {
8534 if (po->op == OP_CALL) {
8539 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
8542 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
8545 if (ret != 1 && from_caller) {
8546 // unresolved eax - probably void func
8551 if (j >= 0 && ops[j].op == OP_CALL) {
8552 if (ops[j].pp != NULL && !ops[j].pp->is_unresolved) {
8553 int call_has_ret = !IS(ops[j].pp->ret_type.name, "void");
8554 if (ops[j].pp->is_noreturn) {
8555 // could be some fail path
8557 *has_ret = call_has_ret;
8560 *has_ret = call_has_ret;
8563 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
8575 l = regmask_save | regmask_dst;
8576 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8579 l = po->regmask_src & ~l;
8582 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
8583 l, regmask_dst, regmask_save, po->flags);
8586 *regmask_use |= (po->regmask_src | po->regmask_dst)
8588 regmask_dst |= po->regmask_dst;
8590 if (po->flags & OPF_TAIL) {
8591 if (!(po->flags & OPF_CC)) // not cond. tailcall
8597 static void gen_hdr(const char *funcn, int opcnt)
8599 unsigned char cbits[MAX_OPS / 8];
8600 const struct parsed_proto *pp_c;
8601 struct parsed_proto *pp;
8602 struct func_prototype *fp;
8603 struct func_proto_dep *dep;
8604 struct parsed_op *po;
8605 int regmask_dummy = 0;
8608 int max_bp_offset = 0;
8613 pp_c = proto_parse(g_fhdr, funcn, 1);
8615 // already in seed, will add to hg_fp later
8618 fp = hg_fp_add(funcn);
8620 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
8621 g_stack_frame_used = 0;
8625 // - resolve all branches
8626 // - parse calls with labels
8627 resolve_branches_parse_calls(opcnt);
8630 // - handle ebp/esp frame, remove ops related to it
8631 scan_prologue_epilogue(opcnt, NULL);
8634 // - remove dead labels
8636 for (i = 0; i < opcnt; i++)
8638 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8644 if (po->flags & (OPF_RMD|OPF_DONE))
8647 if (po->op == OP_CALL) {
8648 if (po->operand[0].type == OPT_LABEL)
8649 hg_fp_add_dep(fp, opr_name(po, 0));
8650 else if (po->pp != NULL)
8651 hg_fp_add_dep(fp, po->pp->name);
8656 // - handle push <const>/pop pairs
8657 for (i = 0; i < opcnt; i++)
8660 if (po->flags & (OPF_RMD|OPF_DONE))
8663 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
8664 scan_for_pop_const(i, opcnt, i + opcnt * 13);
8668 // - process trivial calls
8669 for (i = 0; i < opcnt; i++)
8672 if (po->flags & (OPF_RMD|OPF_DONE))
8675 if (po->op == OP_CALL)
8677 pp = process_call_early(i, opcnt, &j);
8679 if (!(po->flags & OPF_ATAIL))
8680 // since we know the args, try to collect them
8681 if (collect_call_args_early(i, pp, NULL, NULL) != 0)
8687 // commit esp adjust
8688 if (ops[j].op != OP_POP)
8689 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
8691 for (l = 0; l < pp->argc_stack; l++)
8692 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
8696 po->flags |= OPF_DONE;
8702 // - track saved regs (simple)
8704 for (i = 0; i < opcnt; i++)
8707 if (po->flags & (OPF_RMD|OPF_DONE))
8710 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
8711 && po->operand[0].reg != xCX)
8713 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
8715 // regmask_save |= 1 << po->operand[0].reg; // do it later
8716 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
8717 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
8720 else if (po->op == OP_CALL)
8722 pp = process_call(i, opcnt);
8724 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
8725 // since we know the args, collect them
8726 ret = collect_call_args(po, i, pp, ®mask_dummy,
8729 if (!(po->flags & OPF_TAIL)
8730 && po->operand[0].type == OPT_LABEL)
8732 dep = hg_fp_find_dep(fp, opr_name(po, 0));
8733 ferr_assert(po, dep != NULL);
8734 // treat al write as overwrite to avoid many false positives
8735 find_next_read_reg(i + 1, opcnt, xAX, OPLM_BYTE,
8736 i + opcnt * 25, &j);
8739 find_next_read_reg(i + 1, opcnt, xDX, OPLM_BYTE,
8740 i + opcnt * 26, &j);
8741 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j]))
8748 memset(cbits, 0, (opcnt + 7) / 8);
8749 regmask_dep = regmask_use = 0;
8752 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0,
8753 ®mask_dep, ®mask_use, &has_ret);
8755 // find unreachable code - must be fixed in IDA
8756 for (i = 0; i < opcnt; i++)
8758 if (cbits[i >> 3] & (1 << (i & 7)))
8761 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
8762 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
8764 // the compiler sometimes still generates code after
8765 // noreturn OS functions
8768 if (!(ops[i].flags & OPF_RMD)
8769 && ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
8771 ferr(&ops[i], "unreachable code\n");
8775 for (i = 0; i < g_eqcnt; i++) {
8776 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
8777 max_bp_offset = g_eqs[i].offset;
8780 if (fp->argc_stack < 0) {
8781 max_bp_offset = (max_bp_offset + 3) & ~3;
8782 fp->argc_stack = max_bp_offset / 4;
8783 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
8787 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
8788 fp->regmask_use = regmask_use;
8789 fp->has_ret = has_ret;
8791 printf("// has_ret %d, regmask_dep %x\n",
8792 fp->has_ret, fp->regmask_dep);
8793 output_hdr_fp(stdout, fp, 1);
8794 if (IS(funcn, "sub_10007F72")) exit(1);
8797 gen_x_cleanup(opcnt);
8800 static void hg_fp_resolve_deps(struct func_prototype *fp)
8802 struct func_prototype fp_s;
8803 struct func_proto_dep *dep;
8807 // this thing is recursive, so mark first..
8808 fp->dep_resolved = 1;
8810 for (i = 0; i < fp->dep_func_cnt; i++) {
8811 dep = &fp->dep_func[i];
8813 strcpy(fp_s.name, dep->name);
8814 dep->proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8815 sizeof(hg_fp[0]), hg_fp_cmp_name);
8816 if (dep->proto != NULL) {
8817 if (!dep->proto->dep_resolved)
8818 hg_fp_resolve_deps(dep->proto);
8820 regmask_dep = ~dep->regmask_live
8821 & dep->proto->regmask_dep;
8822 fp->regmask_dep |= regmask_dep;
8823 // printf("dep %s %s |= %x\n", fp->name,
8824 // fp->dep_func[i].name, regmask_dep);
8826 if (dep->has_ret && (dep->proto->regmask_use & mxAX))
8827 dep->proto->has_ret = 1;
8828 if (dep->has_ret64 && (dep->proto->regmask_use & mxDX))
8829 dep->proto->has_ret64 = 1;
8830 if (fp->has_ret == -1 && dep->ret_dep)
8831 fp->has_ret = dep->proto->has_ret;
8836 // make all thiscall/edx arg functions referenced from .data fastcall
8837 static void do_func_refs_from_data(void)
8839 struct func_prototype *fp, fp_s;
8842 for (i = 0; i < hg_ref_cnt; i++) {
8843 strcpy(fp_s.name, hg_refs[i]);
8844 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8845 sizeof(hg_fp[0]), hg_fp_cmp_name);
8849 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
8850 fp->regmask_dep |= mxCX | mxDX;
8854 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8857 const struct parsed_proto *pp;
8858 char *p, namebuf[NAMELEN];
8864 for (; count > 0; count--, fp++) {
8865 if (fp->has_ret == -1)
8866 fprintf(fout, "// ret unresolved\n");
8868 fprintf(fout, "// dep:");
8869 for (j = 0; j < fp->dep_func_cnt; j++) {
8870 fprintf(fout, " %s/", fp->dep_func[j].name);
8871 if (fp->dep_func[j].proto != NULL)
8872 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8873 fp->dep_func[j].proto->has_ret);
8875 fprintf(fout, "\n");
8878 p = strchr(fp->name, '@');
8880 memcpy(namebuf, fp->name, p - fp->name);
8881 namebuf[p - fp->name] = 0;
8889 pp = proto_parse(g_fhdr, name, 1);
8890 if (pp != NULL && pp->is_include)
8893 if (fp->pp != NULL) {
8894 // part of seed, output later
8898 regmask_dep = fp->regmask_dep;
8899 argc_normal = fp->argc_stack;
8901 fprintf(fout, "%-5s",
8902 fp->pp ? fp->pp->ret_type.name :
8903 fp->has_ret64 ? "__int64" :
8904 fp->has_ret ? "int" : "void");
8905 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
8906 && (regmask_dep & ~mxCX) == 0)
8908 fprintf(fout, "/*__thiscall*/ ");
8912 else if ((regmask_dep == (mxCX | mxDX)
8913 && (fp->is_stdcall || fp->argc_stack == 0))
8914 || (regmask_dep == mxCX && fp->argc_stack == 0))
8916 fprintf(fout, " __fastcall ");
8917 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8923 else if (regmask_dep && !fp->is_stdcall) {
8924 fprintf(fout, "/*__usercall*/ ");
8926 else if (regmask_dep) {
8927 fprintf(fout, "/*__userpurge*/ ");
8929 else if (fp->is_stdcall)
8930 fprintf(fout, " __stdcall ");
8932 fprintf(fout, " __cdecl ");
8934 fprintf(fout, "%s(", name);
8937 for (j = 0; j < xSP; j++) {
8938 if (regmask_dep & (1 << j)) {
8941 fprintf(fout, ", ");
8943 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8945 fprintf(fout, "int");
8946 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
8950 for (j = 0; j < argc_normal; j++) {
8953 fprintf(fout, ", ");
8954 if (fp->pp != NULL) {
8955 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8956 if (!fp->pp->arg[arg - 1].type.is_ptr)
8960 fprintf(fout, "int ");
8961 fprintf(fout, "a%d", arg);
8964 fprintf(fout, ");\n");
8968 static void output_hdr(FILE *fout)
8970 static const char *lmod_c_names[] = {
8971 [OPLM_UNSPEC] = "???",
8972 [OPLM_BYTE] = "uint8_t",
8973 [OPLM_WORD] = "uint16_t",
8974 [OPLM_DWORD] = "uint32_t",
8975 [OPLM_QWORD] = "uint64_t",
8977 const struct scanned_var *var;
8978 struct func_prototype *fp;
8979 char line[256] = { 0, };
8983 // add stuff from headers
8984 for (i = 0; i < pp_cache_size; i++) {
8985 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
8986 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
8988 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
8989 fp = hg_fp_add(name);
8990 fp->pp = &pp_cache[i];
8991 fp->argc_stack = fp->pp->argc_stack;
8992 fp->is_stdcall = fp->pp->is_stdcall;
8993 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
8994 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
8998 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
8999 for (i = 0; i < hg_fp_cnt; i++)
9000 hg_fp_resolve_deps(&hg_fp[i]);
9002 // adjust functions referenced from data segment
9003 do_func_refs_from_data();
9005 // final adjustments
9006 for (i = 0; i < hg_fp_cnt; i++) {
9007 if (hg_fp[i].eax_pass && (hg_fp[i].regmask_dep & mxAX))
9008 hg_fp[i].has_ret = 1;
9011 // note: messes up .proto ptr, don't use
9012 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
9015 for (i = 0; i < hg_var_cnt; i++) {
9018 if (var->pp != NULL)
9021 else if (var->is_c_str)
9022 fprintf(fout, "extern %-8s %s[];", "char", var->name);
9024 fprintf(fout, "extern %-8s %s;",
9025 lmod_c_names[var->lmod], var->name);
9028 fprintf(fout, " // seeded");
9029 fprintf(fout, "\n");
9032 fprintf(fout, "\n");
9034 // output function prototypes
9035 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
9038 fprintf(fout, "\n// - seed -\n");
9041 while (fgets(line, sizeof(line), g_fhdr))
9042 fwrite(line, 1, strlen(line), fout);
9045 // '=' needs special treatment
9047 static char *next_word_s(char *w, size_t wsize, char *s)
9054 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
9056 for (i = 1; i < wsize - 1; i++) {
9058 printf("warning: missing closing quote: \"%s\"\n", s);
9067 for (; i < wsize - 1; i++) {
9068 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
9074 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
9075 printf("warning: '%s' truncated\n", w);
9080 static int cmpstringp(const void *p1, const void *p2)
9082 return strcmp(*(char * const *)p1, *(char * const *)p2);
9085 static int is_xref_needed(char *p, char **rlist, int rlist_len)
9090 if (strstr(p, "..."))
9091 // unable to determine, assume needed
9094 if (*p == '.') // .text, .data, ...
9095 // ref from other data or non-function -> no
9098 p2 = strpbrk(p, "+:\r\n\x18");
9101 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9102 // referenced from removed code
9108 static int ida_xrefs_show_need(FILE *fasm, char *p,
9109 char **rlist, int rlist_len)
9115 p = strrchr(p, ';');
9116 if (p != NULL && *p == ';') {
9117 if (IS_START(p + 2, "sctref"))
9119 if (IS_START(p + 2, "DATA XREF: ")) {
9121 if (is_xref_needed(p, rlist, rlist_len))
9129 if (!my_fgets(line, sizeof(line), fasm))
9131 // non-first line is always indented
9132 if (!my_isblank(line[0]))
9135 // should be no content, just comment
9140 p = strrchr(p, ';');
9143 if (IS_START(p, "sctref")) {
9148 // it's printed once, but no harm to check again
9149 if (IS_START(p, "DATA XREF: "))
9152 if (is_xref_needed(p, rlist, rlist_len)) {
9157 fseek(fasm, pos, SEEK_SET);
9161 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
9163 struct scanned_var *var;
9164 char line[256] = { 0, };
9173 // skip to next data section
9174 while (my_fgets(line, sizeof(line), fasm))
9179 if (*p == 0 || *p == ';')
9182 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
9183 if (*p == 0 || *p == ';')
9186 if (*p != 's' || !IS_START(p, "segment para public"))
9192 if (p == NULL || !IS_START(p, "segment para public"))
9196 if (!IS_START(p, "'DATA'"))
9200 while (my_fgets(line, sizeof(line), fasm))
9205 no_identifier = my_isblank(*p);
9208 if (*p == 0 || *p == ';')
9211 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9212 words[wordc][0] = 0;
9213 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9214 if (*p == 0 || *p == ';') {
9220 if (wordc == 2 && IS(words[1], "ends"))
9225 if (no_identifier) {
9226 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
9227 hg_ref_add(words[2]);
9231 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
9232 // when this starts, we don't need anything from this section
9236 // check refs comment(s)
9237 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
9240 if ((hg_var_cnt & 0xff) == 0) {
9241 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
9242 * (hg_var_cnt + 0x100));
9243 my_assert_not(hg_vars, NULL);
9244 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
9247 var = &hg_vars[hg_var_cnt++];
9248 snprintf(var->name, sizeof(var->name), "%s", words[0]);
9250 // maybe already in seed header?
9251 var->pp = proto_parse(g_fhdr, var->name, 1);
9252 if (var->pp != NULL) {
9253 if (var->pp->is_fptr) {
9254 var->lmod = OPLM_DWORD;
9257 else if (var->pp->is_func)
9259 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
9260 aerr("unhandled C type '%s' for '%s'\n",
9261 var->pp->type.name, var->name);
9267 if (IS(words[1], "dd")) {
9268 var->lmod = OPLM_DWORD;
9269 if (wordc >= 4 && IS(words[2], "offset"))
9270 hg_ref_add(words[3]);
9272 else if (IS(words[1], "dw"))
9273 var->lmod = OPLM_WORD;
9274 else if (IS(words[1], "db")) {
9275 var->lmod = OPLM_BYTE;
9276 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
9277 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
9281 else if (IS(words[1], "dq"))
9282 var->lmod = OPLM_QWORD;
9283 //else if (IS(words[1], "dt"))
9285 aerr("type '%s' not known\n", words[1]);
9293 static void set_label(int i, const char *name)
9299 p = strchr(name, ':');
9303 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
9304 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
9305 g_labels[i] = realloc(g_labels[i], len + 1);
9306 my_assert_not(g_labels[i], NULL);
9307 memcpy(g_labels[i], name, len);
9308 g_labels[i][len] = 0;
9317 static struct chunk_item *func_chunks;
9318 static int func_chunk_cnt;
9319 static int func_chunk_alloc;
9321 static void add_func_chunk(FILE *fasm, const char *name, int line)
9323 if (func_chunk_cnt >= func_chunk_alloc) {
9324 func_chunk_alloc *= 2;
9325 func_chunks = realloc(func_chunks,
9326 func_chunk_alloc * sizeof(func_chunks[0]));
9327 my_assert_not(func_chunks, NULL);
9329 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
9330 func_chunks[func_chunk_cnt].name = strdup(name);
9331 func_chunks[func_chunk_cnt].asmln = line;
9335 static int cmp_chunks(const void *p1, const void *p2)
9337 const struct chunk_item *c1 = p1, *c2 = p2;
9338 return strcmp(c1->name, c2->name);
9341 static void scan_ahead_for_chunks(FILE *fasm)
9351 oldpos = ftell(fasm);
9354 while (my_fgets(line, sizeof(line), fasm))
9365 // get rid of random tabs
9366 for (i = 0; line[i] != 0; i++)
9367 if (line[i] == '\t')
9370 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9373 next_word(words[0], sizeof(words[0]), p);
9374 if (words[0][0] == 0)
9375 aerr("missing name for func chunk?\n");
9377 add_func_chunk(fasm, words[0], asmln);
9379 else if (IS_START(p, "; sctend"))
9385 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9386 words[wordc][0] = 0;
9387 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9388 if (*p == 0 || *p == ';') {
9394 if (wordc == 2 && IS(words[1], "ends"))
9398 fseek(fasm, oldpos, SEEK_SET);
9402 int main(int argc, char *argv[])
9404 FILE *fout, *fasm, *frlist;
9405 struct parsed_data *pd = NULL;
9407 char **rlist = NULL;
9409 int rlist_alloc = 0;
9410 int func_chunks_used = 0;
9411 int func_chunks_sorted = 0;
9412 int func_chunk_i = -1;
9413 long func_chunk_ret = 0;
9414 int func_chunk_ret_ln = 0;
9415 int scanned_ahead = 0;
9417 char words[20][256];
9418 enum opr_lenmod lmod;
9419 char *sctproto = NULL;
9421 int pending_endp = 0;
9423 int skip_code_end = 0;
9424 int skip_warned = 0;
9437 for (arg = 1; arg < argc; arg++) {
9438 if (IS(argv[arg], "-v"))
9440 else if (IS(argv[arg], "-rf"))
9441 g_allow_regfunc = 1;
9442 else if (IS(argv[arg], "-uc"))
9443 g_allow_user_icall = 1;
9444 else if (IS(argv[arg], "-m"))
9446 else if (IS(argv[arg], "-hdr"))
9447 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
9452 if (argc < arg + 3) {
9453 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
9454 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
9456 " -hdr - header generation mode\n"
9457 " -rf - allow unannotated indirect calls\n"
9458 " -uc - allow ind. calls/refs to __usercall\n"
9459 " -m - allow multiple .text sections\n"
9460 "[rlist] is a file with function names to skip,"
9468 asmfn = argv[arg++];
9469 fasm = fopen(asmfn, "r");
9470 my_assert_not(fasm, NULL);
9472 hdrfn = argv[arg++];
9473 g_fhdr = fopen(hdrfn, "r");
9474 my_assert_not(g_fhdr, NULL);
9477 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
9478 my_assert_not(rlist, NULL);
9479 // needs special handling..
9480 rlist[rlist_len++] = "__alloca_probe";
9482 func_chunk_alloc = 32;
9483 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
9484 my_assert_not(func_chunks, NULL);
9486 memset(words, 0, sizeof(words));
9488 for (; arg < argc; arg++) {
9491 frlist = fopen(argv[arg], "r");
9492 my_assert_not(frlist, NULL);
9494 while (my_fgets(line, sizeof(line), frlist)) {
9496 if (*p == 0 || *p == ';')
9499 if (IS_START(p, "#if 0")
9500 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
9504 else if (IS_START(p, "#endif"))
9511 p = next_word(words[0], sizeof(words[0]), p);
9512 if (words[0][0] == 0)
9515 if (rlist_len >= rlist_alloc) {
9516 rlist_alloc = rlist_alloc * 2 + 64;
9517 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
9518 my_assert_not(rlist, NULL);
9520 rlist[rlist_len++] = strdup(words[0]);
9528 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
9530 fout = fopen(argv[arg_out], "w");
9531 my_assert_not(fout, NULL);
9534 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
9535 my_assert_not(g_eqs, NULL);
9537 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
9538 g_label_refs[i].i = -1;
9539 g_label_refs[i].next = NULL;
9543 scan_variables(fasm, rlist, rlist_len);
9545 while (my_fgets(line, sizeof(line), fasm))
9554 // get rid of random tabs
9555 for (i = 0; line[i] != 0; i++)
9556 if (line[i] == '\t')
9561 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
9562 goto do_pending_endp; // eww..
9564 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
9566 static const char *attrs[] = {
9575 // parse IDA's attribute-list comment
9576 g_ida_func_attr = 0;
9579 for (; *p != 0; p = sskip(p)) {
9580 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9581 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9582 g_ida_func_attr |= 1 << i;
9583 p += strlen(attrs[i]);
9587 if (i == ARRAY_SIZE(attrs)) {
9588 anote("unparsed IDA attr: %s\n", p);
9591 if (IS(attrs[i], "fpd=")) {
9592 p = next_word(words[0], sizeof(words[0]), p);
9597 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
9599 static const char *attrs[] = {
9607 // parse manual attribute-list comment
9608 g_sct_func_attr = 0;
9611 for (; *p != 0; p = sskip(p)) {
9612 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9613 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9614 g_sct_func_attr |= 1 << i;
9615 p += strlen(attrs[i]);
9622 // clear_sf=start,len (in dwords)
9623 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
9624 &g_stack_clear_len, &j);
9626 // clear_regmask=<mask>
9627 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
9629 // rm_regmask=<mask>
9630 ret = sscanf(p, "=%x%n", &g_regmask_rm, &j) + 1;
9632 anote("unparsed attr value: %s\n", p);
9637 else if (i == ARRAY_SIZE(attrs)) {
9638 anote("unparsed sct attr: %s\n", p);
9643 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9646 next_word(words[0], sizeof(words[0]), p);
9647 if (words[0][0] == 0)
9648 aerr("missing name for func chunk?\n");
9650 if (!scanned_ahead) {
9651 add_func_chunk(fasm, words[0], asmln);
9652 func_chunks_sorted = 0;
9655 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
9657 if (func_chunk_i >= 0) {
9658 if (func_chunk_i < func_chunk_cnt
9659 && IS(func_chunks[func_chunk_i].name, g_func))
9661 // move on to next chunk
9662 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9664 aerr("seek failed for '%s' chunk #%d\n",
9665 g_func, func_chunk_i);
9666 asmln = func_chunks[func_chunk_i].asmln;
9670 if (func_chunk_ret == 0)
9671 aerr("no return from chunk?\n");
9672 fseek(fasm, func_chunk_ret, SEEK_SET);
9673 asmln = func_chunk_ret_ln;
9679 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
9680 func_chunks_used = 1;
9682 if (IS_START(g_func, "sub_")) {
9683 unsigned long addr = strtoul(p, NULL, 16);
9684 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
9685 if (addr > f_addr && !scanned_ahead) {
9686 //anote("scan_ahead caused by '%s', addr %lx\n",
9688 scan_ahead_for_chunks(fasm);
9690 func_chunks_sorted = 0;
9698 for (i = wordc; i < ARRAY_SIZE(words); i++)
9700 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9701 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9702 if (*p == 0 || *p == ';') {
9707 if (*p != 0 && *p != ';')
9708 aerr("too many words\n");
9710 if (skip_code_end) {
9715 // allow asm patches in comments
9717 // skip IDA's forced non-removable comment
9718 if (!IS_START(p, "; sct") && (p2 = strchr(p + 1, ';')))
9721 if (*p == ';' && IS_START(p, "; sct")) {
9722 if (IS_START(p, "; sctpatch:")) {
9724 if (*p == 0 || *p == ';')
9726 goto parse_words; // lame
9728 if (IS_START(p, "; sctproto:")) {
9729 sctproto = strdup(p + 11);
9731 else if (IS_START(p, "; sctend")) {
9736 else if (IS_START(p, "; sctskip_start")) {
9737 if (in_func && !g_skip_func) {
9739 ops[pi].op = OPP_ABORT;
9740 ops[pi].asmln = asmln;
9746 else if (IS_START(p, "; sctskip_end")) {
9754 awarn("wordc == 0?\n");
9758 // don't care about this:
9759 if (words[0][0] == '.'
9760 || IS(words[0], "include")
9761 || IS(words[0], "assume") || IS(words[1], "segment")
9762 || IS(words[0], "align"))
9768 // do delayed endp processing to collect switch jumptables
9770 if (in_func && !g_skip_func && !end && wordc >= 2
9771 && ((words[0][0] == 'd' && words[0][2] == 0)
9772 || (words[1][0] == 'd' && words[1][2] == 0)))
9775 if (words[1][0] == 'd' && words[1][2] == 0) {
9777 if (g_func_pd_cnt >= pd_alloc) {
9778 pd_alloc = pd_alloc * 2 + 16;
9779 g_func_pd = realloc(g_func_pd,
9780 sizeof(g_func_pd[0]) * pd_alloc);
9781 my_assert_not(g_func_pd, NULL);
9783 pd = &g_func_pd[g_func_pd_cnt];
9785 memset(pd, 0, sizeof(*pd));
9786 strcpy(pd->label, words[0]);
9787 pd->type = OPT_CONST;
9788 pd->lmod = lmod_from_directive(words[1]);
9794 anote("skipping alignment byte?\n");
9797 lmod = lmod_from_directive(words[0]);
9798 if (lmod != pd->lmod)
9799 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
9802 if (pd->count_alloc < pd->count + wordc) {
9803 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
9804 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
9805 my_assert_not(pd->d, NULL);
9807 for (; i < wordc; i++) {
9808 if (IS(words[i], "offset")) {
9809 pd->type = OPT_OFFSET;
9812 p = strchr(words[i], ',');
9815 if (pd->type == OPT_OFFSET)
9816 pd->d[pd->count].u.label = strdup(words[i]);
9818 pd->d[pd->count].u.val = parse_number(words[i], 0);
9819 pd->d[pd->count].bt_i = -1;
9825 if (in_func && !g_skip_func) {
9827 gen_hdr(g_func, pi);
9829 gen_func(fout, g_fhdr, g_func, pi);
9834 g_ida_func_attr = 0;
9835 g_sct_func_attr = 0;
9836 g_stack_clear_start = 0;
9837 g_stack_clear_len = 0;
9844 func_chunks_used = 0;
9847 memset(&ops, 0, pi * sizeof(ops[0]));
9852 for (i = 0; i < g_func_pd_cnt; i++) {
9854 if (pd->type == OPT_OFFSET) {
9855 for (j = 0; j < pd->count; j++)
9856 free(pd->d[j].u.label);
9871 if (IS(words[1], "proc")) {
9873 aerr("proc '%s' while in_func '%s'?\n",
9876 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9878 strcpy(g_func, words[0]);
9879 set_label(0, words[0]);
9884 if (IS(words[1], "endp"))
9887 aerr("endp '%s' while not in_func?\n", words[0]);
9888 if (!IS(g_func, words[0]))
9889 aerr("endp '%s' while in_func '%s'?\n",
9892 aerr("endp '%s' while skipping code\n", words[0]);
9894 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
9895 && ops[0].op == OP_JMP && ops[0].operand[0].segment)
9901 if (!g_skip_func && func_chunks_used) {
9902 // start processing chunks
9903 struct chunk_item *ci, key = { g_func, 0 };
9905 func_chunk_ret = ftell(fasm);
9906 func_chunk_ret_ln = asmln;
9907 if (!func_chunks_sorted) {
9908 qsort(func_chunks, func_chunk_cnt,
9909 sizeof(func_chunks[0]), cmp_chunks);
9910 func_chunks_sorted = 1;
9912 ci = bsearch(&key, func_chunks, func_chunk_cnt,
9913 sizeof(func_chunks[0]), cmp_chunks);
9915 aerr("'%s' needs chunks, but none found\n", g_func);
9916 func_chunk_i = ci - func_chunks;
9917 for (; func_chunk_i > 0; func_chunk_i--)
9918 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
9921 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9923 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
9924 asmln = func_chunks[func_chunk_i].asmln;
9932 if (wordc == 2 && IS(words[1], "ends")) {
9936 goto do_pending_endp;
9940 // scan for next text segment
9941 while (my_fgets(line, sizeof(line), fasm)) {
9944 if (*p == 0 || *p == ';')
9947 if (strstr(p, "segment para public 'CODE' use32"))
9954 p = strchr(words[0], ':');
9956 set_label(pi, words[0]);
9960 if (!in_func || g_skip_func || skip_code) {
9961 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
9963 anote("skipping from '%s'\n", g_labels[pi]);
9967 g_labels[pi] = NULL;
9971 if (wordc > 1 && IS(words[1], "="))
9974 aerr("unhandled equ, wc=%d\n", wordc);
9975 if (g_eqcnt >= eq_alloc) {
9977 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
9978 my_assert_not(g_eqs, NULL);
9981 len = strlen(words[0]);
9982 if (len > sizeof(g_eqs[0].name) - 1)
9983 aerr("equ name too long: %d\n", len);
9984 strcpy(g_eqs[g_eqcnt].name, words[0]);
9986 if (!IS(words[3], "ptr"))
9987 aerr("unhandled equ\n");
9988 if (IS(words[2], "dword"))
9989 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
9990 else if (IS(words[2], "word"))
9991 g_eqs[g_eqcnt].lmod = OPLM_WORD;
9992 else if (IS(words[2], "byte"))
9993 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
9994 else if (IS(words[2], "qword"))
9995 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
9997 aerr("bad lmod: '%s'\n", words[2]);
9999 g_eqs[g_eqcnt].offset = parse_number(words[4], 0);
10004 if (pi >= ARRAY_SIZE(ops))
10005 aerr("too many ops\n");
10007 parse_op(&ops[pi], words, wordc);
10009 ops[pi].datap = sctproto;
10024 // vim:ts=2:shiftwidth=2:expandtab