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;
3949 add_label_ref(&g_label_refs[l], i);
3955 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3958 if (po->operand[0].type == OPT_LABEL)
3962 ferr(po, "unhandled branch\n");
3966 po->flags |= OPF_TAIL;
3967 prev_op = i > 0 ? ops[i - 1].op : OP_UD2;
3968 if (prev_op == OP_POP)
3969 po->flags |= OPF_ATAIL;
3970 if (g_stack_fsz + g_bp_frame == 0 && prev_op != OP_PUSH
3971 && (g_func_pp == NULL || g_func_pp->argc_stack > 0))
3973 po->flags |= OPF_ATAIL;
3979 static int resolve_origin(int i, const struct parsed_opr *opr,
3980 int magic, int *op_i, int *is_caller);
3981 static void set_label(int i, const char *name);
3983 static void eliminate_seh_writes(int opcnt)
3985 const struct parsed_opr *opr;
3990 // assume all sf writes above g_seh_size to be seh related
3991 // (probably unsafe but oh well)
3992 for (i = 0; i < opcnt; i++) {
3993 if (ops[i].op != OP_MOV)
3995 opr = &ops[i].operand[0];
3996 if (opr->type != OPT_REGMEM)
3998 if (!is_stack_access(&ops[i], opr))
4002 parse_stack_access(&ops[i], opr->name, ofs_reg, &offset,
4004 if (offset < 0 && offset >= -g_seh_size)
4005 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4009 static void eliminate_seh_finally(int opcnt)
4011 const char *target_name = NULL;
4012 const char *return_name = NULL;
4013 int exits[MAX_EXITS];
4021 for (i = 0; i < opcnt; i++) {
4022 if (ops[i].op != OP_CALL)
4024 if (!IS_START(opr_name(&ops[i], 0), "loc_"))
4026 if (target_name != NULL)
4027 ferr(&ops[i], "multiple finally calls? (last was %s)\n",
4029 target_name = opr_name(&ops[i], 0);
4032 if (g_labels[i + 1] == NULL)
4033 set_label(i + 1, "seh_fin_done");
4034 return_name = g_labels[i + 1];
4042 // find finally code (bt_i is not set because it's call)
4043 for (i = 0; i < opcnt; i++) {
4044 if (g_labels[i] == NULL)
4046 if (!IS(g_labels[i], target_name))
4049 ferr_assert(&ops[i], target_i == -1);
4052 ferr_assert(&ops[0], target_i != -1);
4054 find_reachable_exits(target_i, opcnt, target_i + opcnt * 24,
4055 exits, &exit_count);
4056 ferr_assert(&ops[target_i], exit_count == 1);
4057 ferr_assert(&ops[target_i], ops[exits[0]].op == OP_RET);
4060 // convert to jumps, link
4061 ops[call_i].op = OP_JMP;
4062 ops[call_i].bt_i = target_i;
4063 add_label_ref(&g_label_refs[target_i], call_i);
4065 ops[tgend_i].op = OP_JMP;
4066 ops[tgend_i].flags &= ~OPF_TAIL;
4067 ops[tgend_i].flags |= OPF_JMP;
4068 ops[tgend_i].bt_i = return_i;
4069 ops[tgend_i].operand_cnt = 1;
4070 ops[tgend_i].operand[0].type = OPT_LABEL;
4071 snprintf(ops[tgend_i].operand[0].name, NAMELEN, "%s", return_name);
4072 add_label_ref(&g_label_refs[return_i], tgend_i);
4074 // rm seh finally entry code
4075 for (i = target_i - 1; i >= 0; i--) {
4076 if (g_labels[i] != NULL && g_label_refs[i].i != -1)
4078 if (ops[i].flags & OPF_CJMP)
4080 if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4083 for (i = target_i - 1; i >= 0; i--) {
4084 if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4086 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4090 static void eliminate_seh(int opcnt)
4094 for (i = 0; i < opcnt; i++) {
4095 if (ops[i].op != OP_MOV)
4097 if (ops[i].operand[0].segment != SEG_FS)
4099 if (!IS(opr_name(&ops[i], 0), "0"))
4102 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4103 if (ops[i].operand[1].reg == xSP) {
4104 for (j = i - 1; j >= 0; j--) {
4105 if (ops[j].op != OP_PUSH)
4107 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4109 if (ops[j].operand[0].val == ~0)
4111 if (ops[j].operand[0].type == OPT_REG) {
4113 ret = resolve_origin(j, &ops[j].operand[0],
4114 j + opcnt * 22, &k, NULL);
4116 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4120 ferr(ops, "missing seh terminator\n");
4124 ret = resolve_origin(i, &ops[i].operand[1],
4125 i + opcnt * 23, &k, NULL);
4127 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4131 eliminate_seh_writes(opcnt);
4132 eliminate_seh_finally(opcnt);
4135 static void eliminate_seh_calls(int opcnt)
4137 int epilog_found = 0;
4144 ferr_assert(&ops[i], ops[i].op == OP_PUSH
4145 && ops[i].operand[0].type == OPT_CONST);
4146 g_stack_fsz = g_seh_size + ops[i].operand[0].val;
4147 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4150 ferr_assert(&ops[i], ops[i].op == OP_PUSH
4151 && ops[i].operand[0].type == OPT_OFFSET);
4152 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4155 ferr_assert(&ops[i], ops[i].op == OP_CALL
4156 && IS(opr_name(&ops[i], 0), "__SEH_prolog"));
4157 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4159 for (i++; i < opcnt; i++) {
4160 if (ops[i].op != OP_CALL)
4162 if (!IS(opr_name(&ops[i], 0), "__SEH_epilog"))
4165 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4168 ferr_assert(ops, epilog_found);
4170 eliminate_seh_writes(opcnt);
4171 eliminate_seh_finally(opcnt);
4174 // check for prologue of many pushes and epilogue with pops
4175 static void check_simple_sequence(int opcnt, int *fsz)
4184 for (i = 0; i < opcnt && i < ARRAY_SIZE(seq); i++) {
4185 if (ops[i].op != OP_PUSH || ops[i].operand[0].type != OPT_REG)
4187 reg = ops[i].operand[0].reg;
4188 if (reg != xBX && reg != xSI && reg != xDI && reg != xBP)
4190 for (j = 0; j < i; j++)
4194 // probably something else is going on here
4202 for (; i < opcnt && seq_len > 0; i++) {
4203 if (!(ops[i].flags & OPF_TAIL))
4206 for (j = i - 1, seq_p = 0; j >= 0 && seq_p < seq_len; j--) {
4207 if (ops[j].op != OP_POP || ops[j].operand[0].type != OPT_REG)
4209 if (ops[j].operand[0].reg != seq[seq_p])
4213 found = seq_len = seq_p;
4218 for (i = 0; i < seq_len; i++)
4219 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4221 for (; i < opcnt && seq_len > 0; i++) {
4222 if (!(ops[i].flags & OPF_TAIL))
4225 for (j = i - 1, seq_p = 0; j >= 0 && seq_p < seq_len; j--) {
4226 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4231 // unlike pushes after sub esp,
4232 // IDA treats pushed like this as part of var area
4233 *fsz += seq_len * 4;
4236 static int scan_prologue(int i, int opcnt, int *ecx_push, int *esp_sub)
4241 for (; i < opcnt; i++)
4242 if (!(ops[i].flags & OPF_DONE))
4245 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4246 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4252 for (; i < opcnt; i++) {
4253 if (i > 0 && g_labels[i] != NULL)
4255 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
4257 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
4258 && ops[i].operand[1].type == OPT_CONST)
4260 g_stack_fsz += opr_const(&ops[i], 1);
4261 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4266 if (ops[i].op == OP_LEA && ops[i].operand[0].reg == xSP
4267 && ops[i].operand[1].type == OPT_REGMEM
4268 && IS_START(ops[i].operand[1].name, "esp-"))
4270 name = ops[i].operand[1].name;
4271 ret = sscanf(name, "esp-%x%n", &j, &len);
4272 ferr_assert(&ops[i], ret == 1 && len == strlen(name));
4274 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4279 if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
4280 && ops[i].operand[1].type == OPT_CONST)
4282 for (j = i + 1; j < opcnt; j++)
4283 if (!(ops[j].flags & OPF_DONE))
4285 if (ops[j].op == OP_CALL
4286 && IS(opr_name(&ops[j], 0), "__alloca_probe"))
4288 g_stack_fsz += opr_const(&ops[i], 1);
4289 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4290 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4301 static void scan_prologue_epilogue(int opcnt, int *stack_align)
4303 int ecx_push = 0, esp_sub = 0, pusha = 0;
4304 int sandard_epilogue;
4305 int found, ret, len;
4309 if (g_seh_found == 2) {
4310 eliminate_seh_calls(opcnt);
4314 eliminate_seh(opcnt);
4315 // ida treats seh as part of sf
4316 g_stack_fsz = g_seh_size;
4320 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
4321 && ops[1].op == OP_MOV
4322 && IS(opr_name(&ops[1], 0), "ebp")
4323 && IS(opr_name(&ops[1], 1), "esp"))
4326 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4327 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4329 for (i = 2; i < opcnt; i++)
4330 if (!(ops[i].flags & OPF_DONE))
4333 if (ops[i].op == OP_PUSHA) {
4334 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4339 if (ops[i].op == OP_AND && ops[i].operand[0].reg == xSP
4340 && ops[i].operand[1].type == OPT_CONST)
4342 l = ops[i].operand[1].val;
4344 if (j == -1 || (l >> j) != -1)
4345 ferr(&ops[i], "unhandled esp align: %x\n", l);
4346 if (stack_align != NULL)
4347 *stack_align = 1 << j;
4348 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4352 i = scan_prologue(i, opcnt, &ecx_push, &esp_sub);
4356 for (; i < opcnt; i++)
4357 if (ops[i].flags & OPF_TAIL)
4360 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4361 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4367 sandard_epilogue = 0;
4368 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
4370 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4371 // the standard epilogue is sometimes even used without a sf
4372 if (ops[j - 1].op == OP_MOV
4373 && IS(opr_name(&ops[j - 1], 0), "esp")
4374 && IS(opr_name(&ops[j - 1], 1), "ebp"))
4375 sandard_epilogue = 1;
4377 else if (ops[j].op == OP_LEAVE)
4379 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4380 sandard_epilogue = 1;
4382 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
4383 && ops[i].pp->is_noreturn)
4385 // on noreturn, msvc sometimes cleans stack, sometimes not
4390 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4391 ferr(&ops[j], "'pop ebp' expected\n");
4393 if (g_stack_fsz != 0 || sandard_epilogue) {
4394 if (ops[j].op == OP_LEAVE)
4396 else if (sandard_epilogue) // mov esp, ebp
4398 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4401 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4403 ferr(&ops[j], "esp restore expected\n");
4406 if (ecx_push && j >= 0 && ops[j].op == OP_POP
4407 && IS(opr_name(&ops[j], 0), "ecx"))
4409 ferr(&ops[j], "unexpected ecx pop\n");
4414 if (ops[j].op == OP_POPA)
4415 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4417 ferr(&ops[j], "popa expected\n");
4422 } while (i < opcnt);
4425 ferr(ops, "missing ebp epilogue\n");
4430 check_simple_sequence(opcnt, &push_fsz);
4431 i = scan_prologue(0, opcnt, &ecx_push, &esp_sub);
4433 if (ecx_push && !esp_sub) {
4434 // could actually be args for a call..
4435 for (; i < opcnt; i++)
4436 if (ops[i].op != OP_PUSH)
4439 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
4440 const struct parsed_proto *pp;
4441 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
4442 j = pp ? pp->argc_stack : 0;
4443 while (i > 0 && j > 0) {
4445 if (ops[i].op == OP_PUSH) {
4446 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
4451 ferr(&ops[i], "unhandled prologue\n");
4455 g_stack_fsz = g_seh_size;
4456 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4457 if (!(ops[i].flags & OPF_RMD))
4467 if (ecx_push || esp_sub)
4472 for (; i < opcnt; i++)
4473 if (ops[i].flags & OPF_TAIL)
4477 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4478 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4483 else if (i < opcnt && (ops[i].flags & OPF_ATAIL)) {
4484 // skip arg updates for arg-reuse tailcall
4485 for (; j >= 0; j--) {
4486 if (ops[j].op != OP_MOV)
4488 if (ops[j].operand[0].type != OPT_REGMEM)
4490 if (strstr(ops[j].operand[0].name, "arg_") == NULL)
4495 for (; j >= 0; j--) {
4496 if ((ops[j].flags & (OPF_RMD | OPF_DONE | OPF_NOREGS)) !=
4497 (OPF_RMD | OPF_DONE | OPF_NOREGS))
4501 if (ecx_push > 0 && !esp_sub) {
4502 for (l = 0; l < ecx_push && j >= 0; l++) {
4503 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
4505 else if (ops[j].op == OP_ADD
4506 && IS(opr_name(&ops[j], 0), "esp")
4507 && ops[j].operand[1].type == OPT_CONST)
4510 l += ops[j].operand[1].val / 4 - 1;
4515 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4518 if (l != ecx_push) {
4519 if (i < opcnt && ops[i].op == OP_CALL
4520 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4522 // noreturn tailcall with no epilogue
4527 ferr(&ops[j], "epilogue scan failed\n");
4534 if (ops[j].op == OP_ADD
4535 && IS(opr_name(&ops[j], 0), "esp")
4536 && ops[j].operand[1].type == OPT_CONST)
4538 if (ops[j].operand[1].val < g_stack_fsz)
4539 ferr(&ops[j], "esp adj is too low (need %d)\n", g_stack_fsz);
4541 ops[j].operand[1].val -= g_stack_fsz; // for stack arg scanner
4542 if (ops[j].operand[1].val == 0)
4543 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4546 else if (ops[j].op == OP_LEA && ops[j].operand[0].reg == xSP
4547 && ops[j].operand[1].type == OPT_REGMEM
4548 && IS_START(ops[j].operand[1].name, "esp+"))
4550 const char *name = ops[j].operand[1].name;
4551 ret = sscanf(name, "esp+%x%n", &l, &len);
4552 ferr_assert(&ops[j], ret == 1 && len == strlen(name));
4553 ferr_assert(&ops[j], l <= g_stack_fsz);
4554 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4557 else if (i < opcnt && ops[i].op == OP_CALL
4558 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4560 // noreturn tailcall with no epilogue
4564 ferr(&ops[j], "'add esp' expected\n");
4568 } while (i < opcnt);
4571 ferr(ops, "missing esp epilogue\n");
4574 if (g_stack_fsz != 0)
4575 // see check_simple_sequence
4576 g_stack_fsz += push_fsz;
4579 // find an instruction that changed opr before i op
4580 // *op_i must be set to -1 by the caller
4581 // *is_caller is set to 1 if one source is determined to be g_func arg
4582 // returns 1 if found, *op_i is then set to origin
4583 // returns -1 if multiple origins are found
4584 static int resolve_origin(int i, const struct parsed_opr *opr,
4585 int magic, int *op_i, int *is_caller)
4587 struct label_ref *lr;
4591 if (g_labels[i] != NULL) {
4592 lr = &g_label_refs[i];
4593 for (; lr != NULL; lr = lr->next) {
4594 check_i(&ops[i], lr->i);
4595 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4597 if (i > 0 && LAST_OP(i - 1))
4603 if (is_caller != NULL)
4608 if (ops[i].cc_scratch == magic)
4610 ops[i].cc_scratch = magic;
4612 if (!(ops[i].flags & OPF_DATA))
4614 if (!is_opr_modified(opr, &ops[i]))
4618 if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4629 // find an instruction that previously referenced opr
4630 // if multiple results are found - fail
4631 // *op_i must be set to -1 by the caller
4632 // returns 1 if found, *op_i is then set to referencer insn
4633 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4634 int magic, int *op_i)
4636 struct label_ref *lr;
4640 if (g_labels[i] != NULL) {
4641 lr = &g_label_refs[i];
4642 for (; lr != NULL; lr = lr->next) {
4643 check_i(&ops[i], lr->i);
4644 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4646 if (i > 0 && LAST_OP(i - 1))
4654 if (ops[i].cc_scratch == magic)
4656 ops[i].cc_scratch = magic;
4658 if (!is_opr_referenced(opr, &ops[i]))
4669 // adjust datap of all reachable 'op' insns when moving back
4670 // returns 1 if at least 1 op was found
4671 // returns -1 if path without an op was found
4672 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4674 struct label_ref *lr;
4677 if (ops[i].cc_scratch == magic)
4679 ops[i].cc_scratch = magic;
4682 if (g_labels[i] != NULL) {
4683 lr = &g_label_refs[i];
4684 for (; lr != NULL; lr = lr->next) {
4685 check_i(&ops[i], lr->i);
4686 ret |= adjust_prev_op(lr->i, op, magic, datap);
4688 if (i > 0 && LAST_OP(i - 1))
4696 if (ops[i].cc_scratch == magic)
4698 ops[i].cc_scratch = magic;
4700 if (ops[i].op != op)
4703 ops[i].datap = datap;
4708 // find next instruction that reads opr
4709 // *op_i must be set to -1 by the caller
4710 // on return, *op_i is set to first referencer insn
4711 // returns 1 if exactly 1 referencer is found
4712 static int find_next_read(int i, int opcnt,
4713 const struct parsed_opr *opr, int magic, int *op_i)
4715 struct parsed_op *po;
4718 for (; i < opcnt; i++)
4720 if (ops[i].cc_scratch == magic)
4722 ops[i].cc_scratch = magic;
4725 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4726 if (po->btj != NULL) {
4728 for (j = 0; j < po->btj->count; j++) {
4729 check_i(po, po->btj->d[j].bt_i);
4730 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4736 if (po->flags & OPF_RMD)
4738 check_i(po, po->bt_i);
4739 if (po->flags & OPF_CJMP) {
4740 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4749 if (!is_opr_read(opr, po)) {
4751 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4752 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4754 full_opr = po->operand[0].lmod >= opr->lmod;
4756 if (is_opr_modified(opr, po) && full_opr) {
4760 if (po->flags & OPF_TAIL)
4775 static int find_next_read_reg(int i, int opcnt, int reg,
4776 enum opr_lenmod lmod, int magic, int *op_i)
4778 struct parsed_opr opr = OPR_INIT(OPT_REG, lmod, reg);
4781 return find_next_read(i, opcnt, &opr, magic, op_i);
4784 // find next instruction that reads opr
4785 // *op_i must be set to -1 by the caller
4786 // on return, *op_i is set to first flag user insn
4787 // returns 1 if exactly 1 flag user is found
4788 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4790 struct parsed_op *po;
4793 for (; i < opcnt; i++)
4795 if (ops[i].cc_scratch == magic)
4797 ops[i].cc_scratch = magic;
4800 if (po->op == OP_CALL)
4802 if (po->flags & OPF_JMP) {
4803 if (po->btj != NULL) {
4805 for (j = 0; j < po->btj->count; j++) {
4806 check_i(po, po->btj->d[j].bt_i);
4807 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4813 if (po->flags & OPF_RMD)
4815 check_i(po, po->bt_i);
4816 if (po->flags & OPF_CJMP)
4823 if (!(po->flags & OPF_CC)) {
4824 if (po->flags & OPF_FLAGS)
4827 if (po->flags & OPF_TAIL)
4843 static int try_resolve_const(int i, const struct parsed_opr *opr,
4844 int magic, unsigned int *val)
4849 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4852 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4855 *val = ops[i].operand[1].val;
4862 static int resolve_used_bits(int i, int opcnt, int reg,
4863 int *mask, int *is_z_check)
4865 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4869 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4873 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4875 fnote(&ops[j], "(first read)\n");
4876 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4879 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4880 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4882 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4883 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4885 *mask = ops[j].operand[1].val;
4886 if (ops[j].operand[0].lmod == OPLM_BYTE
4887 && ops[j].operand[0].name[1] == 'h')
4891 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4894 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4896 *is_z_check = ops[k].pfo == PFO_Z;
4901 static const struct parsed_proto *resolve_deref(int i, int magic,
4902 struct parsed_opr *opr, int level)
4904 struct parsed_opr opr_s = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
4905 const struct parsed_proto *pp = NULL;
4906 int from_caller = 0;
4915 ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4916 if (ret != 2 || len != strlen(opr->name)) {
4917 ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4918 if (ret != 1 || len != strlen(opr->name))
4922 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4927 ret = resolve_origin(i, &opr_s, i + magic, &j, NULL);
4931 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4932 && strlen(ops[j].operand[1].name) == 3
4933 && ops[j].operand[0].lmod == OPLM_DWORD
4934 && ops[j].pp == NULL // no hint
4937 // allow one simple dereference (com/directx)
4938 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4939 ops[j].operand[1].name);
4943 ret = resolve_origin(j, &opr_s, j + magic, &k, NULL);
4948 if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
4951 if (ops[j].pp != NULL) {
4955 else if (ops[j].operand[1].type == OPT_REGMEM) {
4956 pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
4958 // maybe structure ptr in structure
4959 pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
4962 else if (ops[j].operand[1].type == OPT_LABEL)
4963 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4964 else if (ops[j].operand[1].type == OPT_REG) {
4967 ret = resolve_origin(j, &ops[j].operand[1], i + magic,
4969 if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
4970 for (k = 0; k < g_func_pp->argc; k++) {
4971 if (g_func_pp->arg[k].reg == NULL)
4973 if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
4974 pp = g_func_pp->arg[k].pp;
4983 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4985 ferr(&ops[j], "expected struct, got '%s %s'\n",
4986 pp->type.name, pp->name);
4990 return proto_lookup_struct(g_fhdr, pp->type.name, offset);
4993 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4994 int *pp_i, int *multi_src)
4996 const struct parsed_proto *pp = NULL;
4997 int search_advice = 0;
5002 switch (ops[i].operand[0].type) {
5004 // try to resolve struct member calls
5005 pp = resolve_deref(i, i + opcnt * 19, &ops[i].operand[0], 0);
5011 pp = try_recover_pp(&ops[i], &ops[i].operand[0],
5017 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
5025 static struct parsed_proto *process_call_early(int i, int opcnt,
5028 struct parsed_op *po = &ops[i];
5029 struct parsed_proto *pp;
5035 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
5039 // look for and make use of esp adjust
5041 if (!pp->is_stdcall && pp->argc_stack > 0)
5042 ret = scan_for_esp_adjust(i + 1, opcnt,
5043 pp->argc_stack * 4, &adj, &multipath, 0);
5045 if (pp->argc_stack > adj / 4)
5049 if (ops[ret].op == OP_POP) {
5050 for (j = 1; j < adj / 4; j++) {
5051 if (ops[ret + j].op != OP_POP
5052 || ops[ret + j].operand[0].reg != xCX)
5064 static struct parsed_proto *process_call(int i, int opcnt)
5066 struct parsed_op *po = &ops[i];
5067 const struct parsed_proto *pp_c;
5068 struct parsed_proto *pp;
5069 const char *tmpname;
5070 int call_i = -1, ref_i = -1;
5071 int adj = 0, multipath = 0;
5074 tmpname = opr_name(po, 0);
5079 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
5081 if (!pp_c->is_func && !pp_c->is_fptr)
5082 ferr(po, "call to non-func: %s\n", pp_c->name);
5083 pp = proto_clone(pp_c);
5084 my_assert_not(pp, NULL);
5086 // not resolved just to single func
5089 switch (po->operand[0].type) {
5091 // we resolved this call and no longer need the register
5092 po->regmask_src &= ~(1 << po->operand[0].reg);
5094 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
5095 && ops[call_i].operand[1].type == OPT_LABEL)
5097 // no other source users?
5098 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
5100 if (ret == 1 && call_i == ref_i) {
5101 // and nothing uses it after us?
5103 find_next_read(i + 1, opcnt, &po->operand[0],
5104 i + opcnt * 11, &ref_i);
5106 // then also don't need the source mov
5107 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
5119 pp = calloc(1, sizeof(*pp));
5120 my_assert_not(pp, NULL);
5123 ret = scan_for_esp_adjust(i + 1, opcnt,
5124 -1, &adj, &multipath, 0);
5125 if (ret < 0 || adj < 0) {
5126 if (!g_allow_regfunc)
5127 ferr(po, "non-__cdecl indirect call unhandled yet\n");
5128 pp->is_unresolved = 1;
5132 if (adj > ARRAY_SIZE(pp->arg))
5133 ferr(po, "esp adjust too large: %d\n", adj);
5134 pp->ret_type.name = strdup("int");
5135 pp->argc = pp->argc_stack = adj;
5136 for (arg = 0; arg < pp->argc; arg++)
5137 pp->arg[arg].type.name = strdup("int");
5142 // look for and make use of esp adjust
5145 if (!pp->is_stdcall && pp->argc_stack > 0) {
5146 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
5147 ret = scan_for_esp_adjust(i + 1, opcnt,
5148 adj_expect, &adj, &multipath, 0);
5151 if (pp->is_vararg) {
5152 if (adj / 4 < pp->argc_stack) {
5153 fnote(po, "(this call)\n");
5154 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
5155 adj, pp->argc_stack * 4);
5157 // modify pp to make it have varargs as normal args
5159 pp->argc += adj / 4 - pp->argc_stack;
5160 for (; arg < pp->argc; arg++) {
5161 pp->arg[arg].type.name = strdup("int");
5164 if (pp->argc > ARRAY_SIZE(pp->arg))
5165 ferr(po, "too many args for '%s'\n", tmpname);
5167 if (pp->argc_stack > adj / 4) {
5168 if (pp->is_noreturn)
5169 // assume no stack adjust was emited
5171 fnote(po, "(this call)\n");
5172 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
5173 tmpname, pp->argc_stack * 4, adj);
5176 scan_for_esp_adjust(i + 1, opcnt,
5177 pp->argc_stack * 4, &adj, &multipath, 1);
5179 else if (pp->is_vararg)
5180 ferr(po, "missing esp_adjust for vararg func '%s'\n",
5187 static void mark_float_arg(struct parsed_op *po,
5188 struct parsed_proto *pp, int arg, int *regmask_ffca)
5191 po->p_argnum = arg + 1;
5192 ferr_assert(po, pp->arg[arg].datap == NULL);
5193 pp->arg[arg].datap = po;
5194 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
5195 if (regmask_ffca != NULL)
5196 *regmask_ffca |= 1 << arg;
5199 static int check_for_stp(int i, int i_to)
5201 struct parsed_op *po;
5203 for (; i < i_to; i++) {
5205 if (po->op == OP_FST)
5207 if (g_labels[i] != NULL || (po->flags & OPF_JMP))
5209 if (po->op == OP_CALL || po->op == OP_PUSH || po->op == OP_POP)
5211 if (po->op == OP_ADD && po->operand[0].reg == xSP)
5218 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
5221 struct parsed_op *po;
5227 for (base_arg = 0; base_arg < pp->argc; base_arg++)
5228 if (pp->arg[base_arg].reg == NULL)
5231 for (j = i; j > 0; )
5233 ferr_assert(&ops[j], g_labels[j] == NULL);
5237 ferr_assert(po, po->op != OP_PUSH);
5238 if (po->op == OP_FST)
5240 if (po->operand[0].type != OPT_REGMEM)
5242 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
5245 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3)) {
5246 //ferr(po, "offset %d, %d args\n", offset, pp->argc_stack);
5250 arg = base_arg + offset / 4;
5251 mark_float_arg(po, pp, arg, regmask_ffca);
5253 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5254 && po->operand[1].type == OPT_CONST)
5256 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5261 for (arg = base_arg; arg < pp->argc; arg++) {
5262 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
5263 po = pp->arg[arg].datap;
5265 ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
5266 if (po->operand[0].lmod == OPLM_QWORD)
5273 static int collect_call_args_early(int i, struct parsed_proto *pp,
5274 int *regmask, int *regmask_ffca)
5276 struct parsed_op *po;
5281 for (arg = 0; arg < pp->argc; arg++)
5282 if (pp->arg[arg].reg == NULL)
5285 // first see if it can be easily done
5286 for (j = i; j > 0 && arg < pp->argc; )
5288 if (g_labels[j] != NULL)
5293 if (po->op == OP_CALL)
5295 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
5297 else if (po->op == OP_POP)
5299 else if (po->flags & OPF_CJMP)
5301 else if (po->op == OP_PUSH) {
5302 if (po->flags & (OPF_FARG|OPF_FARGNR))
5304 if (!g_header_mode) {
5305 ret = scan_for_mod(po, j + 1, i, 1);
5310 if (pp->arg[arg].type.is_va_list)
5314 for (arg++; arg < pp->argc; arg++)
5315 if (pp->arg[arg].reg == NULL)
5318 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5319 && po->operand[1].type == OPT_CONST)
5321 if (po->flags & (OPF_RMD|OPF_DONE))
5323 if (po->operand[1].val != pp->argc_stack * 4)
5324 ferr(po, "unexpected esp adjust: %d\n",
5325 po->operand[1].val * 4);
5326 ferr_assert(po, pp->argc - arg == pp->argc_stack);
5327 return collect_call_args_no_push(i, pp, regmask_ffca);
5335 for (arg = 0; arg < pp->argc; arg++)
5336 if (pp->arg[arg].reg == NULL)
5339 for (j = i; j > 0 && arg < pp->argc; )
5343 if (ops[j].op == OP_PUSH)
5345 ops[j].p_argnext = -1;
5346 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
5348 k = check_for_stp(j + 1, i);
5350 // push ecx; fstp dword ptr [esp]
5351 ret = parse_stack_esp_offset(&ops[k],
5352 ops[k].operand[0].name, &offset);
5353 if (ret == 0 && offset == 0) {
5354 if (!pp->arg[arg].type.is_float)
5355 ferr(&ops[i], "arg %d should be float\n", arg + 1);
5356 mark_float_arg(&ops[k], pp, arg, regmask_ffca);
5360 if (pp->arg[arg].datap == NULL) {
5361 pp->arg[arg].datap = &ops[j];
5362 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
5363 *regmask |= 1 << ops[j].operand[0].reg;
5366 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5367 ops[j].flags &= ~OPF_RSAVE;
5370 for (arg++; arg < pp->argc; arg++)
5371 if (pp->arg[arg].reg == NULL)
5379 static int sync_argnum(struct parsed_op *po, int argnum)
5381 struct parsed_op *po_tmp;
5383 // see if other branches don't have higher argnum
5384 for (po_tmp = po; po_tmp != NULL; ) {
5385 if (argnum < po_tmp->p_argnum)
5386 argnum = po_tmp->p_argnum;
5387 // note: p_argnext is active on current collect_call_args only
5388 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5391 // make all argnums consistent
5392 for (po_tmp = po; po_tmp != NULL; ) {
5393 if (po_tmp->p_argnum != 0)
5394 po_tmp->p_argnum = argnum;
5395 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5401 static int collect_call_args_r(struct parsed_op *po, int i,
5402 struct parsed_proto *pp, int *regmask, int *arg_grp,
5403 int arg, int argnum, int magic, int need_op_saving, int may_reuse)
5405 struct parsed_proto *pp_tmp;
5406 struct parsed_op *po_tmp;
5407 struct label_ref *lr;
5408 int need_to_save_current;
5409 int arg_grp_current = 0;
5410 int save_args_seen = 0;
5417 ferr(po, "dead label encountered\n");
5421 for (; arg < pp->argc; arg++, argnum++)
5422 if (pp->arg[arg].reg == NULL)
5424 magic = (magic & 0xffffff) | (arg << 24);
5426 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
5428 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
5429 if (ops[j].cc_scratch != magic) {
5430 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
5434 // ok: have already been here
5437 ops[j].cc_scratch = magic;
5439 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
5440 lr = &g_label_refs[j];
5441 if (lr->next != NULL)
5443 for (; lr->next; lr = lr->next) {
5444 check_i(&ops[j], lr->i);
5445 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5447 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5448 arg, argnum, magic, need_op_saving, may_reuse);
5453 check_i(&ops[j], lr->i);
5454 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5456 if (j > 0 && LAST_OP(j - 1)) {
5457 // follow last branch in reverse
5462 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5463 arg, argnum, magic, need_op_saving, may_reuse);
5469 if (ops[j].op == OP_CALL)
5471 if (pp->is_unresolved)
5476 ferr(po, "arg collect %d/%d hit unparsed call '%s'\n",
5477 arg, pp->argc, ops[j].operand[0].name);
5478 if (may_reuse && pp_tmp->argc_stack > 0)
5479 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
5480 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
5482 // esp adjust of 0 means we collected it before
5483 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
5484 && (ops[j].operand[1].type != OPT_CONST
5485 || ops[j].operand[1].val != 0))
5487 if (pp->is_unresolved)
5490 fnote(po, "(this call)\n");
5491 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
5492 arg, pp->argc, ops[j].operand[1].val);
5494 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
5496 if (pp->is_unresolved)
5499 fnote(po, "(this call)\n");
5500 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
5502 else if (ops[j].flags & OPF_CJMP)
5504 if (pp->is_unresolved)
5509 else if (ops[j].op == OP_PUSH
5510 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
5512 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
5515 ops[j].p_argnext = -1;
5516 po_tmp = pp->arg[arg].datap;
5518 ops[j].p_argnext = po_tmp - ops;
5519 pp->arg[arg].datap = &ops[j];
5521 argnum = sync_argnum(&ops[j], argnum);
5523 need_to_save_current = 0;
5525 if (ops[j].operand[0].type == OPT_REG)
5526 reg = ops[j].operand[0].reg;
5528 if (!need_op_saving) {
5529 ret = scan_for_mod(&ops[j], j + 1, i, 1);
5530 need_to_save_current = (ret >= 0);
5532 if (need_op_saving || need_to_save_current) {
5533 // mark this arg as one that needs operand saving
5534 pp->arg[arg].is_saved = 1;
5536 if (save_args_seen & (1 << (argnum - 1))) {
5539 if (arg_grp_current >= MAX_ARG_GRP)
5540 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
5544 else if (ops[j].p_argnum == 0)
5545 ops[j].flags |= OPF_RMD;
5547 // some PUSHes are reused by different calls on other branches,
5548 // but that can't happen if we didn't branch, so they
5549 // can be removed from future searches (handles nested calls)
5551 ops[j].flags |= OPF_FARGNR;
5553 ops[j].flags |= OPF_FARG;
5554 ops[j].flags &= ~OPF_RSAVE;
5556 // check for __VALIST
5557 if (!pp->is_unresolved && g_func_pp != NULL
5558 && pp->arg[arg].type.is_va_list)
5561 ret = resolve_origin(j, &ops[j].operand[0],
5562 magic + 1, &k, NULL);
5563 if (ret == 1 && k >= 0)
5565 if (ops[k].op == OP_LEA) {
5566 if (!g_func_pp->is_vararg)
5567 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
5570 snprintf(buf, sizeof(buf), "arg_%X",
5571 g_func_pp->argc_stack * 4);
5572 if (strstr(ops[k].operand[1].name, buf)
5573 || strstr(ops[k].operand[1].name, "arglist"))
5575 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
5576 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
5577 pp->arg[arg].is_saved = 0;
5581 ferr(&ops[k], "va_list arg detection failed\n");
5583 // check for va_list from g_func_pp arg too
5584 else if (ops[k].op == OP_MOV
5585 && is_stack_access(&ops[k], &ops[k].operand[1]))
5587 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5588 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5590 ops[k].flags |= OPF_RMD | OPF_DONE;
5591 ops[j].flags |= OPF_RMD;
5592 ops[j].p_argpass = ret + 1;
5593 pp->arg[arg].is_saved = 0;
5600 if (pp->arg[arg].is_saved) {
5601 ops[j].flags &= ~OPF_RMD;
5602 ops[j].p_argnum = argnum;
5605 // tracking reg usage
5607 *regmask |= 1 << reg;
5611 if (!pp->is_unresolved) {
5613 for (; arg < pp->argc; arg++, argnum++)
5614 if (pp->arg[arg].reg == NULL)
5617 magic = (magic & 0xffffff) | (arg << 24);
5620 if (ops[j].p_arggrp > arg_grp_current) {
5622 arg_grp_current = ops[j].p_arggrp;
5624 if (ops[j].p_argnum > 0)
5625 save_args_seen |= 1 << (ops[j].p_argnum - 1);
5628 if (arg < pp->argc) {
5629 ferr(po, "arg collect failed for '%s': %d/%d\n",
5630 pp->name, arg, pp->argc);
5634 if (arg_grp_current > *arg_grp)
5635 *arg_grp = arg_grp_current;
5640 static int collect_call_args(struct parsed_op *po, int i,
5641 struct parsed_proto *pp, int *regmask, int magic)
5643 // arg group is for cases when pushes for
5644 // multiple funcs are going on
5645 struct parsed_op *po_tmp;
5650 ret = collect_call_args_r(po, i, pp, regmask, &arg_grp,
5656 // propagate arg_grp
5657 for (a = 0; a < pp->argc; a++) {
5658 if (pp->arg[a].reg != NULL)
5661 po_tmp = pp->arg[a].datap;
5662 while (po_tmp != NULL) {
5663 po_tmp->p_arggrp = arg_grp;
5664 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5669 if (pp->is_unresolved) {
5671 pp->argc_stack += ret;
5672 for (a = 0; a < pp->argc; a++)
5673 if (pp->arg[a].type.name == NULL)
5674 pp->arg[a].type.name = strdup("int");
5680 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5681 int regmask_now, int *regmask,
5682 int regmask_save_now, int *regmask_save,
5683 int *regmask_init, int regmask_arg)
5685 struct parsed_op *po;
5693 for (; i < opcnt; i++)
5696 if (cbits[i >> 3] & (1 << (i & 7)))
5698 cbits[i >> 3] |= (1 << (i & 7));
5700 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5701 if (po->flags & (OPF_RMD|OPF_DONE))
5703 if (po->btj != NULL) {
5704 for (j = 0; j < po->btj->count; j++) {
5705 check_i(po, po->btj->d[j].bt_i);
5706 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5707 regmask_now, regmask, regmask_save_now, regmask_save,
5708 regmask_init, regmask_arg);
5713 check_i(po, po->bt_i);
5714 if (po->flags & OPF_CJMP)
5715 reg_use_pass(po->bt_i, opcnt, cbits,
5716 regmask_now, regmask, regmask_save_now, regmask_save,
5717 regmask_init, regmask_arg);
5723 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5724 && !g_func_pp->is_userstack
5725 && po->operand[0].type == OPT_REG)
5727 reg = po->operand[0].reg;
5728 ferr_assert(po, reg >= 0);
5731 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5732 if (regmask_now & (1 << reg)) {
5733 already_saved = regmask_save_now & (1 << reg);
5734 flags_set = OPF_RSAVE | OPF_DONE;
5737 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, 0);
5739 scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5740 reg, 0, 0, flags_set);
5743 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5745 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5750 ferr_assert(po, !already_saved);
5751 po->flags |= flags_set;
5753 if (regmask_now & (1 << reg)) {
5754 regmask_save_now |= (1 << reg);
5755 *regmask_save |= regmask_save_now;
5760 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5761 reg = po->operand[0].reg;
5762 ferr_assert(po, reg >= 0);
5764 if (regmask_save_now & (1 << reg))
5765 regmask_save_now &= ~(1 << reg);
5767 regmask_now &= ~(1 << reg);
5770 else if (po->op == OP_CALL) {
5771 if ((po->regmask_dst & (1 << xAX))
5772 && !(po->regmask_dst & (1 << xDX)))
5774 if (po->flags & OPF_TAIL)
5775 // don't need eax, will do "return f();" or "f(); return;"
5776 po->regmask_dst &= ~(1 << xAX);
5778 find_next_read_reg(i + 1, opcnt, xAX, OPLM_DWORD,
5779 i + opcnt * 17, &j);
5782 po->regmask_dst &= ~(1 << xAX);
5786 // not "full stack" mode and have something in stack
5787 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5788 ferr(po, "float stack is not empty on func call\n");
5791 if (po->flags & OPF_NOREGS)
5794 // if incomplete register is used, clear it on init to avoid
5795 // later use of uninitialized upper part in some situations
5796 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5797 && po->operand[0].lmod != OPLM_DWORD)
5799 reg = po->operand[0].reg;
5800 ferr_assert(po, reg >= 0);
5802 if (!(regmask_now & (1 << reg)))
5803 *regmask_init |= 1 << reg;
5806 regmask_op = po->regmask_src | po->regmask_dst;
5808 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5809 regmask_new &= ~(1 << xSP);
5810 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5811 regmask_new &= ~(1 << xBP);
5813 if (regmask_new != 0)
5814 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5816 if (regmask_op & (1 << xBP)) {
5817 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5818 if (po->regmask_dst & (1 << xBP))
5819 // compiler decided to drop bp frame and use ebp as scratch
5820 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5822 regmask_op &= ~(1 << xBP);
5826 if (po->flags & OPF_FPUSH) {
5827 if (regmask_now & mxST1)
5828 regmask_now |= mxSTa; // switch to "full stack" mode
5829 if (regmask_now & mxSTa)
5830 po->flags |= OPF_FSHIFT;
5831 if (!(regmask_now & mxST7_2)) {
5833 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5837 regmask_now |= regmask_op;
5838 *regmask |= regmask_now;
5841 if (po->flags & OPF_FPOPP) {
5842 if ((regmask_now & mxSTa) == 0)
5843 ferr(po, "float pop on empty stack?\n");
5844 if (regmask_now & mxST7_2)
5845 po->flags |= OPF_FSHIFT;
5846 if (!(regmask_now & mxST7_2))
5847 regmask_now &= ~mxST1_0;
5849 else if (po->flags & OPF_FPOP) {
5850 if ((regmask_now & mxSTa) == 0)
5851 ferr(po, "float pop on empty stack?\n");
5852 if (regmask_now & (mxST7_2 | mxST1))
5853 po->flags |= OPF_FSHIFT;
5854 if (!(regmask_now & mxST7_2)) {
5856 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5860 if (po->flags & OPF_TAIL) {
5861 if (!(regmask_now & mxST7_2)) {
5862 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5863 if (!(regmask_now & mxST0))
5864 ferr(po, "no st0 on float return, mask: %x\n",
5867 else if (regmask_now & mxST1_0)
5868 ferr(po, "float regs on tail: %x\n", regmask_now);
5871 // there is support for "conditional tailcall", sort of
5872 if (!(po->flags & OPF_CC))
5878 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5882 for (i = 0; i < pp->argc; i++)
5883 if (pp->arg[i].reg == NULL)
5887 memmove(&pp->arg[i + 1], &pp->arg[i],
5888 sizeof(pp->arg[0]) * pp->argc_stack);
5889 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5890 pp->arg[i].reg = strdup(reg);
5891 pp->arg[i].type.name = strdup("int");
5896 static void output_std_flag_z(FILE *fout, struct parsed_op *po,
5897 int *pfomask, const char *dst_opr_text)
5899 if (*pfomask & (1 << PFO_Z)) {
5900 fprintf(fout, "\n cond_z = (%s%s == 0);",
5901 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5902 *pfomask &= ~(1 << PFO_Z);
5906 static void output_std_flag_s(FILE *fout, struct parsed_op *po,
5907 int *pfomask, const char *dst_opr_text)
5909 if (*pfomask & (1 << PFO_S)) {
5910 fprintf(fout, "\n cond_s = (%s%s < 0);",
5911 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5912 *pfomask &= ~(1 << PFO_S);
5916 static void output_std_flags(FILE *fout, struct parsed_op *po,
5917 int *pfomask, const char *dst_opr_text)
5919 output_std_flag_z(fout, po, pfomask, dst_opr_text);
5920 output_std_flag_s(fout, po, pfomask, dst_opr_text);
5924 OPP_FORCE_NORETURN = (1 << 0),
5925 OPP_SIMPLE_ARGS = (1 << 1),
5926 OPP_ALIGN = (1 << 2),
5929 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
5932 const char *cconv = "";
5934 if (pp->is_fastcall)
5935 cconv = "__fastcall ";
5936 else if (pp->is_stdcall && pp->argc_reg == 0)
5937 cconv = "__stdcall ";
5939 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5941 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
5942 fprintf(fout, "noreturn ");
5945 static void output_pp(FILE *fout, const struct parsed_proto *pp,
5950 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5954 output_pp_attrs(fout, pp, flags);
5957 fprintf(fout, "%s", pp->name);
5962 for (i = 0; i < pp->argc; i++) {
5964 fprintf(fout, ", ");
5965 if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
5966 && !(flags & OPP_SIMPLE_ARGS))
5969 output_pp(fout, pp->arg[i].pp, 0);
5971 else if (pp->arg[i].type.is_retreg) {
5972 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
5975 fprintf(fout, "%s", pp->arg[i].type.name);
5977 fprintf(fout, " a%d", i + 1);
5980 if (pp->arg[i].type.is_64bit)
5983 if (pp->is_vararg) {
5985 fprintf(fout, ", ");
5986 fprintf(fout, "...");
5991 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
5997 snprintf(buf1, sizeof(buf1), "%d", grp);
5998 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
6003 static void gen_x_cleanup(int opcnt);
6005 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
6007 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
6008 struct parsed_opr *last_arith_dst = NULL;
6009 char buf1[256], buf2[256], buf3[256], cast[64];
6010 struct parsed_proto *pp, *pp_tmp;
6011 struct parsed_data *pd;
6012 int save_arg_vars[MAX_ARG_GRP] = { 0, };
6013 unsigned char cbits[MAX_OPS / 8];
6014 const char *float_type;
6015 const char *float_st0;
6016 const char *float_st1;
6017 int need_float_stack = 0;
6018 int need_float_sw = 0; // status word
6019 int need_tmp_var = 0;
6023 int label_pending = 0;
6024 int need_double = 0;
6025 int stack_align = 0;
6026 int stack_fsz_adj = 0;
6027 int lock_handled = 0;
6028 int regmask_save = 0; // used regs saved/restored in this func
6029 int regmask_arg; // regs from this function args (fastcall, etc)
6030 int regmask_ret; // regs needed on ret
6031 int regmask_now; // temp
6032 int regmask_init = 0; // regs that need zero initialization
6033 int regmask_pp = 0; // regs used in complex push-pop graph
6034 int regmask_ffca = 0; // float function call args
6035 int regmask = 0; // used regs
6045 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
6046 g_stack_frame_used = 0;
6048 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
6049 regmask_init = g_regmask_init;
6051 g_func_pp = proto_parse(fhdr, funcn, 0);
6052 if (g_func_pp == NULL)
6053 ferr(ops, "proto_parse failed for '%s'\n", funcn);
6055 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
6056 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
6059 // - resolve all branches
6060 // - parse calls with labels
6061 resolve_branches_parse_calls(opcnt);
6064 // - handle ebp/esp frame, remove ops related to it
6065 scan_prologue_epilogue(opcnt, &stack_align);
6067 // handle a case where sf size is unalignment, but is
6068 // placed in a way that elements are still aligned
6069 if (g_stack_fsz & 4) {
6070 for (i = 0; i < g_eqcnt; i++) {
6071 if (g_eqs[i].lmod != OPLM_QWORD)
6073 if (!(g_eqs[i].offset & 4)) {
6082 // - remove dead labels
6083 // - set regs needed at ret
6084 for (i = 0; i < opcnt; i++)
6086 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
6091 if (ops[i].op == OP_RET)
6092 ops[i].regmask_src |= regmask_ret;
6096 // - process trivial calls
6097 for (i = 0; i < opcnt; i++)
6100 if (po->flags & (OPF_RMD|OPF_DONE))
6103 if (po->op == OP_CALL)
6105 pp = process_call_early(i, opcnt, &j);
6107 if (!(po->flags & OPF_ATAIL)) {
6108 // since we know the args, try to collect them
6109 ret = collect_call_args_early(i, pp, ®mask, ®mask_ffca);
6117 // commit esp adjust
6118 if (ops[j].op != OP_POP)
6119 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
6121 for (l = 0; l < pp->argc_stack; l++)
6122 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
6126 if (strstr(pp->ret_type.name, "int64"))
6129 po->flags |= OPF_DONE;
6135 // - process calls, stage 2
6136 // - handle some push/pop pairs
6137 // - scan for STD/CLD, propagate DF
6138 // - try to resolve needed x87 status word bits
6139 for (i = 0; i < opcnt; i++)
6144 if (po->flags & OPF_RMD)
6147 if (po->op == OP_CALL)
6149 if (!(po->flags & OPF_DONE)) {
6150 pp = process_call(i, opcnt);
6152 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
6153 // since we know the args, collect them
6154 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
6156 // for unresolved, collect after other passes
6160 ferr_assert(po, pp != NULL);
6162 po->regmask_src |= get_pp_arg_regmask_src(pp);
6163 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
6165 if (po->regmask_dst & mxST0)
6166 po->flags |= OPF_FPUSH;
6168 if (strstr(pp->ret_type.name, "int64"))
6174 if (po->flags & OPF_DONE)
6179 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
6180 && po->operand[0].type == OPT_CONST)
6182 scan_for_pop_const(i, opcnt, i + opcnt * 12);
6187 scan_pushes_for_pop(i, opcnt, ®mask_pp);
6191 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
6192 scan_propagate_df(i + 1, opcnt);
6197 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
6198 ferr(po, "TODO: fnstsw to mem\n");
6199 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
6201 ferr(po, "fnstsw resolve failed\n");
6202 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
6203 (void *)(long)(mask | (z_check << 16)));
6205 ferr(po, "failed to find fcom: %d\n", ret);
6214 // - find POPs for PUSHes, rm both
6215 // - scan for all used registers
6216 memset(cbits, 0, sizeof(cbits));
6217 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
6218 0, ®mask_save, ®mask_init, regmask_arg);
6220 need_float_stack = !!(regmask & mxST7_2);
6223 // - find flag set ops for their users
6224 // - do unresolved calls
6225 // - declare indirect functions
6226 // - other op specific processing
6227 for (i = 0; i < opcnt; i++)
6230 if (po->flags & (OPF_RMD|OPF_DONE))
6233 if (po->flags & OPF_CC)
6235 int setters[16], cnt = 0, branched = 0;
6237 ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
6238 &branched, setters, &cnt);
6239 if (ret < 0 || cnt <= 0)
6240 ferr(po, "unable to trace flag setter(s)\n");
6241 if (cnt > ARRAY_SIZE(setters))
6242 ferr(po, "too many flag setters\n");
6244 for (j = 0; j < cnt; j++)
6246 tmp_op = &ops[setters[j]]; // flag setter
6249 // to get nicer code, we try to delay test and cmp;
6250 // if we can't because of operand modification, or if we
6251 // have arith op, or branch, make it calculate flags explicitly
6252 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
6254 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
6255 pfomask = 1 << po->pfo;
6257 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
6258 pfomask = 1 << po->pfo;
6261 // see if we'll be able to handle based on op result
6262 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
6263 && po->pfo != PFO_Z && po->pfo != PFO_S
6264 && po->pfo != PFO_P)
6266 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
6268 pfomask = 1 << po->pfo;
6271 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
6272 propagate_lmod(tmp_op, &tmp_op->operand[0],
6273 &tmp_op->operand[1]);
6274 if (tmp_op->operand[0].lmod == OPLM_DWORD)
6279 tmp_op->pfomask |= pfomask;
6280 cond_vars |= pfomask;
6282 // note: may overwrite, currently not a problem
6286 if (po->op == OP_RCL || po->op == OP_RCR
6287 || po->op == OP_ADC || po->op == OP_SBB)
6288 cond_vars |= 1 << PFO_C;
6294 cond_vars |= 1 << PFO_Z;
6298 if (po->operand[0].lmod == OPLM_DWORD)
6303 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
6308 // note: resolved non-reg calls are OPF_DONE already
6310 ferr_assert(po, pp != NULL);
6312 if (pp->is_unresolved) {
6313 int regmask_stack = 0;
6314 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
6316 // this is pretty rough guess:
6317 // see ecx and edx were pushed (and not their saved versions)
6318 for (arg = 0; arg < pp->argc; arg++) {
6319 if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
6322 tmp_op = pp->arg[arg].datap;
6324 ferr(po, "parsed_op missing for arg%d\n", arg);
6325 if (tmp_op->operand[0].type == OPT_REG)
6326 regmask_stack |= 1 << tmp_op->operand[0].reg;
6329 if (!((regmask_stack & (1 << xCX))
6330 && (regmask_stack & (1 << xDX))))
6332 if (pp->argc_stack != 0
6333 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
6335 pp_insert_reg_arg(pp, "ecx");
6336 pp->is_fastcall = 1;
6337 regmask_init |= 1 << xCX;
6338 regmask |= 1 << xCX;
6340 if (pp->argc_stack != 0
6341 || ((regmask | regmask_arg) & (1 << xDX)))
6343 pp_insert_reg_arg(pp, "edx");
6344 regmask_init |= 1 << xDX;
6345 regmask |= 1 << xDX;
6349 // note: __cdecl doesn't fall into is_unresolved category
6350 if (pp->argc_stack > 0)
6353 if (!(po->flags & OPF_TAIL)
6354 && !(g_sct_func_attr & SCTFA_NOWARN))
6356 // treat al write as overwrite to avoid many false positives
6357 if (IS(pp->ret_type.name, "void") || pp->ret_type.is_float) {
6358 find_next_read_reg(i + 1, opcnt, xAX, OPLM_BYTE,
6359 i + opcnt * 25, &j);
6361 fnote(po, "eax used after void/float ret call\n");
6362 fnote(&ops[j], "(used here)\n");
6365 if (!strstr(pp->ret_type.name, "int64")) {
6366 find_next_read_reg(i + 1, opcnt, xDX, OPLM_BYTE,
6367 i + opcnt * 26, &j);
6368 // indirect calls are often guessed, don't warn
6369 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j])) {
6370 fnote(po, "edx used after 32bit ret call\n");
6371 fnote(&ops[j], "(used here)\n");
6375 // msvc often relies on callee not modifying 'this'
6376 for (arg = 0; arg < pp->argc; arg++) {
6377 if (pp->arg[arg].reg && IS(pp->arg[arg].reg, "ecx")) {
6383 find_next_read_reg(i + 1, opcnt, xCX, OPLM_BYTE,
6384 i + opcnt * 27, &j);
6385 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j])) {
6386 fnote(po, "ecx used after call\n");
6387 fnote(&ops[j], "(used here)\n");
6394 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
6396 // <var> = offset <something>
6397 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
6398 && !IS_START(po->operand[1].name, "off_"))
6400 if (!po->operand[0].pp->is_fptr)
6401 ferr(po, "%s not declared as fptr when it should be\n",
6402 po->operand[0].name);
6403 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
6404 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
6405 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
6406 fnote(po, "var: %s\n", buf1);
6407 fnote(po, "func: %s\n", buf2);
6408 ferr(po, "^ mismatch\n");
6416 if (po->operand[0].lmod == OPLM_DWORD) {
6417 // 32bit division is common, look for it
6418 if (po->op == OP_DIV)
6419 ret = scan_for_reg_clear(i, xDX);
6421 ret = scan_for_cdq_edx(i);
6423 po->flags |= OPF_32BIT;
6432 po->flags |= OPF_RMD | OPF_DONE;
6442 if (po->operand[0].lmod == OPLM_QWORD)
6453 find_next_read_reg(i + 1, opcnt, xDX, OPLM_DWORD,
6454 i + opcnt * 18, &j);
6456 po->flags |= OPF_32BIT;
6463 // this might need it's own pass...
6464 if (po->op != OP_FST && po->p_argnum > 0)
6465 save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
6467 // correct for "full stack" mode late enable
6468 if ((po->flags & (OPF_PPUSH|OPF_FPOP|OPF_FPOPP))
6469 && need_float_stack)
6470 po->flags |= OPF_FSHIFT;
6473 float_type = need_double ? "double" : "float";
6474 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
6475 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
6477 // output starts here
6480 fprintf(fout, "// had SEH\n");
6482 // define userstack size
6483 if (g_func_pp->is_userstack) {
6484 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
6485 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
6486 fprintf(fout, "#endif\n");
6489 // the function itself
6490 ferr_assert(ops, !g_func_pp->is_fptr);
6491 output_pp(fout, g_func_pp,
6492 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
6493 fprintf(fout, "\n{\n");
6495 // declare indirect functions
6496 for (i = 0; i < opcnt; i++) {
6498 if (po->flags & OPF_RMD)
6501 if (po->op == OP_CALL) {
6504 ferr(po, "NULL pp\n");
6506 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
6507 if (pp->name[0] != 0) {
6508 if (IS_START(pp->name, "guess"))
6511 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
6512 memcpy(pp->name, "i_", 2);
6514 // might be declared already
6516 for (j = 0; j < i; j++) {
6517 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
6518 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
6528 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
6531 output_pp(fout, pp, OPP_SIMPLE_ARGS);
6532 fprintf(fout, ";\n");
6537 // output LUTs/jumptables
6538 for (i = 0; i < g_func_pd_cnt; i++) {
6540 fprintf(fout, " static const ");
6541 if (pd->type == OPT_OFFSET) {
6542 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
6544 for (j = 0; j < pd->count; j++) {
6546 fprintf(fout, ", ");
6547 fprintf(fout, "&&%s", pd->d[j].u.label);
6551 fprintf(fout, "%s %s[] =\n { ",
6552 lmod_type_u(ops, pd->lmod), pd->label);
6554 for (j = 0; j < pd->count; j++) {
6556 fprintf(fout, ", ");
6557 fprintf(fout, "%u", pd->d[j].u.val);
6560 fprintf(fout, " };\n");
6564 // declare stack frame, va_arg
6567 fprintf(fout, " // stack_fsz_adj %d\n", stack_fsz_adj);
6569 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
6570 if (g_func_lmods & (1 << OPLM_WORD))
6571 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
6572 if (g_func_lmods & (1 << OPLM_BYTE))
6573 fprintf(fout, " u8 b[%d];", g_stack_fsz);
6574 if (g_func_lmods & (1 << OPLM_QWORD))
6575 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
6577 if (stack_align > 8)
6578 ferr(ops, "unhandled stack align of %d\n", stack_align);
6579 else if (stack_align == 8)
6580 fprintf(fout, " u64 align;");
6581 fprintf(fout, " } sf;\n");
6585 if ((g_sct_func_attr & SCTFA_ARGFRAME) && g_func_pp->argc_stack) {
6586 fprintf(fout, " struct { u32 ");
6587 for (i = j = 0; i < g_func_pp->argc; i++) {
6588 if (g_func_pp->arg[i].reg != NULL)
6591 fprintf(fout, ", ");
6592 fprintf(fout, "a%d", i + 1);
6594 fprintf(fout, "; } af = {\n ");
6595 for (i = j = 0; i < g_func_pp->argc; i++) {
6596 if (g_func_pp->arg[i].reg != NULL)
6599 fprintf(fout, ", ");
6600 if (g_func_pp->arg[i].type.is_ptr)
6601 fprintf(fout, "(u32)");
6602 fprintf(fout, "a%d", i + 1);
6604 fprintf(fout, "\n };\n");
6607 if (g_func_pp->is_userstack) {
6608 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
6609 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
6613 if (g_func_pp->is_vararg) {
6614 fprintf(fout, " va_list ap;\n");
6618 // declare arg-registers
6619 for (i = 0; i < g_func_pp->argc; i++) {
6620 if (g_func_pp->arg[i].reg != NULL) {
6621 reg = char_array_i(regs_r32,
6622 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
6623 if (regmask & (1 << reg)) {
6624 if (g_func_pp->arg[i].type.is_retreg)
6625 fprintf(fout, " u32 %s = *r_%s;\n",
6626 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
6628 fprintf(fout, " u32 %s = (u32)a%d;\n",
6629 g_func_pp->arg[i].reg, i + 1);
6632 if (g_func_pp->arg[i].type.is_retreg)
6633 ferr(ops, "retreg '%s' is unused?\n",
6634 g_func_pp->arg[i].reg);
6635 fprintf(fout, " // %s = a%d; // unused\n",
6636 g_func_pp->arg[i].reg, i + 1);
6642 // declare normal registers
6643 regmask_now = regmask & ~regmask_arg & ~g_regmask_rm;
6644 regmask_now &= ~(1 << xSP);
6645 if (regmask_now & 0x00ff) {
6646 for (reg = 0; reg < 8; reg++) {
6647 if (regmask_now & (1 << reg)) {
6648 fprintf(fout, " u32 %s", regs_r32[reg]);
6649 if (regmask_init & (1 << reg))
6650 fprintf(fout, " = 0");
6651 fprintf(fout, ";\n");
6657 if (regmask_now & 0xff00) {
6658 for (reg = 8; reg < 16; reg++) {
6659 if (regmask_now & (1 << reg)) {
6660 fprintf(fout, " mmxr %s", regs_r32[reg]);
6661 if (regmask_init & (1 << reg))
6662 fprintf(fout, " = { 0, }");
6663 fprintf(fout, ";\n");
6669 if (need_float_stack) {
6670 fprintf(fout, " %s f_st[8];\n", float_type);
6671 fprintf(fout, " int f_stp = 0;\n");
6675 if (regmask_now & 0xff0000) {
6676 for (reg = 16; reg < 24; reg++) {
6677 if (regmask_now & (1 << reg)) {
6678 fprintf(fout, " %s f_st%d", float_type, reg - 16);
6679 if (regmask_init & (1 << reg))
6680 fprintf(fout, " = 0");
6681 fprintf(fout, ";\n");
6688 if (need_float_sw) {
6689 fprintf(fout, " u16 f_sw;\n");
6694 for (reg = 0; reg < 8; reg++) {
6695 if (regmask_save & (1 << reg)) {
6696 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
6702 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6703 if (save_arg_vars[i] == 0)
6705 for (reg = 0; reg < 32; reg++) {
6706 if (save_arg_vars[i] & (1 << reg)) {
6707 fprintf(fout, " u32 %s;\n",
6708 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
6715 for (reg = 0; reg < 32; reg++) {
6716 if (regmask_ffca & (1 << reg)) {
6717 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
6723 // declare push-pop temporaries
6725 for (reg = 0; reg < 8; reg++) {
6726 if (regmask_pp & (1 << reg)) {
6727 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
6734 for (i = 0; i < 8; i++) {
6735 if (cond_vars & (1 << i)) {
6736 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
6743 fprintf(fout, " u32 tmp;\n");
6748 fprintf(fout, " u64 tmp64;\n");
6753 fprintf(fout, "\n");
6755 // do stack clear, if needed
6756 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6758 if (g_stack_clear_len != 0) {
6759 if (g_stack_clear_len <= 4) {
6760 for (i = 0; i < g_stack_clear_len; i++)
6761 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6762 fprintf(fout, "0;\n");
6765 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6766 g_stack_clear_start, g_stack_clear_len * 4);
6770 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6773 if (g_func_pp->is_vararg) {
6774 if (g_func_pp->argc_stack == 0)
6775 ferr(ops, "vararg func without stack args?\n");
6776 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
6780 for (i = 0; i < opcnt; i++)
6782 if (g_labels[i] != NULL) {
6783 fprintf(fout, "\n%s:\n", g_labels[i]);
6786 delayed_flag_op = NULL;
6787 last_arith_dst = NULL;
6791 if (po->flags & OPF_RMD)
6797 #define assert_operand_cnt(n_) \
6798 if (po->operand_cnt != n_) \
6799 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6801 // conditional/flag using op?
6802 if (po->flags & OPF_CC)
6808 // we go through all this trouble to avoid using parsed_flag_op,
6809 // which makes generated code much nicer
6810 if (delayed_flag_op != NULL)
6812 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6813 po->pfo, po->pfo_inv);
6816 else if (last_arith_dst != NULL
6817 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6818 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6821 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6822 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6823 last_arith_dst->lmod, buf3);
6826 else if (tmp_op != NULL) {
6827 // use preprocessed flag calc results
6828 if (!(tmp_op->pfomask & (1 << po->pfo)))
6829 ferr(po, "not prepared for pfo %d\n", po->pfo);
6831 // note: pfo_inv was not yet applied
6832 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6833 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6836 ferr(po, "all methods of finding comparison failed\n");
6839 if (po->flags & OPF_JMP) {
6840 fprintf(fout, " if %s", buf1);
6842 else if (po->op == OP_RCL || po->op == OP_RCR
6843 || po->op == OP_ADC || po->op == OP_SBB)
6846 fprintf(fout, " cond_%s = %s;\n",
6847 parsed_flag_op_names[po->pfo], buf1);
6849 else if (po->flags & OPF_DATA) { // SETcc
6850 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6851 fprintf(fout, " %s = %s;", buf2, buf1);
6854 ferr(po, "unhandled conditional op\n");
6858 pfomask = po->pfomask;
6863 assert_operand_cnt(2);
6864 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6865 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6866 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
6867 fprintf(fout, " %s = %s;", buf1,
6868 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6873 assert_operand_cnt(2);
6874 po->operand[1].lmod = OPLM_DWORD; // always
6875 fprintf(fout, " %s = %s;",
6876 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6877 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6882 assert_operand_cnt(2);
6883 fprintf(fout, " %s = %s;",
6884 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6885 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6889 assert_operand_cnt(2);
6890 switch (po->operand[1].lmod) {
6892 strcpy(buf3, "(s8)");
6895 strcpy(buf3, "(s16)");
6898 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6900 fprintf(fout, " %s = %s;",
6901 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6902 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6907 assert_operand_cnt(2);
6908 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6909 fprintf(fout, " tmp = %s;",
6910 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6911 fprintf(fout, " %s = %s;",
6912 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6913 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6914 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6915 fprintf(fout, " %s = %stmp;",
6916 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6917 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
6918 snprintf(g_comment, sizeof(g_comment), "xchg");
6922 assert_operand_cnt(1);
6923 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6924 fprintf(fout, " %s = ~%s;", buf1, buf1);
6928 assert_operand_cnt(2);
6929 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6930 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6931 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6932 strcpy(g_comment, "xlat");
6936 assert_operand_cnt(2);
6937 fprintf(fout, " %s = (s32)%s >> 31;",
6938 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6939 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6940 strcpy(g_comment, "cdq");
6944 assert_operand_cnt(1);
6945 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6946 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
6950 if (po->flags & OPF_REP) {
6951 assert_operand_cnt(3);
6956 assert_operand_cnt(2);
6957 fprintf(fout, " %s = %sesi; esi %c= %d;",
6958 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6959 lmod_cast_u_ptr(po, po->operand[1].lmod),
6960 (po->flags & OPF_DF) ? '-' : '+',
6961 lmod_bytes(po, po->operand[1].lmod));
6962 strcpy(g_comment, "lods");
6967 if (po->flags & OPF_REP) {
6968 assert_operand_cnt(3);
6969 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
6970 (po->flags & OPF_DF) ? '-' : '+',
6971 lmod_bytes(po, po->operand[1].lmod));
6972 fprintf(fout, " %sedi = eax;\n",
6973 lmod_cast_u_ptr(po, po->operand[1].lmod));
6974 fprintf(fout, " barrier();");
6975 strcpy(g_comment, "^ rep stos");
6978 assert_operand_cnt(2);
6979 fprintf(fout, " %sedi = eax; edi %c= %d;",
6980 lmod_cast_u_ptr(po, po->operand[1].lmod),
6981 (po->flags & OPF_DF) ? '-' : '+',
6982 lmod_bytes(po, po->operand[1].lmod));
6983 strcpy(g_comment, "stos");
6988 j = lmod_bytes(po, po->operand[0].lmod);
6989 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6990 l = (po->flags & OPF_DF) ? '-' : '+';
6991 if (po->flags & OPF_REP) {
6992 assert_operand_cnt(3);
6994 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
6997 " %sedi = %sesi;\n", buf1, buf1);
6998 // this can overwrite many variables
6999 fprintf(fout, " barrier();");
7000 strcpy(g_comment, "^ rep movs");
7003 assert_operand_cnt(2);
7004 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
7005 buf1, buf1, l, j, l, j);
7006 strcpy(g_comment, "movs");
7011 // repe ~ repeat while ZF=1
7012 j = lmod_bytes(po, po->operand[0].lmod);
7013 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
7014 l = (po->flags & OPF_DF) ? '-' : '+';
7015 if (po->flags & OPF_REP) {
7016 assert_operand_cnt(3);
7018 " while (ecx != 0) {\n");
7019 if (pfomask & (1 << PFO_C)) {
7022 " cond_c = %sesi < %sedi;\n", buf1, buf1);
7023 pfomask &= ~(1 << PFO_C);
7026 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
7027 buf1, buf1, l, j, l, j);
7030 " if (cond_z %s 0) break;\n",
7031 (po->flags & OPF_REPZ) ? "==" : "!=");
7034 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
7035 (po->flags & OPF_REPZ) ? "e" : "ne");
7038 assert_operand_cnt(2);
7040 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
7041 buf1, buf1, l, j, l, j);
7042 strcpy(g_comment, "cmps");
7044 pfomask &= ~(1 << PFO_Z);
7045 last_arith_dst = NULL;
7046 delayed_flag_op = NULL;
7050 // only does ZF (for now)
7051 // repe ~ repeat while ZF=1
7052 j = lmod_bytes(po, po->operand[1].lmod);
7053 l = (po->flags & OPF_DF) ? '-' : '+';
7054 if (po->flags & OPF_REP) {
7055 assert_operand_cnt(3);
7057 " while (ecx != 0) {\n");
7059 " cond_z = (%seax == %sedi); edi %c= %d;\n",
7060 lmod_cast_u(po, po->operand[1].lmod),
7061 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
7064 " if (cond_z %s 0) break;\n",
7065 (po->flags & OPF_REPZ) ? "==" : "!=");
7068 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
7069 (po->flags & OPF_REPZ) ? "e" : "ne");
7072 assert_operand_cnt(2);
7073 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
7074 lmod_cast_u(po, po->operand[1].lmod),
7075 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
7076 strcpy(g_comment, "scas");
7078 pfomask &= ~(1 << PFO_Z);
7079 last_arith_dst = NULL;
7080 delayed_flag_op = NULL;
7084 fprintf(fout, " tmp64 = ext_rdtsc();\n");
7085 fprintf(fout, " edx = tmp64 >> 32;\n");
7086 fprintf(fout, " eax = tmp64;");
7090 fprintf(fout, " ext_cpuid(&eax, &ebx, &ecx, &edx);");
7093 // arithmetic w/flags
7095 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
7096 goto dualop_arith_const;
7097 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7101 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7102 if (po->operand[1].type == OPT_CONST) {
7103 j = lmod_bytes(po, po->operand[0].lmod);
7104 if (((1ull << j * 8) - 1) == po->operand[1].val)
7105 goto dualop_arith_const;
7110 assert_operand_cnt(2);
7111 fprintf(fout, " %s %s= %s;",
7112 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7114 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7115 output_std_flags(fout, po, &pfomask, buf1);
7116 last_arith_dst = &po->operand[0];
7117 delayed_flag_op = NULL;
7121 // and 0, or ~0 used instead mov
7122 assert_operand_cnt(2);
7123 fprintf(fout, " %s = %s;",
7124 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7125 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
7126 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7127 output_std_flags(fout, po, &pfomask, buf1);
7128 last_arith_dst = &po->operand[0];
7129 delayed_flag_op = NULL;
7134 assert_operand_cnt(2);
7135 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7136 if (pfomask & (1 << PFO_C)) {
7137 if (po->operand[1].type == OPT_CONST) {
7138 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7139 j = po->operand[1].val;
7142 if (po->op == OP_SHL)
7146 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
7150 ferr(po, "zero shift?\n");
7154 pfomask &= ~(1 << PFO_C);
7156 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
7157 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7158 if (po->operand[1].type != OPT_CONST)
7159 fprintf(fout, " & 0x1f");
7161 output_std_flags(fout, po, &pfomask, buf1);
7162 last_arith_dst = &po->operand[0];
7163 delayed_flag_op = NULL;
7167 assert_operand_cnt(2);
7168 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7169 fprintf(fout, " %s = %s%s >> %s;", buf1,
7170 lmod_cast_s(po, po->operand[0].lmod), buf1,
7171 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7172 output_std_flags(fout, po, &pfomask, buf1);
7173 last_arith_dst = &po->operand[0];
7174 delayed_flag_op = NULL;
7179 assert_operand_cnt(3);
7180 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7181 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7182 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
7183 if (po->operand[2].type != OPT_CONST) {
7184 // no handling for "undefined" case, hopefully not needed
7185 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
7188 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7189 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7190 if (po->op == OP_SHLD) {
7191 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
7192 buf1, buf3, buf1, buf2, l, buf3);
7193 strcpy(g_comment, "shld");
7196 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
7197 buf1, buf3, buf1, buf2, l, buf3);
7198 strcpy(g_comment, "shrd");
7200 output_std_flags(fout, po, &pfomask, buf1);
7201 last_arith_dst = &po->operand[0];
7202 delayed_flag_op = NULL;
7207 assert_operand_cnt(2);
7208 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7209 if (po->operand[1].type == OPT_CONST) {
7210 j = po->operand[1].val;
7211 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
7212 fprintf(fout, po->op == OP_ROL ?
7213 " %s = (%s << %d) | (%s >> %d);" :
7214 " %s = (%s >> %d) | (%s << %d);",
7215 buf1, buf1, j, buf1,
7216 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
7220 output_std_flags(fout, po, &pfomask, buf1);
7221 last_arith_dst = &po->operand[0];
7222 delayed_flag_op = NULL;
7227 assert_operand_cnt(2);
7228 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7229 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7230 if (po->operand[1].type == OPT_CONST) {
7231 j = po->operand[1].val % l;
7233 ferr(po, "zero rotate\n");
7234 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
7235 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
7236 if (po->op == OP_RCL) {
7238 " %s = (%s << %d) | (cond_c << %d)",
7239 buf1, buf1, j, j - 1);
7241 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
7245 " %s = (%s >> %d) | (cond_c << %d)",
7246 buf1, buf1, j, l - j);
7248 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
7250 fprintf(fout, ";\n");
7251 fprintf(fout, " cond_c = tmp;");
7255 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
7256 output_std_flags(fout, po, &pfomask, buf1);
7257 last_arith_dst = &po->operand[0];
7258 delayed_flag_op = NULL;
7262 assert_operand_cnt(2);
7263 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7264 if (IS(opr_name(po, 0), opr_name(po, 1))) {
7265 // special case for XOR
7266 int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
7267 for (j = 0; j <= PFO_LE; j++) {
7268 if (pfomask & (1 << j)) {
7269 fprintf(fout, " cond_%s = %d;\n",
7270 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
7271 pfomask &= ~(1 << j);
7274 fprintf(fout, " %s = 0;",
7275 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7276 last_arith_dst = &po->operand[0];
7277 delayed_flag_op = NULL;
7283 assert_operand_cnt(2);
7284 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7285 if (pfomask & (1 << PFO_C)) {
7286 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7287 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7288 if (po->operand[0].lmod == OPLM_DWORD) {
7289 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
7290 fprintf(fout, " cond_c = tmp64 >> 32;\n");
7291 fprintf(fout, " %s = (u32)tmp64;",
7292 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7293 strcat(g_comment, " add64");
7296 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
7297 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
7298 fprintf(fout, " %s += %s;",
7299 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7302 pfomask &= ~(1 << PFO_C);
7303 output_std_flags(fout, po, &pfomask, buf1);
7304 last_arith_dst = &po->operand[0];
7305 delayed_flag_op = NULL;
7308 if (pfomask & (1 << PFO_LE)) {
7309 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
7310 fprintf(fout, " cond_%s = %s;\n",
7311 parsed_flag_op_names[PFO_LE], buf1);
7312 pfomask &= ~(1 << PFO_LE);
7317 assert_operand_cnt(2);
7318 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7319 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
7320 for (j = 0; j <= PFO_LE; j++) {
7321 if (!(pfomask & (1 << j)))
7323 if (j == PFO_Z || j == PFO_S)
7326 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7327 fprintf(fout, " cond_%s = %s;\n",
7328 parsed_flag_op_names[j], buf1);
7329 pfomask &= ~(1 << j);
7336 assert_operand_cnt(2);
7337 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7338 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7339 if (po->op == OP_SBB
7340 && IS(po->operand[0].name, po->operand[1].name))
7342 // avoid use of unitialized var
7343 fprintf(fout, " %s = -cond_c;", buf1);
7344 // carry remains what it was
7345 pfomask &= ~(1 << PFO_C);
7348 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
7349 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7351 output_std_flags(fout, po, &pfomask, buf1);
7352 last_arith_dst = &po->operand[0];
7353 delayed_flag_op = NULL;
7358 // on SKL, if src is 0, dst is left unchanged
7359 assert_operand_cnt(2);
7360 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7361 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7362 output_std_flag_z(fout, po, &pfomask, buf2);
7363 if (po->op == OP_BSF)
7364 snprintf(buf3, sizeof(buf3), "__builtin_ffs(%s) - 1", buf2);
7366 snprintf(buf3, sizeof(buf3), "31 - __builtin_clz(%s)", buf2);
7367 fprintf(fout, " if (%s) %s = %s;", buf2, buf1, buf3);
7368 last_arith_dst = &po->operand[0];
7369 delayed_flag_op = NULL;
7370 strcat(g_comment, po->op == OP_BSF ? " bsf" : " bsr");
7374 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
7375 for (j = 0; j <= PFO_LE; j++) {
7376 if (!(pfomask & (1 << j)))
7378 if (j == PFO_Z || j == PFO_S || j == PFO_C)
7381 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7382 fprintf(fout, " cond_%s = %s;\n",
7383 parsed_flag_op_names[j], buf1);
7384 pfomask &= ~(1 << j);
7390 if (pfomask & (1 << PFO_C))
7391 // carry is unaffected by inc/dec.. wtf?
7392 ferr(po, "carry propagation needed\n");
7394 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7395 if (po->operand[0].type == OPT_REG) {
7396 ferr_assert(po, !(po->flags & OPF_LOCK));
7397 strcpy(buf2, po->op == OP_INC ? "++" : "--");
7398 fprintf(fout, " %s%s;", buf1, buf2);
7400 else if (po->flags & OPF_LOCK) {
7401 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0], "", 1);
7402 fprintf(fout, " __sync_fetch_and_%s((%s *)(%s), 1);",
7403 po->op == OP_INC ? "add" : "sub",
7404 lmod_type_u(po, po->operand[0].lmod), buf2);
7405 strcat(g_comment, " lock");
7409 strcpy(buf2, po->op == OP_INC ? "+" : "-");
7410 fprintf(fout, " %s %s= 1;", buf1, buf2);
7412 output_std_flags(fout, po, &pfomask, buf1);
7413 last_arith_dst = &po->operand[0];
7414 delayed_flag_op = NULL;
7418 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7419 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
7420 fprintf(fout, " %s = -%s%s;", buf1,
7421 lmod_cast_s(po, po->operand[0].lmod), buf2);
7422 last_arith_dst = &po->operand[0];
7423 delayed_flag_op = NULL;
7424 if (pfomask & PFOB_C) {
7425 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
7428 output_std_flags(fout, po, &pfomask, buf1);
7432 if (po->operand_cnt == 2) {
7433 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7436 if (po->operand_cnt == 3)
7437 ferr(po, "TODO imul3\n");
7440 assert_operand_cnt(1);
7441 switch (po->operand[0].lmod) {
7443 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
7444 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
7445 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
7446 fprintf(fout, " edx = tmp64 >> 32;\n");
7447 fprintf(fout, " eax = tmp64;");
7450 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
7451 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
7452 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
7456 ferr(po, "TODO: unhandled mul type\n");
7459 last_arith_dst = NULL;
7460 delayed_flag_op = NULL;
7465 assert_operand_cnt(1);
7466 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7467 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
7468 po->op == OP_IDIV));
7469 switch (po->operand[0].lmod) {
7471 if (po->flags & OPF_32BIT)
7472 snprintf(buf2, sizeof(buf2), "%seax", cast);
7474 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7475 snprintf(buf2, sizeof(buf2), "%stmp64",
7476 (po->op == OP_IDIV) ? "(s64)" : "");
7478 if (po->operand[0].type == OPT_REG
7479 && po->operand[0].reg == xDX)
7481 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
7482 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
7485 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
7486 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
7490 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
7491 snprintf(buf2, sizeof(buf2), "%stmp",
7492 (po->op == OP_IDIV) ? "(s32)" : "");
7493 if (po->operand[0].type == OPT_REG
7494 && po->operand[0].reg == xDX)
7496 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
7498 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
7502 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
7504 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
7507 strcat(g_comment, " div16");
7510 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
7512 last_arith_dst = NULL;
7513 delayed_flag_op = NULL;
7518 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7520 for (j = 0; j < 8; j++) {
7521 if (pfomask & (1 << j)) {
7522 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
7523 fprintf(fout, " cond_%s = %s;",
7524 parsed_flag_op_names[j], buf1);
7531 last_arith_dst = NULL;
7532 delayed_flag_op = po;
7536 // SETcc - should already be handled
7539 // note: we reuse OP_Jcc for SETcc, only flags differ
7541 fprintf(fout, "\n goto %s;", po->operand[0].name);
7545 fprintf(fout, " if (ecx == 0)\n");
7546 fprintf(fout, " goto %s;", po->operand[0].name);
7547 strcat(g_comment, " jecxz");
7551 fprintf(fout, " if (--ecx != 0)\n");
7552 fprintf(fout, " goto %s;", po->operand[0].name);
7553 strcat(g_comment, " loop");
7557 assert_operand_cnt(1);
7558 last_arith_dst = NULL;
7559 delayed_flag_op = NULL;
7561 if (po->operand[0].type == OPT_REGMEM) {
7562 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
7565 ferr(po, "parse failure for jmp '%s'\n",
7566 po->operand[0].name);
7567 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
7570 else if (po->operand[0].type != OPT_LABEL)
7571 ferr(po, "unhandled jmp type\n");
7573 fprintf(fout, " goto %s;", po->operand[0].name);
7577 assert_operand_cnt(1);
7579 my_assert_not(pp, NULL);
7582 if (po->flags & OPF_CC) {
7583 // we treat conditional branch to another func
7584 // (yes such code exists..) as conditional tailcall
7586 fprintf(fout, " {\n");
7589 if (pp->is_fptr && !pp->is_arg) {
7590 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
7591 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7594 if (pp->is_fptr && (pp->is_unresolved || pp->is_guessed)) {
7595 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
7596 buf3, asmfn, po->asmln, pp->name);
7599 fprintf(fout, "%s", buf3);
7600 if (strstr(pp->ret_type.name, "int64")) {
7601 if (po->flags & OPF_TAIL)
7602 ferr(po, "int64 and tail?\n");
7603 fprintf(fout, "tmp64 = ");
7605 else if (!IS(pp->ret_type.name, "void")) {
7606 if (po->flags & OPF_TAIL) {
7607 if (regmask_ret & mxAX) {
7608 fprintf(fout, "return ");
7609 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
7610 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
7612 else if (regmask_ret & mxST0)
7613 ferr(po, "float tailcall\n");
7615 else if (po->regmask_dst & mxAX) {
7616 fprintf(fout, "eax = ");
7617 if (pp->ret_type.is_ptr)
7618 fprintf(fout, "(u32)");
7620 else if (po->regmask_dst & mxST0) {
7621 ferr_assert(po, po->flags & OPF_FPUSH);
7622 if (need_float_stack)
7623 fprintf(fout, "f_st[--f_stp & 7] = ");
7625 fprintf(fout, "f_st0 = ");
7629 if (pp->name[0] == 0)
7630 ferr(po, "missing pp->name\n");
7631 fprintf(fout, "%s%s(", pp->name,
7632 pp->has_structarg ? "_sa" : "");
7634 if (po->flags & OPF_ATAIL) {
7636 g_func_pp->is_stdcall && g_func_pp->argc_stack > 0;
7637 check_compat |= pp->argc_stack > 0;
7639 && (pp->argc_stack != g_func_pp->argc_stack
7640 || pp->is_stdcall != g_func_pp->is_stdcall))
7641 ferr(po, "incompatible arg-reuse tailcall\n");
7642 if (g_func_pp->has_retreg)
7643 ferr(po, "TODO: retreg+tailcall\n");
7645 for (arg = j = 0; arg < pp->argc; arg++) {
7647 fprintf(fout, ", ");
7650 if (pp->arg[arg].type.is_ptr)
7651 snprintf(cast, sizeof(cast), "(%s)",
7652 pp->arg[arg].type.name);
7654 if (pp->arg[arg].reg != NULL) {
7655 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7659 for (; j < g_func_pp->argc; j++)
7660 if (g_func_pp->arg[j].reg == NULL)
7662 fprintf(fout, "%sa%d", cast, j + 1);
7667 for (arg = 0; arg < pp->argc; arg++) {
7669 fprintf(fout, ", ");
7672 if (pp->arg[arg].type.is_ptr)
7673 snprintf(cast, sizeof(cast), "(%s)",
7674 pp->arg[arg].type.name);
7676 if (pp->arg[arg].reg != NULL) {
7677 if (pp->arg[arg].type.is_retreg)
7678 fprintf(fout, "&%s", pp->arg[arg].reg);
7679 else if (IS(pp->arg[arg].reg, "ebp")
7680 && g_bp_frame && !(po->flags & OPF_EBP_S))
7682 // rare special case
7683 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
7684 strcat(g_comment, " bp_ref");
7687 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7692 tmp_op = pp->arg[arg].datap;
7694 ferr(po, "parsed_op missing for arg%d\n", arg);
7696 if (tmp_op->flags & OPF_VAPUSH) {
7697 fprintf(fout, "ap");
7699 else if (tmp_op->op == OP_FST) {
7700 fprintf(fout, "fs_%d", tmp_op->p_argnum);
7701 if (tmp_op->operand[0].lmod == OPLM_QWORD)
7704 else if (pp->arg[arg].type.is_64bit) {
7705 ferr_assert(po, tmp_op->p_argpass == 0);
7706 ferr_assert(po, !pp->arg[arg].is_saved);
7707 ferr_assert(po, !pp->arg[arg].type.is_float);
7708 ferr_assert(po, cast[0] == 0);
7709 out_src_opr(buf1, sizeof(buf1),
7710 tmp_op, &tmp_op->operand[0], cast, 0);
7711 tmp_op = pp->arg[++arg].datap;
7712 ferr_assert(po, tmp_op != NULL);
7713 out_src_opr(buf2, sizeof(buf2),
7714 tmp_op, &tmp_op->operand[0], cast, 0);
7715 fprintf(fout, "((u64)(%s) << 32) | (%s)",
7718 else if (tmp_op->p_argpass != 0) {
7719 ferr_assert(po, !pp->arg[arg].type.is_float);
7720 fprintf(fout, "a%d", tmp_op->p_argpass);
7722 else if (pp->arg[arg].is_saved) {
7723 ferr_assert(po, tmp_op->p_argnum > 0);
7724 ferr_assert(po, !pp->arg[arg].type.is_float);
7725 fprintf(fout, "%s%s", cast,
7726 saved_arg_name(buf1, sizeof(buf1),
7727 tmp_op->p_arggrp, tmp_op->p_argnum));
7729 else if (pp->arg[arg].type.is_float) {
7730 ferr_assert(po, !pp->arg[arg].type.is_64bit);
7732 out_src_opr_float(buf1, sizeof(buf1),
7733 tmp_op, &tmp_op->operand[0], need_float_stack));
7737 out_src_opr(buf1, sizeof(buf1),
7738 tmp_op, &tmp_op->operand[0], cast, 0));
7742 fprintf(fout, ");");
7744 if (strstr(pp->ret_type.name, "int64")) {
7745 fprintf(fout, "\n");
7746 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7747 fprintf(fout, "%seax = tmp64;", buf3);
7750 if (pp->is_unresolved) {
7751 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
7753 strcat(g_comment, buf2);
7756 if (po->flags & OPF_TAIL) {
7758 if (i == opcnt - 1 || pp->is_noreturn)
7760 else if (IS(pp->ret_type.name, "void"))
7762 else if (!(regmask_ret & (1 << xAX)))
7764 // else already handled as 'return f()'
7767 fprintf(fout, "\n%sreturn;", buf3);
7768 strcat(g_comment, " ^ tailcall");
7771 strcat(g_comment, " tailcall");
7773 if ((regmask_ret & (1 << xAX))
7774 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7776 ferr(po, "int func -> void func tailcall?\n");
7779 if (pp->is_noreturn)
7780 strcat(g_comment, " noreturn");
7781 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7782 strcat(g_comment, " argframe");
7783 if (po->flags & OPF_CC)
7784 strcat(g_comment, " cond");
7786 if (po->flags & OPF_CC)
7787 fprintf(fout, "\n }");
7789 delayed_flag_op = NULL;
7790 last_arith_dst = NULL;
7794 if (g_func_pp->is_vararg)
7795 fprintf(fout, " va_end(ap);\n");
7796 if (g_func_pp->has_retreg) {
7797 for (arg = 0; arg < g_func_pp->argc; arg++)
7798 if (g_func_pp->arg[arg].type.is_retreg)
7799 fprintf(fout, " *r_%s = %s;\n",
7800 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7803 if (regmask_ret & mxST0) {
7804 fprintf(fout, " return %s;", float_st0);
7806 else if (!(regmask_ret & mxAX)) {
7807 if (i != opcnt - 1 || label_pending)
7808 fprintf(fout, " return;");
7810 else if (g_func_pp->ret_type.is_ptr) {
7811 fprintf(fout, " return (%s)eax;",
7812 g_func_pp->ret_type.name);
7814 else if (IS(g_func_pp->ret_type.name, "__int64"))
7815 fprintf(fout, " return ((u64)edx << 32) | eax;");
7817 fprintf(fout, " return eax;");
7819 last_arith_dst = NULL;
7820 delayed_flag_op = NULL;
7824 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7825 if (po->p_argnum != 0) {
7826 // special case - saved func arg
7827 fprintf(fout, " %s = %s;",
7828 saved_arg_name(buf2, sizeof(buf2),
7829 po->p_arggrp, po->p_argnum), buf1);
7832 else if (po->flags & OPF_RSAVE) {
7833 fprintf(fout, " s_%s = %s;", buf1, buf1);
7836 else if (po->flags & OPF_PPUSH) {
7838 ferr_assert(po, tmp_op != NULL);
7839 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7840 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7843 else if (g_func_pp->is_userstack) {
7844 fprintf(fout, " *(--esp) = %s;", buf1);
7847 if (!(g_ida_func_attr & IDAFA_NORETURN))
7848 ferr(po, "stray push encountered\n");
7853 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7854 if (po->flags & OPF_RSAVE) {
7855 fprintf(fout, " %s = s_%s;", buf1, buf1);
7858 else if (po->flags & OPF_PPUSH) {
7859 // push/pop graph / non-const
7860 ferr_assert(po, po->datap == NULL);
7861 fprintf(fout, " %s = pp_%s;", buf1, buf1);
7864 else if (po->datap != NULL) {
7867 fprintf(fout, " %s = %s;", buf1,
7868 out_src_opr(buf2, sizeof(buf2),
7869 tmp_op, &tmp_op->operand[0],
7870 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7873 else if (g_func_pp->is_userstack) {
7874 fprintf(fout, " %s = *esp++;", buf1);
7878 ferr(po, "stray pop encountered\n");
7888 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7889 fprintf(fout, " tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
7890 po->op == OPP_ALLSHL ? "<<" : ">>");
7891 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
7892 strcat(g_comment, po->op == OPP_ALLSHL
7893 ? " allshl" : " allshr");
7898 if (need_float_stack) {
7899 out_src_opr_float(buf1, sizeof(buf1),
7900 po, &po->operand[0], 1);
7901 if (po->regmask_src & mxSTa) {
7902 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7906 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
7909 if (po->flags & OPF_FSHIFT)
7910 fprintf(fout, " f_st1 = f_st0;");
7911 if (po->operand[0].type == OPT_REG
7912 && po->operand[0].reg == xST0)
7914 strcat(g_comment, " fld st");
7917 fprintf(fout, " f_st0 = %s;",
7918 out_src_opr_float(buf1, sizeof(buf1),
7919 po, &po->operand[0], 0));
7921 strcat(g_comment, " fld");
7925 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7926 lmod_cast(po, po->operand[0].lmod, 1), 0);
7927 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7928 if (need_float_stack) {
7929 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
7932 if (po->flags & OPF_FSHIFT)
7933 fprintf(fout, " f_st1 = f_st0;");
7934 fprintf(fout, " f_st0 = %s;", buf2);
7936 strcat(g_comment, " fild");
7940 if (need_float_stack)
7941 fprintf(fout, " f_st[--f_stp & 7] = ");
7943 if (po->flags & OPF_FSHIFT)
7944 fprintf(fout, " f_st1 = f_st0;");
7945 fprintf(fout, " f_st0 = ");
7947 switch (po->operand[0].val) {
7948 case X87_CONST_1: fprintf(fout, "1.0;"); break;
7949 case X87_CONST_L2T: fprintf(fout, "3.321928094887362;"); break;
7950 case X87_CONST_L2E: fprintf(fout, "M_LOG2E;"); break;
7951 case X87_CONST_PI: fprintf(fout, "M_PI;"); break;
7952 case X87_CONST_LG2: fprintf(fout, "0.301029995663981;"); break;
7953 case X87_CONST_LN2: fprintf(fout, "M_LN2;"); break;
7954 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
7955 default: ferr_assert(po, 0); break;
7960 if (po->flags & OPF_FARG) {
7961 // store to stack as func arg
7962 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7966 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7968 dead_dst = po->operand[0].type == OPT_REG
7969 && po->operand[0].reg == xST0;
7972 fprintf(fout, " %s = %s;", buf1, float_st0);
7973 if (po->flags & OPF_FSHIFT) {
7974 if (need_float_stack)
7975 fprintf(fout, " f_stp++;");
7977 fprintf(fout, " f_st0 = f_st1;");
7979 if (dead_dst && !(po->flags & OPF_FSHIFT))
7982 strcat(g_comment, " fst");
7986 fprintf(fout, " %s = %s%s;",
7987 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7988 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7989 if (po->flags & OPF_FSHIFT) {
7990 if (need_float_stack)
7991 fprintf(fout, " f_stp++;");
7993 fprintf(fout, " f_st0 = f_st1;");
7995 strcat(g_comment, " fist");
8002 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8004 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
8006 dead_dst = (po->flags & OPF_FPOP)
8007 && po->operand[0].type == OPT_REG
8008 && po->operand[0].reg == xST0;
8010 case OP_FADD: j = '+'; break;
8011 case OP_FDIV: j = '/'; break;
8012 case OP_FMUL: j = '*'; break;
8013 case OP_FSUB: j = '-'; break;
8014 default: j = 'x'; break;
8016 if (need_float_stack) {
8018 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
8019 if (po->flags & OPF_FSHIFT)
8020 fprintf(fout, " f_stp++;");
8023 if (po->flags & OPF_FSHIFT) {
8024 // note: assumes only 2 regs handled
8026 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
8028 fprintf(fout, " f_st0 = f_st1;");
8031 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
8033 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
8038 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8040 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
8042 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
8044 dead_dst = (po->flags & OPF_FPOP)
8045 && po->operand[0].type == OPT_REG
8046 && po->operand[0].reg == xST0;
8047 j = po->op == OP_FDIVR ? '/' : '-';
8048 if (need_float_stack) {
8050 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
8051 if (po->flags & OPF_FSHIFT)
8052 fprintf(fout, " f_stp++;");
8055 if (po->flags & OPF_FSHIFT) {
8057 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
8059 fprintf(fout, " f_st0 = f_st1;");
8062 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
8064 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
8072 case OP_FIADD: j = '+'; break;
8073 case OP_FIDIV: j = '/'; break;
8074 case OP_FIMUL: j = '*'; break;
8075 case OP_FISUB: j = '-'; break;
8076 default: j = 'x'; break;
8078 fprintf(fout, " %s %c= (%s)%s;", float_st0,
8080 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
8081 lmod_cast(po, po->operand[0].lmod, 1), 0));
8086 fprintf(fout, " %s = %s %c %s;", float_st0,
8087 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
8089 po->op == OP_FIDIVR ? '/' : '-', float_st0);
8094 ferr_assert(po, po->datap != NULL);
8095 mask = (long)po->datap & 0xffff;
8096 z_check = ((long)po->datap >> 16) & 1;
8097 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8099 if (mask == 0x0100 || mask == 0x0500) { // C0 -> <
8100 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
8103 else if (mask == 0x4000 || mask == 0x4400) { // C3 -> =
8104 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
8107 else if (mask == 0x4100) { // C3, C0
8109 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
8111 strcat(g_comment, " z_chk_det");
8114 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
8115 "(%s < %s ? 0x0100 : 0);",
8116 float_st0, buf1, float_st0, buf1);
8120 ferr(po, "unhandled sw mask: %x\n", mask);
8121 if (po->flags & OPF_FSHIFT) {
8122 if (need_float_stack) {
8123 if (po->flags & OPF_FPOPP)
8124 fprintf(fout, " f_stp += 2;");
8126 fprintf(fout, " f_stp++;");
8129 ferr_assert(po, !(po->flags & OPF_FPOPP));
8130 fprintf(fout, " f_st0 = f_st1;");
8137 fprintf(fout, " %s = f_sw;",
8138 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
8142 fprintf(fout, " %s = -%s;", float_st0, float_st0);
8146 fprintf(fout, " %s = cos%s(%s);", float_st0,
8147 need_double ? "" : "f", float_st0);
8151 if (need_float_stack) {
8152 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
8153 need_double ? "" : "f", float_st1, float_st0);
8154 fprintf(fout, " f_stp++;");
8157 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
8158 need_double ? "" : "f");
8163 if (need_float_stack) {
8164 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
8165 float_st1, need_double ? "" : "f", float_st0);
8166 fprintf(fout, " f_stp++;");
8169 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
8170 need_double ? "" : "f");
8172 strcat(g_comment, " fyl2x");
8176 fprintf(fout, " %s = sin%s(%s);", float_st0,
8177 need_double ? "" : "f", float_st0);
8181 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
8182 need_double ? "" : "f", float_st0);
8186 dead_dst = po->operand[0].type == OPT_REG
8187 && po->operand[0].reg == xST0;
8189 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8191 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
8192 float_st0, float_st0, buf1, buf1);
8193 strcat(g_comment, " fxch");
8200 ferr_assert(po, po->flags & OPF_32BIT);
8201 fprintf(fout, " eax = (s32)%s;", float_st0);
8202 if (po->flags & OPF_FSHIFT) {
8203 if (need_float_stack)
8204 fprintf(fout, " f_stp++;");
8206 fprintf(fout, " f_st0 = f_st1;");
8208 strcat(g_comment, " ftol");
8212 if (need_float_stack) {
8213 fprintf(fout, " %s = pow%s(%s, %s);", float_st1,
8214 need_double ? "" : "f", float_st1, float_st0);
8215 fprintf(fout, " f_stp++;");
8218 fprintf(fout, " f_st0 = pow%s(f_st1, f_st0);",
8219 need_double ? "" : "f");
8221 strcat(g_comment, " CIpow");
8225 fprintf(fout, " do_skip_code_abort();");
8230 fprintf(fout, " do_emms();");
8235 ferr(po, "unhandled op type %d, flags %x\n",
8240 if (g_comment[0] != 0) {
8241 char *p = g_comment;
8242 while (my_isblank(*p))
8244 fprintf(fout, " // %s", p);
8249 fprintf(fout, "\n");
8251 // some sanity checking
8252 if (po->flags & OPF_REP) {
8253 if (po->op != OP_STOS && po->op != OP_MOVS
8254 && po->op != OP_CMPS && po->op != OP_SCAS)
8255 ferr(po, "unexpected rep\n");
8256 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
8257 && (po->op == OP_CMPS || po->op == OP_SCAS))
8258 ferr(po, "cmps/scas with plain rep\n");
8260 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
8261 && po->op != OP_CMPS && po->op != OP_SCAS)
8262 ferr(po, "unexpected repz/repnz\n");
8265 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
8267 if ((po->flags & OPF_LOCK) && !lock_handled)
8268 ferr(po, "unhandled lock\n");
8270 // see is delayed flag stuff is still valid
8271 if (delayed_flag_op != NULL && delayed_flag_op != po) {
8272 if (is_any_opr_modified(delayed_flag_op, po, 0))
8273 delayed_flag_op = NULL;
8276 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
8277 if (is_opr_modified(last_arith_dst, po))
8278 last_arith_dst = NULL;
8285 if (g_stack_fsz && !g_stack_frame_used)
8286 fprintf(fout, " (void)sf;\n");
8288 fprintf(fout, "}\n\n");
8290 gen_x_cleanup(opcnt);
8293 static void gen_x_cleanup(int opcnt)
8297 for (i = 0; i < opcnt; i++) {
8298 struct label_ref *lr, *lr_del;
8300 lr = g_label_refs[i].next;
8301 while (lr != NULL) {
8306 g_label_refs[i].i = -1;
8307 g_label_refs[i].next = NULL;
8309 if (ops[i].op == OP_CALL) {
8311 proto_release(ops[i].pp);
8317 struct func_proto_dep;
8319 struct func_prototype {
8323 int regmask_dep; // likely register args
8324 int regmask_use; // used registers
8325 int has_ret:3; // -1, 0, 1: unresolved, no, yes
8326 unsigned int has_ret64:1;
8327 unsigned int dep_resolved:1;
8328 unsigned int is_stdcall:1;
8329 unsigned int eax_pass:1; // returns without touching eax
8330 struct func_proto_dep *dep_func;
8332 const struct parsed_proto *pp; // seed pp, if any
8335 struct func_proto_dep {
8337 struct func_prototype *proto;
8338 int regmask_live; // .. at the time of call
8339 unsigned int ret_dep:1; // return from this is caller's return
8340 unsigned int has_ret:1; // found from eax use after return
8341 unsigned int has_ret64:1;
8344 static struct func_prototype *hg_fp;
8345 static int hg_fp_cnt;
8347 static struct scanned_var {
8349 enum opr_lenmod lmod;
8350 unsigned int is_seeded:1;
8351 unsigned int is_c_str:1;
8352 const struct parsed_proto *pp; // seed pp, if any
8354 static int hg_var_cnt;
8356 static char **hg_refs;
8357 static int hg_ref_cnt;
8359 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8362 static struct func_prototype *hg_fp_add(const char *funcn)
8364 struct func_prototype *fp;
8366 if ((hg_fp_cnt & 0xff) == 0) {
8367 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
8368 my_assert_not(hg_fp, NULL);
8369 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
8372 fp = &hg_fp[hg_fp_cnt];
8373 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
8375 fp->argc_stack = -1;
8381 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
8386 for (i = 0; i < fp->dep_func_cnt; i++)
8387 if (IS(fp->dep_func[i].name, name))
8388 return &fp->dep_func[i];
8393 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
8396 if (hg_fp_find_dep(fp, name))
8399 if ((fp->dep_func_cnt & 0xff) == 0) {
8400 fp->dep_func = realloc(fp->dep_func,
8401 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
8402 my_assert_not(fp->dep_func, NULL);
8403 memset(&fp->dep_func[fp->dep_func_cnt], 0,
8404 sizeof(fp->dep_func[0]) * 0x100);
8406 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
8410 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
8412 const struct func_prototype *p1 = p1_, *p2 = p2_;
8413 return strcmp(p1->name, p2->name);
8417 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
8419 const struct func_prototype *p1 = p1_, *p2 = p2_;
8420 return p1->id - p2->id;
8424 static void hg_ref_add(const char *name)
8426 if ((hg_ref_cnt & 0xff) == 0) {
8427 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
8428 my_assert_not(hg_refs, NULL);
8429 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
8432 hg_refs[hg_ref_cnt] = strdup(name);
8433 my_assert_not(hg_refs[hg_ref_cnt], NULL);
8437 // recursive register dep pass
8438 // - track saved regs (part 2)
8439 // - try to figure out arg-regs
8440 // - calculate reg deps
8441 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
8442 struct func_prototype *fp, int regmask_save, int regmask_dst,
8443 int *regmask_dep, int *regmask_use, int *has_ret)
8445 struct func_proto_dep *dep;
8446 struct parsed_op *po;
8447 int from_caller = 0;
8452 for (; i < opcnt; i++)
8454 if (cbits[i >> 3] & (1 << (i & 7)))
8456 cbits[i >> 3] |= (1 << (i & 7));
8460 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
8461 if (po->flags & OPF_RMD)
8464 if (po->btj != NULL) {
8466 for (j = 0; j < po->btj->count; j++) {
8467 check_i(po, po->btj->d[j].bt_i);
8468 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
8469 regmask_save, regmask_dst, regmask_dep, regmask_use,
8475 check_i(po, po->bt_i);
8476 if (po->flags & OPF_CJMP) {
8477 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
8478 regmask_save, regmask_dst, regmask_dep, regmask_use,
8487 if (po->flags & OPF_FARG)
8488 /* (just calculate register deps) */;
8489 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
8491 reg = po->operand[0].reg;
8492 ferr_assert(po, reg >= 0);
8494 if (po->flags & OPF_RSAVE) {
8495 regmask_save |= 1 << reg;
8498 if (po->flags & OPF_DONE)
8501 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0, 0);
8503 regmask_save |= 1 << reg;
8504 po->flags |= OPF_RMD;
8505 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, OPF_RMD);
8509 else if (po->flags & OPF_RMD)
8511 else if (po->op == OP_CALL) {
8512 po->regmask_dst |= 1 << xAX;
8514 dep = hg_fp_find_dep(fp, po->operand[0].name);
8516 dep->regmask_live = regmask_save | regmask_dst;
8517 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8518 dep->regmask_live |= 1 << xBP;
8521 else if (po->op == OP_RET) {
8522 if (po->operand_cnt > 0) {
8524 if (fp->argc_stack >= 0
8525 && fp->argc_stack != po->operand[0].val / 4)
8526 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
8527 fp->argc_stack = po->operand[0].val / 4;
8531 if (!fp->eax_pass && (po->flags & OPF_TAIL)) {
8532 if (po->op == OP_CALL) {
8537 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
8540 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
8543 if (ret != 1 && from_caller) {
8544 // unresolved eax - probably void func
8549 if (j >= 0 && ops[j].op == OP_CALL) {
8550 if (ops[j].pp != NULL && !ops[j].pp->is_unresolved) {
8551 int call_has_ret = !IS(ops[j].pp->ret_type.name, "void");
8552 if (ops[j].pp->is_noreturn) {
8553 // could be some fail path
8555 *has_ret = call_has_ret;
8558 *has_ret = call_has_ret;
8561 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
8573 l = regmask_save | regmask_dst;
8574 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8577 l = po->regmask_src & ~l;
8580 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
8581 l, regmask_dst, regmask_save, po->flags);
8584 *regmask_use |= (po->regmask_src | po->regmask_dst)
8586 regmask_dst |= po->regmask_dst;
8588 if (po->flags & OPF_TAIL) {
8589 if (!(po->flags & OPF_CC)) // not cond. tailcall
8595 static void gen_hdr(const char *funcn, int opcnt)
8597 unsigned char cbits[MAX_OPS / 8];
8598 const struct parsed_proto *pp_c;
8599 struct parsed_proto *pp;
8600 struct func_prototype *fp;
8601 struct func_proto_dep *dep;
8602 struct parsed_op *po;
8603 int regmask_dummy = 0;
8606 int max_bp_offset = 0;
8611 pp_c = proto_parse(g_fhdr, funcn, 1);
8613 // already in seed, will add to hg_fp later
8616 fp = hg_fp_add(funcn);
8618 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
8619 g_stack_frame_used = 0;
8623 // - resolve all branches
8624 // - parse calls with labels
8625 resolve_branches_parse_calls(opcnt);
8628 // - handle ebp/esp frame, remove ops related to it
8629 scan_prologue_epilogue(opcnt, NULL);
8632 // - remove dead labels
8634 for (i = 0; i < opcnt; i++)
8636 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8642 if (po->flags & (OPF_RMD|OPF_DONE))
8645 if (po->op == OP_CALL) {
8646 if (po->operand[0].type == OPT_LABEL)
8647 hg_fp_add_dep(fp, opr_name(po, 0));
8648 else if (po->pp != NULL)
8649 hg_fp_add_dep(fp, po->pp->name);
8654 // - handle push <const>/pop pairs
8655 for (i = 0; i < opcnt; i++)
8658 if (po->flags & (OPF_RMD|OPF_DONE))
8661 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
8662 scan_for_pop_const(i, opcnt, i + opcnt * 13);
8666 // - process trivial calls
8667 for (i = 0; i < opcnt; i++)
8670 if (po->flags & (OPF_RMD|OPF_DONE))
8673 if (po->op == OP_CALL)
8675 pp = process_call_early(i, opcnt, &j);
8677 if (!(po->flags & OPF_ATAIL))
8678 // since we know the args, try to collect them
8679 if (collect_call_args_early(i, pp, NULL, NULL) != 0)
8685 // commit esp adjust
8686 if (ops[j].op != OP_POP)
8687 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
8689 for (l = 0; l < pp->argc_stack; l++)
8690 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
8694 po->flags |= OPF_DONE;
8700 // - track saved regs (simple)
8702 for (i = 0; i < opcnt; i++)
8705 if (po->flags & (OPF_RMD|OPF_DONE))
8708 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
8709 && po->operand[0].reg != xCX)
8711 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
8713 // regmask_save |= 1 << po->operand[0].reg; // do it later
8714 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
8715 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
8718 else if (po->op == OP_CALL)
8720 pp = process_call(i, opcnt);
8722 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
8723 // since we know the args, collect them
8724 ret = collect_call_args(po, i, pp, ®mask_dummy,
8727 if (!(po->flags & OPF_TAIL)
8728 && po->operand[0].type == OPT_LABEL)
8730 dep = hg_fp_find_dep(fp, opr_name(po, 0));
8731 ferr_assert(po, dep != NULL);
8732 // treat al write as overwrite to avoid many false positives
8733 find_next_read_reg(i + 1, opcnt, xAX, OPLM_BYTE,
8734 i + opcnt * 25, &j);
8737 find_next_read_reg(i + 1, opcnt, xDX, OPLM_BYTE,
8738 i + opcnt * 26, &j);
8739 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j]))
8746 memset(cbits, 0, (opcnt + 7) / 8);
8747 regmask_dep = regmask_use = 0;
8750 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0,
8751 ®mask_dep, ®mask_use, &has_ret);
8753 // find unreachable code - must be fixed in IDA
8754 for (i = 0; i < opcnt; i++)
8756 if (cbits[i >> 3] & (1 << (i & 7)))
8759 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
8760 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
8762 // the compiler sometimes still generates code after
8763 // noreturn OS functions
8766 if (!(ops[i].flags & OPF_RMD)
8767 && ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
8769 ferr(&ops[i], "unreachable code\n");
8773 for (i = 0; i < g_eqcnt; i++) {
8774 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
8775 max_bp_offset = g_eqs[i].offset;
8778 if (fp->argc_stack < 0) {
8779 max_bp_offset = (max_bp_offset + 3) & ~3;
8780 fp->argc_stack = max_bp_offset / 4;
8781 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
8785 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
8786 fp->regmask_use = regmask_use;
8787 fp->has_ret = has_ret;
8789 printf("// has_ret %d, regmask_dep %x\n",
8790 fp->has_ret, fp->regmask_dep);
8791 output_hdr_fp(stdout, fp, 1);
8792 if (IS(funcn, "sub_10007F72")) exit(1);
8795 gen_x_cleanup(opcnt);
8798 static void hg_fp_resolve_deps(struct func_prototype *fp)
8800 struct func_prototype fp_s;
8801 struct func_proto_dep *dep;
8805 // this thing is recursive, so mark first..
8806 fp->dep_resolved = 1;
8808 for (i = 0; i < fp->dep_func_cnt; i++) {
8809 dep = &fp->dep_func[i];
8811 strcpy(fp_s.name, dep->name);
8812 dep->proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8813 sizeof(hg_fp[0]), hg_fp_cmp_name);
8814 if (dep->proto != NULL) {
8815 if (!dep->proto->dep_resolved)
8816 hg_fp_resolve_deps(dep->proto);
8818 regmask_dep = ~dep->regmask_live
8819 & dep->proto->regmask_dep;
8820 fp->regmask_dep |= regmask_dep;
8821 // printf("dep %s %s |= %x\n", fp->name,
8822 // fp->dep_func[i].name, regmask_dep);
8824 if (dep->has_ret && (dep->proto->regmask_use & mxAX))
8825 dep->proto->has_ret = 1;
8826 if (dep->has_ret64 && (dep->proto->regmask_use & mxDX))
8827 dep->proto->has_ret64 = 1;
8828 if (fp->has_ret == -1 && dep->ret_dep)
8829 fp->has_ret = dep->proto->has_ret;
8834 // make all thiscall/edx arg functions referenced from .data fastcall
8835 static void do_func_refs_from_data(void)
8837 struct func_prototype *fp, fp_s;
8840 for (i = 0; i < hg_ref_cnt; i++) {
8841 strcpy(fp_s.name, hg_refs[i]);
8842 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8843 sizeof(hg_fp[0]), hg_fp_cmp_name);
8847 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
8848 fp->regmask_dep |= mxCX | mxDX;
8852 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8855 const struct parsed_proto *pp;
8856 char *p, namebuf[NAMELEN];
8862 for (; count > 0; count--, fp++) {
8863 if (fp->has_ret == -1)
8864 fprintf(fout, "// ret unresolved\n");
8866 fprintf(fout, "// dep:");
8867 for (j = 0; j < fp->dep_func_cnt; j++) {
8868 fprintf(fout, " %s/", fp->dep_func[j].name);
8869 if (fp->dep_func[j].proto != NULL)
8870 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8871 fp->dep_func[j].proto->has_ret);
8873 fprintf(fout, "\n");
8876 p = strchr(fp->name, '@');
8878 memcpy(namebuf, fp->name, p - fp->name);
8879 namebuf[p - fp->name] = 0;
8887 pp = proto_parse(g_fhdr, name, 1);
8888 if (pp != NULL && pp->is_include)
8891 if (fp->pp != NULL) {
8892 // part of seed, output later
8896 regmask_dep = fp->regmask_dep;
8897 argc_normal = fp->argc_stack;
8899 fprintf(fout, "%-5s",
8900 fp->pp ? fp->pp->ret_type.name :
8901 fp->has_ret64 ? "__int64" :
8902 fp->has_ret ? "int" : "void");
8903 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
8904 && (regmask_dep & ~mxCX) == 0)
8906 fprintf(fout, "/*__thiscall*/ ");
8910 else if ((regmask_dep == (mxCX | mxDX)
8911 && (fp->is_stdcall || fp->argc_stack == 0))
8912 || (regmask_dep == mxCX && fp->argc_stack == 0))
8914 fprintf(fout, " __fastcall ");
8915 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8921 else if (regmask_dep && !fp->is_stdcall) {
8922 fprintf(fout, "/*__usercall*/ ");
8924 else if (regmask_dep) {
8925 fprintf(fout, "/*__userpurge*/ ");
8927 else if (fp->is_stdcall)
8928 fprintf(fout, " __stdcall ");
8930 fprintf(fout, " __cdecl ");
8932 fprintf(fout, "%s(", name);
8935 for (j = 0; j < xSP; j++) {
8936 if (regmask_dep & (1 << j)) {
8939 fprintf(fout, ", ");
8941 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8943 fprintf(fout, "int");
8944 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
8948 for (j = 0; j < argc_normal; j++) {
8951 fprintf(fout, ", ");
8952 if (fp->pp != NULL) {
8953 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8954 if (!fp->pp->arg[arg - 1].type.is_ptr)
8958 fprintf(fout, "int ");
8959 fprintf(fout, "a%d", arg);
8962 fprintf(fout, ");\n");
8966 static void output_hdr(FILE *fout)
8968 static const char *lmod_c_names[] = {
8969 [OPLM_UNSPEC] = "???",
8970 [OPLM_BYTE] = "uint8_t",
8971 [OPLM_WORD] = "uint16_t",
8972 [OPLM_DWORD] = "uint32_t",
8973 [OPLM_QWORD] = "uint64_t",
8975 const struct scanned_var *var;
8976 struct func_prototype *fp;
8977 char line[256] = { 0, };
8981 // add stuff from headers
8982 for (i = 0; i < pp_cache_size; i++) {
8983 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
8984 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
8986 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
8987 fp = hg_fp_add(name);
8988 fp->pp = &pp_cache[i];
8989 fp->argc_stack = fp->pp->argc_stack;
8990 fp->is_stdcall = fp->pp->is_stdcall;
8991 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
8992 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
8996 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
8997 for (i = 0; i < hg_fp_cnt; i++)
8998 hg_fp_resolve_deps(&hg_fp[i]);
9000 // adjust functions referenced from data segment
9001 do_func_refs_from_data();
9003 // final adjustments
9004 for (i = 0; i < hg_fp_cnt; i++) {
9005 if (hg_fp[i].eax_pass && (hg_fp[i].regmask_dep & mxAX))
9006 hg_fp[i].has_ret = 1;
9009 // note: messes up .proto ptr, don't use
9010 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
9013 for (i = 0; i < hg_var_cnt; i++) {
9016 if (var->pp != NULL)
9019 else if (var->is_c_str)
9020 fprintf(fout, "extern %-8s %s[];", "char", var->name);
9022 fprintf(fout, "extern %-8s %s;",
9023 lmod_c_names[var->lmod], var->name);
9026 fprintf(fout, " // seeded");
9027 fprintf(fout, "\n");
9030 fprintf(fout, "\n");
9032 // output function prototypes
9033 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
9036 fprintf(fout, "\n// - seed -\n");
9039 while (fgets(line, sizeof(line), g_fhdr))
9040 fwrite(line, 1, strlen(line), fout);
9043 // '=' needs special treatment
9045 static char *next_word_s(char *w, size_t wsize, char *s)
9052 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
9054 for (i = 1; i < wsize - 1; i++) {
9056 printf("warning: missing closing quote: \"%s\"\n", s);
9065 for (; i < wsize - 1; i++) {
9066 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
9072 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
9073 printf("warning: '%s' truncated\n", w);
9078 static int cmpstringp(const void *p1, const void *p2)
9080 return strcmp(*(char * const *)p1, *(char * const *)p2);
9083 static int is_xref_needed(char *p, char **rlist, int rlist_len)
9088 if (strstr(p, "..."))
9089 // unable to determine, assume needed
9092 if (*p == '.') // .text, .data, ...
9093 // ref from other data or non-function -> no
9096 p2 = strpbrk(p, "+:\r\n\x18");
9099 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9100 // referenced from removed code
9106 static int ida_xrefs_show_need(FILE *fasm, char *p,
9107 char **rlist, int rlist_len)
9113 p = strrchr(p, ';');
9114 if (p != NULL && *p == ';') {
9115 if (IS_START(p + 2, "sctref"))
9117 if (IS_START(p + 2, "DATA XREF: ")) {
9119 if (is_xref_needed(p, rlist, rlist_len))
9127 if (!my_fgets(line, sizeof(line), fasm))
9129 // non-first line is always indented
9130 if (!my_isblank(line[0]))
9133 // should be no content, just comment
9138 p = strrchr(p, ';');
9141 if (IS_START(p, "sctref")) {
9146 // it's printed once, but no harm to check again
9147 if (IS_START(p, "DATA XREF: "))
9150 if (is_xref_needed(p, rlist, rlist_len)) {
9155 fseek(fasm, pos, SEEK_SET);
9159 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
9161 struct scanned_var *var;
9162 char line[256] = { 0, };
9171 // skip to next data section
9172 while (my_fgets(line, sizeof(line), fasm))
9177 if (*p == 0 || *p == ';')
9180 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
9181 if (*p == 0 || *p == ';')
9184 if (*p != 's' || !IS_START(p, "segment para public"))
9190 if (p == NULL || !IS_START(p, "segment para public"))
9194 if (!IS_START(p, "'DATA'"))
9198 while (my_fgets(line, sizeof(line), fasm))
9203 no_identifier = my_isblank(*p);
9206 if (*p == 0 || *p == ';')
9209 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9210 words[wordc][0] = 0;
9211 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9212 if (*p == 0 || *p == ';') {
9218 if (wordc == 2 && IS(words[1], "ends"))
9223 if (no_identifier) {
9224 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
9225 hg_ref_add(words[2]);
9229 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
9230 // when this starts, we don't need anything from this section
9234 // check refs comment(s)
9235 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
9238 if ((hg_var_cnt & 0xff) == 0) {
9239 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
9240 * (hg_var_cnt + 0x100));
9241 my_assert_not(hg_vars, NULL);
9242 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
9245 var = &hg_vars[hg_var_cnt++];
9246 snprintf(var->name, sizeof(var->name), "%s", words[0]);
9248 // maybe already in seed header?
9249 var->pp = proto_parse(g_fhdr, var->name, 1);
9250 if (var->pp != NULL) {
9251 if (var->pp->is_fptr) {
9252 var->lmod = OPLM_DWORD;
9255 else if (var->pp->is_func)
9257 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
9258 aerr("unhandled C type '%s' for '%s'\n",
9259 var->pp->type.name, var->name);
9265 if (IS(words[1], "dd")) {
9266 var->lmod = OPLM_DWORD;
9267 if (wordc >= 4 && IS(words[2], "offset"))
9268 hg_ref_add(words[3]);
9270 else if (IS(words[1], "dw"))
9271 var->lmod = OPLM_WORD;
9272 else if (IS(words[1], "db")) {
9273 var->lmod = OPLM_BYTE;
9274 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
9275 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
9279 else if (IS(words[1], "dq"))
9280 var->lmod = OPLM_QWORD;
9281 //else if (IS(words[1], "dt"))
9283 aerr("type '%s' not known\n", words[1]);
9291 static void set_label(int i, const char *name)
9297 p = strchr(name, ':');
9301 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
9302 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
9303 g_labels[i] = realloc(g_labels[i], len + 1);
9304 my_assert_not(g_labels[i], NULL);
9305 memcpy(g_labels[i], name, len);
9306 g_labels[i][len] = 0;
9315 static struct chunk_item *func_chunks;
9316 static int func_chunk_cnt;
9317 static int func_chunk_alloc;
9319 static void add_func_chunk(FILE *fasm, const char *name, int line)
9321 if (func_chunk_cnt >= func_chunk_alloc) {
9322 func_chunk_alloc *= 2;
9323 func_chunks = realloc(func_chunks,
9324 func_chunk_alloc * sizeof(func_chunks[0]));
9325 my_assert_not(func_chunks, NULL);
9327 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
9328 func_chunks[func_chunk_cnt].name = strdup(name);
9329 func_chunks[func_chunk_cnt].asmln = line;
9333 static int cmp_chunks(const void *p1, const void *p2)
9335 const struct chunk_item *c1 = p1, *c2 = p2;
9336 return strcmp(c1->name, c2->name);
9339 static void scan_ahead_for_chunks(FILE *fasm)
9349 oldpos = ftell(fasm);
9352 while (my_fgets(line, sizeof(line), fasm))
9363 // get rid of random tabs
9364 for (i = 0; line[i] != 0; i++)
9365 if (line[i] == '\t')
9368 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9371 next_word(words[0], sizeof(words[0]), p);
9372 if (words[0][0] == 0)
9373 aerr("missing name for func chunk?\n");
9375 add_func_chunk(fasm, words[0], asmln);
9377 else if (IS_START(p, "; sctend"))
9383 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9384 words[wordc][0] = 0;
9385 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9386 if (*p == 0 || *p == ';') {
9392 if (wordc == 2 && IS(words[1], "ends"))
9396 fseek(fasm, oldpos, SEEK_SET);
9400 int main(int argc, char *argv[])
9402 FILE *fout, *fasm, *frlist;
9403 struct parsed_data *pd = NULL;
9405 char **rlist = NULL;
9407 int rlist_alloc = 0;
9408 int func_chunks_used = 0;
9409 int func_chunks_sorted = 0;
9410 int func_chunk_i = -1;
9411 long func_chunk_ret = 0;
9412 int func_chunk_ret_ln = 0;
9413 int scanned_ahead = 0;
9415 char words[20][256];
9416 enum opr_lenmod lmod;
9417 char *sctproto = NULL;
9419 int pending_endp = 0;
9421 int skip_code_end = 0;
9422 int skip_warned = 0;
9435 for (arg = 1; arg < argc; arg++) {
9436 if (IS(argv[arg], "-v"))
9438 else if (IS(argv[arg], "-rf"))
9439 g_allow_regfunc = 1;
9440 else if (IS(argv[arg], "-uc"))
9441 g_allow_user_icall = 1;
9442 else if (IS(argv[arg], "-m"))
9444 else if (IS(argv[arg], "-hdr"))
9445 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
9450 if (argc < arg + 3) {
9451 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
9452 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
9454 " -hdr - header generation mode\n"
9455 " -rf - allow unannotated indirect calls\n"
9456 " -uc - allow ind. calls/refs to __usercall\n"
9457 " -m - allow multiple .text sections\n"
9458 "[rlist] is a file with function names to skip,"
9466 asmfn = argv[arg++];
9467 fasm = fopen(asmfn, "r");
9468 my_assert_not(fasm, NULL);
9470 hdrfn = argv[arg++];
9471 g_fhdr = fopen(hdrfn, "r");
9472 my_assert_not(g_fhdr, NULL);
9475 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
9476 my_assert_not(rlist, NULL);
9477 // needs special handling..
9478 rlist[rlist_len++] = "__alloca_probe";
9480 func_chunk_alloc = 32;
9481 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
9482 my_assert_not(func_chunks, NULL);
9484 memset(words, 0, sizeof(words));
9486 for (; arg < argc; arg++) {
9489 frlist = fopen(argv[arg], "r");
9490 my_assert_not(frlist, NULL);
9492 while (my_fgets(line, sizeof(line), frlist)) {
9494 if (*p == 0 || *p == ';')
9497 if (IS_START(p, "#if 0")
9498 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
9502 else if (IS_START(p, "#endif"))
9509 p = next_word(words[0], sizeof(words[0]), p);
9510 if (words[0][0] == 0)
9513 if (rlist_len >= rlist_alloc) {
9514 rlist_alloc = rlist_alloc * 2 + 64;
9515 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
9516 my_assert_not(rlist, NULL);
9518 rlist[rlist_len++] = strdup(words[0]);
9526 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
9528 fout = fopen(argv[arg_out], "w");
9529 my_assert_not(fout, NULL);
9532 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
9533 my_assert_not(g_eqs, NULL);
9535 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
9536 g_label_refs[i].i = -1;
9537 g_label_refs[i].next = NULL;
9541 scan_variables(fasm, rlist, rlist_len);
9543 while (my_fgets(line, sizeof(line), fasm))
9552 // get rid of random tabs
9553 for (i = 0; line[i] != 0; i++)
9554 if (line[i] == '\t')
9559 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
9560 goto do_pending_endp; // eww..
9562 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
9564 static const char *attrs[] = {
9573 // parse IDA's attribute-list comment
9574 g_ida_func_attr = 0;
9577 for (; *p != 0; p = sskip(p)) {
9578 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9579 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9580 g_ida_func_attr |= 1 << i;
9581 p += strlen(attrs[i]);
9585 if (i == ARRAY_SIZE(attrs)) {
9586 anote("unparsed IDA attr: %s\n", p);
9589 if (IS(attrs[i], "fpd=")) {
9590 p = next_word(words[0], sizeof(words[0]), p);
9595 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
9597 static const char *attrs[] = {
9605 // parse manual attribute-list comment
9606 g_sct_func_attr = 0;
9609 for (; *p != 0; p = sskip(p)) {
9610 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9611 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9612 g_sct_func_attr |= 1 << i;
9613 p += strlen(attrs[i]);
9620 // clear_sf=start,len (in dwords)
9621 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
9622 &g_stack_clear_len, &j);
9624 // clear_regmask=<mask>
9625 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
9627 // rm_regmask=<mask>
9628 ret = sscanf(p, "=%x%n", &g_regmask_rm, &j) + 1;
9630 anote("unparsed attr value: %s\n", p);
9635 else if (i == ARRAY_SIZE(attrs)) {
9636 anote("unparsed sct attr: %s\n", p);
9641 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9644 next_word(words[0], sizeof(words[0]), p);
9645 if (words[0][0] == 0)
9646 aerr("missing name for func chunk?\n");
9648 if (!scanned_ahead) {
9649 add_func_chunk(fasm, words[0], asmln);
9650 func_chunks_sorted = 0;
9653 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
9655 if (func_chunk_i >= 0) {
9656 if (func_chunk_i < func_chunk_cnt
9657 && IS(func_chunks[func_chunk_i].name, g_func))
9659 // move on to next chunk
9660 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9662 aerr("seek failed for '%s' chunk #%d\n",
9663 g_func, func_chunk_i);
9664 asmln = func_chunks[func_chunk_i].asmln;
9668 if (func_chunk_ret == 0)
9669 aerr("no return from chunk?\n");
9670 fseek(fasm, func_chunk_ret, SEEK_SET);
9671 asmln = func_chunk_ret_ln;
9677 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
9678 func_chunks_used = 1;
9680 if (IS_START(g_func, "sub_")) {
9681 unsigned long addr = strtoul(p, NULL, 16);
9682 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
9683 if (addr > f_addr && !scanned_ahead) {
9684 //anote("scan_ahead caused by '%s', addr %lx\n",
9686 scan_ahead_for_chunks(fasm);
9688 func_chunks_sorted = 0;
9696 for (i = wordc; i < ARRAY_SIZE(words); i++)
9698 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9699 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9700 if (*p == 0 || *p == ';') {
9705 if (*p != 0 && *p != ';')
9706 aerr("too many words\n");
9708 if (skip_code_end) {
9713 // allow asm patches in comments
9715 // skip IDA's forced non-removable comment
9716 if (!IS_START(p, "; sct") && (p2 = strchr(p + 1, ';')))
9719 if (*p == ';' && IS_START(p, "; sct")) {
9720 if (IS_START(p, "; sctpatch:")) {
9722 if (*p == 0 || *p == ';')
9724 goto parse_words; // lame
9726 if (IS_START(p, "; sctproto:")) {
9727 sctproto = strdup(p + 11);
9729 else if (IS_START(p, "; sctend")) {
9734 else if (IS_START(p, "; sctskip_start")) {
9735 if (in_func && !g_skip_func) {
9737 ops[pi].op = OPP_ABORT;
9738 ops[pi].asmln = asmln;
9744 else if (IS_START(p, "; sctskip_end")) {
9752 awarn("wordc == 0?\n");
9756 // don't care about this:
9757 if (words[0][0] == '.'
9758 || IS(words[0], "include")
9759 || IS(words[0], "assume") || IS(words[1], "segment")
9760 || IS(words[0], "align"))
9766 // do delayed endp processing to collect switch jumptables
9768 if (in_func && !g_skip_func && !end && wordc >= 2
9769 && ((words[0][0] == 'd' && words[0][2] == 0)
9770 || (words[1][0] == 'd' && words[1][2] == 0)))
9773 if (words[1][0] == 'd' && words[1][2] == 0) {
9775 if (g_func_pd_cnt >= pd_alloc) {
9776 pd_alloc = pd_alloc * 2 + 16;
9777 g_func_pd = realloc(g_func_pd,
9778 sizeof(g_func_pd[0]) * pd_alloc);
9779 my_assert_not(g_func_pd, NULL);
9781 pd = &g_func_pd[g_func_pd_cnt];
9783 memset(pd, 0, sizeof(*pd));
9784 strcpy(pd->label, words[0]);
9785 pd->type = OPT_CONST;
9786 pd->lmod = lmod_from_directive(words[1]);
9792 anote("skipping alignment byte?\n");
9795 lmod = lmod_from_directive(words[0]);
9796 if (lmod != pd->lmod)
9797 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
9800 if (pd->count_alloc < pd->count + wordc) {
9801 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
9802 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
9803 my_assert_not(pd->d, NULL);
9805 for (; i < wordc; i++) {
9806 if (IS(words[i], "offset")) {
9807 pd->type = OPT_OFFSET;
9810 p = strchr(words[i], ',');
9813 if (pd->type == OPT_OFFSET)
9814 pd->d[pd->count].u.label = strdup(words[i]);
9816 pd->d[pd->count].u.val = parse_number(words[i], 0);
9817 pd->d[pd->count].bt_i = -1;
9823 if (in_func && !g_skip_func) {
9825 gen_hdr(g_func, pi);
9827 gen_func(fout, g_fhdr, g_func, pi);
9832 g_ida_func_attr = 0;
9833 g_sct_func_attr = 0;
9834 g_stack_clear_start = 0;
9835 g_stack_clear_len = 0;
9842 func_chunks_used = 0;
9845 memset(&ops, 0, pi * sizeof(ops[0]));
9850 for (i = 0; i < g_func_pd_cnt; i++) {
9852 if (pd->type == OPT_OFFSET) {
9853 for (j = 0; j < pd->count; j++)
9854 free(pd->d[j].u.label);
9869 if (IS(words[1], "proc")) {
9871 aerr("proc '%s' while in_func '%s'?\n",
9874 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9876 strcpy(g_func, words[0]);
9877 set_label(0, words[0]);
9882 if (IS(words[1], "endp"))
9885 aerr("endp '%s' while not in_func?\n", words[0]);
9886 if (!IS(g_func, words[0]))
9887 aerr("endp '%s' while in_func '%s'?\n",
9890 aerr("endp '%s' while skipping code\n", words[0]);
9892 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
9893 && ops[0].op == OP_JMP && ops[0].operand[0].segment)
9899 if (!g_skip_func && func_chunks_used) {
9900 // start processing chunks
9901 struct chunk_item *ci, key = { g_func, 0 };
9903 func_chunk_ret = ftell(fasm);
9904 func_chunk_ret_ln = asmln;
9905 if (!func_chunks_sorted) {
9906 qsort(func_chunks, func_chunk_cnt,
9907 sizeof(func_chunks[0]), cmp_chunks);
9908 func_chunks_sorted = 1;
9910 ci = bsearch(&key, func_chunks, func_chunk_cnt,
9911 sizeof(func_chunks[0]), cmp_chunks);
9913 aerr("'%s' needs chunks, but none found\n", g_func);
9914 func_chunk_i = ci - func_chunks;
9915 for (; func_chunk_i > 0; func_chunk_i--)
9916 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
9919 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9921 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
9922 asmln = func_chunks[func_chunk_i].asmln;
9930 if (wordc == 2 && IS(words[1], "ends")) {
9934 goto do_pending_endp;
9938 // scan for next text segment
9939 while (my_fgets(line, sizeof(line), fasm)) {
9942 if (*p == 0 || *p == ';')
9945 if (strstr(p, "segment para public 'CODE' use32"))
9952 p = strchr(words[0], ':');
9954 set_label(pi, words[0]);
9958 if (!in_func || g_skip_func || skip_code) {
9959 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
9961 anote("skipping from '%s'\n", g_labels[pi]);
9965 g_labels[pi] = NULL;
9969 if (wordc > 1 && IS(words[1], "="))
9972 aerr("unhandled equ, wc=%d\n", wordc);
9973 if (g_eqcnt >= eq_alloc) {
9975 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
9976 my_assert_not(g_eqs, NULL);
9979 len = strlen(words[0]);
9980 if (len > sizeof(g_eqs[0].name) - 1)
9981 aerr("equ name too long: %d\n", len);
9982 strcpy(g_eqs[g_eqcnt].name, words[0]);
9984 if (!IS(words[3], "ptr"))
9985 aerr("unhandled equ\n");
9986 if (IS(words[2], "dword"))
9987 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
9988 else if (IS(words[2], "word"))
9989 g_eqs[g_eqcnt].lmod = OPLM_WORD;
9990 else if (IS(words[2], "byte"))
9991 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
9992 else if (IS(words[2], "qword"))
9993 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
9995 aerr("bad lmod: '%s'\n", words[2]);
9997 g_eqs[g_eqcnt].offset = parse_number(words[4], 0);
10002 if (pi >= ARRAY_SIZE(ops))
10003 aerr("too many ops\n");
10005 parse_op(&ops[pi], words, wordc);
10007 ops[pi].datap = sctproto;
10022 // vim:ts=2:shiftwidth=2:expandtab