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)
24 #include "my_assert.h"
28 #include "protoparse.h"
30 static const char *asmfn;
34 #define anote(fmt, ...) \
35 printf("%s:%d: note: " fmt, asmfn, asmln, ##__VA_ARGS__)
36 #define awarn(fmt, ...) \
37 printf("%s:%d: warning: " fmt, asmfn, asmln, ##__VA_ARGS__)
38 #define aerr(fmt, ...) do { \
39 printf("%s:%d: error: " fmt, asmfn, asmln, ##__VA_ARGS__); \
44 #include "masm_tools.h"
47 OPF_RMD = (1 << 0), /* removed from code generation */
48 OPF_DATA = (1 << 1), /* data processing - writes to dst opr */
49 OPF_FLAGS = (1 << 2), /* sets flags */
50 OPF_JMP = (1 << 3), /* branch, call */
51 OPF_CJMP = (1 << 4), /* cond. branch (cc or jecxz/loop) */
52 OPF_CC = (1 << 5), /* uses flags */
53 OPF_TAIL = (1 << 6), /* ret or tail call */
54 OPF_RSAVE = (1 << 7), /* push/pop is local reg save/load */
55 OPF_REP = (1 << 8), /* prefixed by rep */
56 OPF_REPZ = (1 << 9), /* rep is repe/repz */
57 OPF_REPNZ = (1 << 10), /* rep is repne/repnz */
58 OPF_FARG = (1 << 11), /* push collected as func arg */
59 OPF_FARGNR = (1 << 12), /* push collected as func arg (no reuse) */
60 OPF_EBP_S = (1 << 13), /* ebp used as scratch here, not BP */
61 OPF_DF = (1 << 14), /* DF flag set */
62 OPF_ATAIL = (1 << 15), /* tail call with reused arg frame */
63 OPF_32BIT = (1 << 16), /* 32bit division */
64 OPF_LOCK = (1 << 17), /* op has lock prefix */
65 OPF_VAPUSH = (1 << 18), /* vararg ptr push (as call arg) */
66 OPF_DONE = (1 << 19), /* already fully handled by analysis */
67 OPF_PPUSH = (1 << 20), /* part of complex push-pop graph */
68 OPF_NOREGS = (1 << 21), /* don't track regs of this op */
69 OPF_FPUSH = (1 << 22), /* pushes x87 stack */
70 OPF_FPOP = (1 << 23), /* pops x87 stack */
71 OPF_FSHIFT = (1 << 24), /* x87 stack shift is actually needed */
161 // pseudo-ops for lib calls
180 // must be sorted (larger len must be further in enum)
189 #define MAX_EXITS 128
191 #define MAX_OPERANDS 3
194 #define OPR_INIT(type_, lmod_, reg_) \
195 { type_, lmod_, reg_, }
199 enum opr_lenmod lmod;
201 unsigned int is_ptr:1; // pointer in C
202 unsigned int is_array:1; // array in C
203 unsigned int type_from_var:1; // .. in header, sometimes wrong
204 unsigned int size_mismatch:1; // type override differs from C
205 unsigned int size_lt:1; // type override is larger than C
206 unsigned int had_ds:1; // had ds: prefix
207 const struct parsed_proto *pp; // for OPT_LABEL
214 struct parsed_opr operand[MAX_OPERANDS];
217 unsigned char pfo_inv;
218 unsigned char operand_cnt;
219 unsigned char p_argnum; // arg push: altered before call arg #
220 unsigned char p_arggrp; // arg push: arg group # for above
221 unsigned char p_argpass;// arg push: arg of host func
222 short p_argnext;// arg push: same arg pushed elsewhere or -1
223 int regmask_src; // all referensed regs
225 int pfomask; // flagop: parsed_flag_op that can't be delayed
226 int cc_scratch; // scratch storage during analysis
227 int bt_i; // branch target for branches
228 struct parsed_data *btj;// branch targets for jumptables
229 struct parsed_proto *pp;// parsed_proto for OP_CALL
235 // on start: function/data type hint (sctproto)
237 // (OPF_CC) - points to one of (OPF_FLAGS) that affects cc op
238 // OP_PUSH - points to OP_POP in complex push/pop graph
239 // OP_POP - points to OP_PUSH in simple push/pop pair
240 // OP_FCOM - needed_status_word_bits | (is_z_check << 16)
244 enum opr_lenmod lmod;
251 enum opr_lenmod lmod;
265 struct label_ref *next;
269 IDAFA_BP_FRAME = (1 << 0),
270 IDAFA_LIB_FUNC = (1 << 1),
271 IDAFA_STATIC = (1 << 2),
272 IDAFA_NORETURN = (1 << 3),
273 IDAFA_THUNK = (1 << 4),
274 IDAFA_FPD = (1 << 5),
278 SCTFA_CLEAR_SF = (1 << 0), // clear stack frame
279 SCTFA_CLEAR_REGS = (1 << 1), // clear registers (mask)
292 // note: limited to 32k due to p_argnext
294 #define MAX_ARG_GRP 2
296 static struct parsed_op ops[MAX_OPS];
297 static struct parsed_equ *g_eqs;
299 static char *g_labels[MAX_OPS];
300 static struct label_ref g_label_refs[MAX_OPS];
301 static const struct parsed_proto *g_func_pp;
302 static struct parsed_data *g_func_pd;
303 static int g_func_pd_cnt;
304 static int g_func_lmods;
305 static char g_func[256];
306 static char g_comment[256];
307 static int g_bp_frame;
308 static int g_sp_frame;
309 static int g_stack_frame_used;
310 static int g_stack_fsz;
311 static int g_ida_func_attr;
312 static int g_sct_func_attr;
313 static int g_stack_clear_start; // in dwords
314 static int g_stack_clear_len;
315 static int g_regmask_init;
316 static int g_skip_func;
317 static int g_allow_regfunc;
318 static int g_allow_user_icall;
319 static int g_quiet_pp;
320 static int g_header_mode;
322 #define ferr(op_, fmt, ...) do { \
323 printf("%s:%d: error %u: [%s] '%s': " fmt, asmfn, (op_)->asmln, \
324 __LINE__, g_func, dump_op(op_), ##__VA_ARGS__); \
328 #define fnote(op_, fmt, ...) \
329 printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
330 dump_op(op_), ##__VA_ARGS__)
332 #define ferr_assert(op_, cond) do { \
333 if (!(cond)) ferr(op_, "assertion '%s' failed\n", #cond); \
336 const char *regs_r32[] = {
337 "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
338 // not r32, but list here for easy parsing and printing
339 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
340 "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"
342 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
343 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
344 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
350 xMM0, xMM1, xMM2, xMM3, // mmx
351 xMM4, xMM5, xMM6, xMM7,
352 xST0, xST1, xST2, xST3, // x87
353 xST4, xST5, xST6, xST7,
356 #define mxAX (1 << xAX)
357 #define mxCX (1 << xCX)
358 #define mxDX (1 << xDX)
359 #define mxST0 (1 << xST0)
360 #define mxST1 (1 << xST1)
361 #define mxST1_0 (mxST1 | mxST0)
362 #define mxST7_2 (0xfc << xST0)
363 #define mxSTa (0xff << xST0)
365 // possible basic comparison types (without inversion)
366 enum parsed_flag_op {
370 PFO_BE, // 6 CF=1||ZF=1
374 PFO_LE, // e ZF=1||SF!=OF
377 #define PFOB_O (1 << PFO_O)
378 #define PFOB_C (1 << PFO_C)
379 #define PFOB_Z (1 << PFO_Z)
380 #define PFOB_S (1 << PFO_S)
382 static const char *parsed_flag_op_names[] = {
383 "o", "c", "z", "be", "s", "p", "l", "le"
386 static int char_array_i(const char *array[], size_t len, const char *s)
390 for (i = 0; i < len; i++)
397 static void printf_number(char *buf, size_t buf_size,
398 unsigned long number)
400 // output in C-friendly form
401 snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
404 static int check_segment_prefix(const char *s)
406 if (s[0] == 0 || s[1] != 's' || s[2] != ':')
420 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
424 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
426 *reg_lmod = OPLM_QWORD;
430 *reg_lmod = OPLM_DWORD;
433 reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
435 *reg_lmod = OPLM_WORD;
438 reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
440 *reg_lmod = OPLM_BYTE;
443 reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
445 *reg_lmod = OPLM_BYTE;
452 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
454 enum opr_lenmod lmod;
467 while (my_isblank(*s))
469 for (; my_issep(*s); d++, s++)
471 while (my_isblank(*s))
475 // skip '?s:' prefixes
476 if (check_segment_prefix(s))
479 s = next_idt(w, sizeof(w), s);
484 reg = parse_reg(&lmod, w);
486 *regmask |= 1 << reg;
490 if ('0' <= w[0] && w[0] <= '9') {
491 number = parse_number(w, 0);
492 printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
496 // probably some label/identifier - pass
499 snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
503 strcpy(name, cvtbuf);
508 static int is_reg_in_str(const char *s)
512 if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
515 for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
516 if (!strncmp(s, regs_r32[i], 3))
522 static const char *parse_stack_el(const char *name, char *extra_reg,
523 int *base_val, int early_try)
525 const char *p, *p2, *s;
531 if (g_bp_frame || early_try)
534 if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
536 if (extra_reg != NULL) {
537 strncpy(extra_reg, name, 3);
542 if (IS_START(p, "ebp+")) {
546 if (p2 != NULL && is_reg_in_str(p)) {
547 if (extra_reg != NULL) {
548 strncpy(extra_reg, p, p2 - p);
549 extra_reg[p2 - p] = 0;
554 if (!('0' <= *p && *p <= '9'))
561 if (!IS_START(name, "esp+"))
567 if (is_reg_in_str(s)) {
568 if (extra_reg != NULL) {
569 strncpy(extra_reg, s, p - s);
570 extra_reg[p - s] = 0;
575 aerr("%s IDA stackvar not set?\n", __func__);
577 if (!('0' <= *s && *s <= '9')) {
578 aerr("%s IDA stackvar offset not set?\n", __func__);
581 if (s[0] == '0' && s[1] == 'x')
584 if (len < sizeof(buf) - 1) {
585 strncpy(buf, s, len);
588 val = strtol(buf, &endp, 16);
589 if (val == 0 || *endp != 0 || errno != 0) {
590 aerr("%s num parse fail for '%s'\n", __func__, buf);
599 if ('0' <= *p && *p <= '9')
602 if (base_val != NULL)
607 static int guess_lmod_from_name(struct parsed_opr *opr)
609 if (IS_START(opr->name, "dword_") || IS_START(opr->name, "off_")) {
610 opr->lmod = OPLM_DWORD;
613 if (IS_START(opr->name, "word_")) {
614 opr->lmod = OPLM_WORD;
617 if (IS_START(opr->name, "byte_")) {
618 opr->lmod = OPLM_BYTE;
621 if (IS_START(opr->name, "qword_")) {
622 opr->lmod = OPLM_QWORD;
628 static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
629 const struct parsed_type *c_type)
631 static const char *qword_types[] = {
632 "uint64_t", "int64_t", "__int64",
634 static const char *dword_types[] = {
635 "uint32_t", "int", "_DWORD", "UINT_PTR", "DWORD",
636 "WPARAM", "LPARAM", "UINT", "__int32",
637 "LONG", "HIMC", "BOOL", "size_t",
640 static const char *word_types[] = {
641 "uint16_t", "int16_t", "_WORD", "WORD",
642 "unsigned __int16", "__int16",
644 static const char *byte_types[] = {
645 "uint8_t", "int8_t", "char",
646 "unsigned __int8", "__int8", "BYTE", "_BYTE",
648 // structures.. deal the same as with _UNKNOWN for now
654 if (c_type->is_ptr) {
659 n = skip_type_mod(c_type->name);
661 for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
662 if (IS(n, dword_types[i])) {
668 for (i = 0; i < ARRAY_SIZE(word_types); i++) {
669 if (IS(n, word_types[i])) {
675 for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
676 if (IS(n, byte_types[i])) {
682 for (i = 0; i < ARRAY_SIZE(qword_types); i++) {
683 if (IS(n, qword_types[i])) {
692 static char *default_cast_to(char *buf, size_t buf_size,
693 struct parsed_opr *opr)
697 if (!opr->is_ptr || strchr(opr->name, '['))
699 if (opr->pp == NULL || opr->pp->type.name == NULL
702 snprintf(buf, buf_size, "%s", "(void *)");
706 snprintf(buf, buf_size, "(%s)", opr->pp->type.name);
710 static enum opr_type lmod_from_directive(const char *d)
714 else if (IS(d, "dw"))
716 else if (IS(d, "db"))
719 aerr("unhandled directive: '%s'\n", d);
723 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
729 *regmask |= 1 << reg;
732 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
735 static int parse_operand(struct parsed_opr *opr,
736 int *regmask, int *regmask_indirect,
737 char words[16][256], int wordc, int w, unsigned int op_flags)
739 const struct parsed_proto *pp = NULL;
740 enum opr_lenmod tmplmod;
741 unsigned long number;
749 aerr("parse_operand w %d, wordc %d\n", w, wordc);
753 for (i = w; i < wordc; i++) {
754 len = strlen(words[i]);
755 if (words[i][len - 1] == ',') {
756 words[i][len - 1] = 0;
762 wordc_in = wordc - w;
764 if ((op_flags & OPF_JMP) && wordc_in > 0
765 && !('0' <= words[w][0] && words[w][0] <= '9'))
767 const char *label = NULL;
769 if (wordc_in == 3 && !strncmp(words[w], "near", 4)
770 && IS(words[w + 1], "ptr"))
771 label = words[w + 2];
772 else if (wordc_in == 2 && IS(words[w], "short"))
773 label = words[w + 1];
774 else if (wordc_in == 1
775 && strchr(words[w], '[') == NULL
776 && parse_reg(&tmplmod, words[w]) < 0)
780 opr->type = OPT_LABEL;
781 ret = check_segment_prefix(label);
784 aerr("fs/gs used\n");
788 strcpy(opr->name, label);
794 if (IS(words[w + 1], "ptr")) {
795 if (IS(words[w], "dword"))
796 opr->lmod = OPLM_DWORD;
797 else if (IS(words[w], "word"))
798 opr->lmod = OPLM_WORD;
799 else if (IS(words[w], "byte"))
800 opr->lmod = OPLM_BYTE;
801 else if (IS(words[w], "qword"))
802 opr->lmod = OPLM_QWORD;
804 aerr("type parsing failed\n");
806 wordc_in = wordc - w;
811 if (IS(words[w], "offset")) {
812 opr->type = OPT_OFFSET;
813 opr->lmod = OPLM_DWORD;
814 strcpy(opr->name, words[w + 1]);
815 pp = proto_parse(g_fhdr, opr->name, 1);
818 if (IS(words[w], "(offset")) {
819 p = strchr(words[w + 1], ')');
821 aerr("parse of bracketed offset failed\n");
823 opr->type = OPT_OFFSET;
824 strcpy(opr->name, words[w + 1]);
830 aerr("parse_operand 1 word expected\n");
832 ret = check_segment_prefix(words[w]);
835 aerr("fs/gs used\n");
837 memmove(words[w], words[w] + 3, strlen(words[w]) - 2);
839 strcpy(opr->name, words[w]);
841 if (words[w][0] == '[') {
842 opr->type = OPT_REGMEM;
843 ret = sscanf(words[w], "[%[^]]]", opr->name);
845 aerr("[] parse failure\n");
847 parse_indmode(opr->name, regmask_indirect, 1);
848 if (opr->lmod == OPLM_UNSPEC
849 && parse_stack_el(opr->name, NULL, NULL, 1))
852 struct parsed_equ *eq =
853 equ_find(NULL, parse_stack_el(opr->name, NULL, NULL, 1), &i);
855 opr->lmod = eq->lmod;
857 // might be unaligned access
858 g_func_lmods |= 1 << OPLM_BYTE;
862 else if (strchr(words[w], '[')) {
864 p = strchr(words[w], '[');
865 opr->type = OPT_REGMEM;
866 parse_indmode(p, regmask_indirect, 0);
867 strncpy(buf, words[w], p - words[w]);
868 buf[p - words[w]] = 0;
869 pp = proto_parse(g_fhdr, buf, 1);
872 else if (('0' <= words[w][0] && words[w][0] <= '9')
873 || words[w][0] == '-')
875 number = parse_number(words[w], 0);
876 opr->type = OPT_CONST;
878 printf_number(opr->name, sizeof(opr->name), number);
882 ret = parse_reg(&tmplmod, opr->name);
884 setup_reg_opr(opr, ret, tmplmod, regmask);
888 // most likely var in data segment
889 opr->type = OPT_LABEL;
890 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
894 if (pp->is_fptr || pp->is_func) {
895 opr->lmod = OPLM_DWORD;
899 tmplmod = OPLM_UNSPEC;
900 if (!guess_lmod_from_c_type(&tmplmod, &pp->type))
901 anote("unhandled C type '%s' for '%s'\n",
902 pp->type.name, opr->name);
904 if (opr->lmod == OPLM_UNSPEC) {
906 opr->type_from_var = 1;
908 else if (opr->lmod != tmplmod) {
909 opr->size_mismatch = 1;
910 if (tmplmod < opr->lmod)
913 opr->is_ptr = pp->type.is_ptr;
915 opr->is_array = pp->type.is_array;
919 if (opr->lmod == OPLM_UNSPEC)
920 guess_lmod_from_name(opr);
924 static const struct {
929 { "repe", OPF_REP|OPF_REPZ },
930 { "repz", OPF_REP|OPF_REPZ },
931 { "repne", OPF_REP|OPF_REPNZ },
932 { "repnz", OPF_REP|OPF_REPNZ },
933 { "lock", OPF_LOCK }, // ignored for now..
936 #define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
938 static const struct {
941 unsigned short minopr;
942 unsigned short maxopr;
945 unsigned char pfo_inv;
947 { "nop", OP_NOP, 0, 0, 0 },
948 { "push", OP_PUSH, 1, 1, 0 },
949 { "pop", OP_POP, 1, 1, OPF_DATA },
950 { "pusha",OP_PUSHA, 0, 0, 0 },
951 { "popa", OP_POPA, 0, 0, OPF_DATA },
952 { "leave",OP_LEAVE, 0, 0, OPF_DATA },
953 { "mov" , OP_MOV, 2, 2, OPF_DATA },
954 { "lea", OP_LEA, 2, 2, OPF_DATA },
955 { "movzx",OP_MOVZX, 2, 2, OPF_DATA },
956 { "movsx",OP_MOVSX, 2, 2, OPF_DATA },
957 { "xchg", OP_XCHG, 2, 2, OPF_DATA },
958 { "not", OP_NOT, 1, 1, OPF_DATA },
959 { "xlat", OP_XLAT, 0, 0, OPF_DATA },
960 { "cdq", OP_CDQ, 0, 0, OPF_DATA },
961 { "bswap",OP_BSWAP, 1, 1, OPF_DATA },
962 { "lodsb",OP_LODS, 0, 0, OPF_DATA },
963 { "lodsw",OP_LODS, 0, 0, OPF_DATA },
964 { "lodsd",OP_LODS, 0, 0, OPF_DATA },
965 { "stosb",OP_STOS, 0, 0, OPF_DATA },
966 { "stosw",OP_STOS, 0, 0, OPF_DATA },
967 { "stosd",OP_STOS, 0, 0, OPF_DATA },
968 { "movsb",OP_MOVS, 0, 0, OPF_DATA },
969 { "movsw",OP_MOVS, 0, 0, OPF_DATA },
970 { "movsd",OP_MOVS, 0, 0, OPF_DATA },
971 { "cmpsb",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
972 { "cmpsw",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
973 { "cmpsd",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
974 { "scasb",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
975 { "scasw",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
976 { "scasd",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
977 { "std", OP_STD, 0, 0, OPF_DATA }, // special flag
978 { "cld", OP_CLD, 0, 0, OPF_DATA },
979 { "add", OP_ADD, 2, 2, OPF_DATA|OPF_FLAGS },
980 { "sub", OP_SUB, 2, 2, OPF_DATA|OPF_FLAGS },
981 { "and", OP_AND, 2, 2, OPF_DATA|OPF_FLAGS },
982 { "or", OP_OR, 2, 2, OPF_DATA|OPF_FLAGS },
983 { "xor", OP_XOR, 2, 2, OPF_DATA|OPF_FLAGS },
984 { "shl", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
985 { "shr", OP_SHR, 2, 2, OPF_DATA|OPF_FLAGS },
986 { "sal", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
987 { "sar", OP_SAR, 2, 2, OPF_DATA|OPF_FLAGS },
988 { "shld", OP_SHLD, 3, 3, OPF_DATA|OPF_FLAGS },
989 { "shrd", OP_SHRD, 3, 3, OPF_DATA|OPF_FLAGS },
990 { "rol", OP_ROL, 2, 2, OPF_DATA|OPF_FLAGS },
991 { "ror", OP_ROR, 2, 2, OPF_DATA|OPF_FLAGS },
992 { "rcl", OP_RCL, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
993 { "rcr", OP_RCR, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
994 { "adc", OP_ADC, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
995 { "sbb", OP_SBB, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
996 { "bsf", OP_BSF, 2, 2, OPF_DATA|OPF_FLAGS },
997 { "inc", OP_INC, 1, 1, OPF_DATA|OPF_FLAGS },
998 { "dec", OP_DEC, 1, 1, OPF_DATA|OPF_FLAGS },
999 { "neg", OP_NEG, 1, 1, OPF_DATA|OPF_FLAGS },
1000 { "mul", OP_MUL, 1, 1, OPF_DATA|OPF_FLAGS },
1001 { "imul", OP_IMUL, 1, 3, OPF_DATA|OPF_FLAGS },
1002 { "div", OP_DIV, 1, 1, OPF_DATA|OPF_FLAGS },
1003 { "idiv", OP_IDIV, 1, 1, OPF_DATA|OPF_FLAGS },
1004 { "test", OP_TEST, 2, 2, OPF_FLAGS },
1005 { "cmp", OP_CMP, 2, 2, OPF_FLAGS },
1006 { "retn", OP_RET, 0, 1, OPF_TAIL },
1007 { "call", OP_CALL, 1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
1008 { "jmp", OP_JMP, 1, 1, OPF_JMP },
1009 { "jecxz",OP_JECXZ, 1, 1, OPF_JMP|OPF_CJMP },
1010 { "loop", OP_LOOP, 1, 1, OPF_JMP|OPF_CJMP|OPF_DATA },
1011 { "jo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 0 }, // 70 OF=1
1012 { "jno", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 1 }, // 71 OF=0
1013 { "jc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72 CF=1
1014 { "jb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72
1015 { "jnc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73 CF=0
1016 { "jnb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1017 { "jae", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1018 { "jz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74 ZF=1
1019 { "je", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74
1020 { "jnz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75 ZF=0
1021 { "jne", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75
1022 { "jbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76 CF=1||ZF=1
1023 { "jna", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76
1024 { "ja", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77 CF=0&&ZF=0
1025 { "jnbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77
1026 { "js", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 0 }, // 78 SF=1
1027 { "jns", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 1 }, // 79 SF=0
1028 { "jp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a PF=1
1029 { "jpe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a
1030 { "jnp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b PF=0
1031 { "jpo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b
1032 { "jl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c SF!=OF
1033 { "jnge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c
1034 { "jge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d SF=OF
1035 { "jnl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d
1036 { "jle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e ZF=1||SF!=OF
1037 { "jng", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e
1038 { "jg", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f ZF=0&&SF=OF
1039 { "jnle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f
1040 { "seto", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 0 },
1041 { "setno", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 1 },
1042 { "setc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1043 { "setb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1044 { "setnc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1045 { "setae", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1046 { "setnb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1047 { "setz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1048 { "sete", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1049 { "setnz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1050 { "setne", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1051 { "setbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1052 { "setna", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1053 { "seta", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1054 { "setnbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1055 { "sets", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 0 },
1056 { "setns", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 1 },
1057 { "setp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1058 { "setpe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1059 { "setnp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1060 { "setpo", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1061 { "setl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1062 { "setnge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1063 { "setge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1064 { "setnl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1065 { "setle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1066 { "setng", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1067 { "setg", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1068 { "setnle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1070 { "fld", OP_FLD, 1, 1, OPF_FPUSH },
1071 { "fild", OP_FILD, 1, 1, OPF_FPUSH },
1072 { "fld1", OP_FLDc, 0, 0, OPF_FPUSH },
1073 { "fldln2", OP_FLDc, 0, 0, OPF_FPUSH },
1074 { "fldz", OP_FLDc, 0, 0, OPF_FPUSH },
1075 { "fst", OP_FST, 1, 1, 0 },
1076 { "fstp", OP_FST, 1, 1, OPF_FPOP },
1077 { "fist", OP_FIST, 1, 1, 0 },
1078 { "fistp", OP_FIST, 1, 1, OPF_FPOP },
1079 { "fadd", OP_FADD, 0, 2, 0 },
1080 { "faddp", OP_FADD, 0, 2, OPF_FPOP },
1081 { "fdiv", OP_FDIV, 0, 2, 0 },
1082 { "fdivp", OP_FDIV, 0, 2, OPF_FPOP },
1083 { "fmul", OP_FMUL, 0, 2, 0 },
1084 { "fmulp", OP_FMUL, 0, 2, OPF_FPOP },
1085 { "fsub", OP_FSUB, 0, 2, 0 },
1086 { "fsubp", OP_FSUB, 0, 2, OPF_FPOP },
1087 { "fdivr", OP_FDIVR, 0, 2, 0 },
1088 { "fdivrp", OP_FDIVR, 0, 2, OPF_FPOP },
1089 { "fsubr", OP_FSUBR, 0, 2, 0 },
1090 { "fsubrp", OP_FSUBR, 0, 2, OPF_FPOP },
1091 { "fiadd", OP_FIADD, 1, 1, 0 },
1092 { "fidiv", OP_FIDIV, 1, 1, 0 },
1093 { "fimul", OP_FIMUL, 1, 1, 0 },
1094 { "fisub", OP_FISUB, 1, 1, 0 },
1095 { "fidivr", OP_FIDIVR, 1, 1, 0 },
1096 { "fisubr", OP_FISUBR, 1, 1, 0 },
1097 { "fcom", OP_FCOM, 0, 1, 0 },
1098 { "fcomp", OP_FCOM, 0, 1, OPF_FPOP },
1099 { "fnstsw", OP_FNSTSW, 1, 1, OPF_DATA },
1100 { "fchs", OP_FCHS, 0, 0, 0 },
1101 { "fcos", OP_FCOS, 0, 0, 0 },
1102 { "fpatan", OP_FPATAN, 0, 0, OPF_FPOP },
1103 { "fptan", OP_FPTAN, 0, 0, OPF_FPUSH },
1104 { "fsin", OP_FSIN, 0, 0, 0 },
1105 { "fsqrt", OP_FSQRT, 0, 0, 0 },
1106 { "fxch", OP_FXCH, 1, 1, 0 },
1107 { "fyl2x", OP_FYL2X, 0, 0, OPF_FPOP },
1109 { "emms", OP_EMMS, 0, 0, OPF_DATA },
1110 { "movq", OP_MOV, 2, 2, OPF_DATA },
1111 // pseudo-ops for lib calls
1112 { "_allshl",OPP_ALLSHL },
1113 { "_allshr",OPP_ALLSHR },
1114 { "_ftol", OPP_FTOL },
1115 { "_CIpow", OPP_CIPOW },
1120 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
1122 enum opr_lenmod lmod = OPLM_UNSPEC;
1123 int prefix_flags = 0;
1131 for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
1132 if (IS(words[w], pref_table[i].name)) {
1133 prefix_flags = pref_table[i].flags;
1140 aerr("lone prefix: '%s'\n", words[0]);
1145 for (i = 0; i < ARRAY_SIZE(op_table); i++) {
1146 if (IS(words[w], op_table[i].name))
1150 if (i == ARRAY_SIZE(op_table)) {
1152 aerr("unhandled op: '%s'\n", words[0]);
1157 op->op = op_table[i].op;
1158 op->flags = op_table[i].flags | prefix_flags;
1159 op->pfo = op_table[i].pfo;
1160 op->pfo_inv = op_table[i].pfo_inv;
1161 op->regmask_src = op->regmask_dst = 0;
1164 if (op->op == OP_UD2)
1167 for (opr = 0; opr < op_table[i].maxopr; opr++) {
1168 if (opr >= op_table[i].minopr && w >= wordc)
1171 regmask = regmask_ind = 0;
1172 w = parse_operand(&op->operand[opr], ®mask, ®mask_ind,
1173 words, wordc, w, op->flags);
1175 if (opr == 0 && (op->flags & OPF_DATA))
1176 op->regmask_dst = regmask;
1178 op->regmask_src |= regmask;
1179 op->regmask_src |= regmask_ind;
1181 if (op->operand[opr].lmod != OPLM_UNSPEC)
1182 g_func_lmods |= 1 << op->operand[opr].lmod;
1186 aerr("parse_op %s incomplete: %d/%d\n",
1187 words[0], w, wordc);
1190 op->operand_cnt = opr;
1191 if (!strncmp(op_table[i].name, "set", 3))
1192 op->operand[0].lmod = OPLM_BYTE;
1195 // first operand is not dst
1198 op->regmask_src |= op->regmask_dst;
1199 op->regmask_dst = 0;
1202 // first operand is src too
1215 op->regmask_src |= op->regmask_dst;
1220 op->regmask_src |= op->regmask_dst;
1221 op->regmask_dst |= op->regmask_src;
1227 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1228 && op->operand[0].lmod == op->operand[1].lmod
1229 && op->operand[0].reg == op->operand[1].reg
1230 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1232 op->regmask_src = 0;
1235 op->regmask_src |= op->regmask_dst;
1238 // ops with implicit argumets
1240 op->operand_cnt = 2;
1241 setup_reg_opr(&op->operand[0], xAX, OPLM_BYTE, &op->regmask_src);
1242 op->regmask_dst = op->regmask_src;
1243 setup_reg_opr(&op->operand[1], xBX, OPLM_DWORD, &op->regmask_src);
1247 op->operand_cnt = 2;
1248 setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
1249 setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
1255 if (words[op_w][4] == 'b')
1257 else if (words[op_w][4] == 'w')
1259 else if (words[op_w][4] == 'd')
1262 op->regmask_src = 0;
1263 setup_reg_opr(&op->operand[j++], op->op == OP_LODS ? xSI : xDI,
1264 OPLM_DWORD, &op->regmask_src);
1265 op->regmask_dst = op->regmask_src;
1266 setup_reg_opr(&op->operand[j++], xAX, lmod,
1267 op->op == OP_LODS ? &op->regmask_dst : &op->regmask_src);
1268 if (op->flags & OPF_REP) {
1269 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1270 op->regmask_dst |= 1 << xCX;
1272 op->operand_cnt = j;
1277 if (words[op_w][4] == 'b')
1279 else if (words[op_w][4] == 'w')
1281 else if (words[op_w][4] == 'd')
1284 op->regmask_src = 0;
1285 // note: lmod is not correct, don't have where to place it
1286 setup_reg_opr(&op->operand[j++], xDI, lmod, &op->regmask_src);
1287 setup_reg_opr(&op->operand[j++], xSI, OPLM_DWORD, &op->regmask_src);
1288 if (op->flags & OPF_REP)
1289 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1290 op->operand_cnt = j;
1291 op->regmask_dst = op->regmask_src;
1295 op->regmask_dst = 1 << xCX;
1298 op->operand_cnt = 2;
1299 op->regmask_src = 1 << xCX;
1300 op->operand[1].type = OPT_REG;
1301 op->operand[1].reg = xCX;
1302 op->operand[1].lmod = OPLM_DWORD;
1306 if (op->operand_cnt == 2) {
1307 if (op->operand[0].type != OPT_REG)
1308 aerr("reg expected\n");
1309 op->regmask_src |= 1 << op->operand[0].reg;
1311 if (op->operand_cnt != 1)
1316 op->regmask_src |= op->regmask_dst;
1317 op->regmask_dst = (1 << xDX) | (1 << xAX);
1318 if (op->operand[0].lmod == OPLM_UNSPEC)
1319 op->operand[0].lmod = OPLM_DWORD;
1324 // we could set up operands for edx:eax, but there is no real need to
1325 // (see is_opr_modified())
1326 op->regmask_src |= op->regmask_dst;
1327 op->regmask_dst = (1 << xDX) | (1 << xAX);
1328 if (op->operand[0].lmod == OPLM_UNSPEC)
1329 op->operand[0].lmod = OPLM_DWORD;
1337 op->regmask_src |= op->regmask_dst;
1338 if (op->operand[1].lmod == OPLM_UNSPEC)
1339 op->operand[1].lmod = OPLM_BYTE;
1344 op->regmask_src |= op->regmask_dst;
1345 if (op->operand[2].lmod == OPLM_UNSPEC)
1346 op->operand[2].lmod = OPLM_BYTE;
1350 op->regmask_src |= op->regmask_dst;
1351 op->regmask_dst = 0;
1352 if (op->operand[0].lmod == OPLM_UNSPEC
1353 && (op->operand[0].type == OPT_CONST
1354 || op->operand[0].type == OPT_OFFSET
1355 || op->operand[0].type == OPT_LABEL))
1356 op->operand[0].lmod = OPLM_DWORD;
1362 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1363 && op->operand[0].lmod == op->operand[1].lmod
1364 && op->operand[0].reg == op->operand[1].reg
1365 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1367 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1368 op->regmask_src = op->regmask_dst = 0;
1373 if (op->operand[0].type == OPT_REG
1374 && op->operand[1].type == OPT_REGMEM)
1377 snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1378 if (IS(buf, op->operand[1].name))
1379 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1384 // trashed regs must be explicitly detected later
1385 op->regmask_dst = 0;
1389 op->regmask_dst = (1 << xBP) | (1 << xSP);
1390 op->regmask_src = 1 << xBP;
1395 op->regmask_dst |= mxST0;
1399 op->regmask_dst |= mxST0;
1400 if (IS(words[op_w] + 3, "1"))
1401 op->operand[0].val = X87_CONST_1;
1402 else if (IS(words[op_w] + 3, "ln2"))
1403 op->operand[0].val = X87_CONST_LN2;
1404 else if (IS(words[op_w] + 3, "z"))
1405 op->operand[0].val = X87_CONST_Z;
1412 op->regmask_src |= mxST0;
1421 op->regmask_src |= mxST0;
1422 if (op->operand_cnt == 2)
1423 op->regmask_src |= op->regmask_dst;
1424 else if (op->operand_cnt == 1) {
1425 memcpy(&op->operand[1], &op->operand[0], sizeof(op->operand[1]));
1426 op->operand[0].type = OPT_REG;
1427 op->operand[0].lmod = OPLM_QWORD;
1428 op->operand[0].reg = xST0;
1429 op->regmask_dst |= mxST0;
1432 // IDA doesn't use this
1433 aerr("no operands?\n");
1447 op->regmask_src |= mxST0;
1448 op->regmask_dst |= mxST0;
1453 op->regmask_src |= mxST0 | mxST1;
1454 op->regmask_dst |= mxST0;
1462 op->regmask_src |= mxST0;
1469 if (op->operand[0].type == OPT_REG
1470 && op->operand[1].type == OPT_CONST)
1472 struct parsed_opr *op1 = &op->operand[1];
1473 if ((op->op == OP_AND && op1->val == 0)
1476 || (op->operand[0].lmod == OPLM_WORD && op1->val == 0xffff)
1477 || (op->operand[0].lmod == OPLM_BYTE && op1->val == 0xff))))
1479 op->regmask_src = 0;
1484 static const char *op_name(struct parsed_op *po)
1486 static char buf[16];
1490 if (po->op == OP_JCC || po->op == OP_SCC) {
1492 *p++ = (po->op == OP_JCC) ? 'j' : 's';
1495 strcpy(p, parsed_flag_op_names[po->pfo]);
1499 for (i = 0; i < ARRAY_SIZE(op_table); i++)
1500 if (op_table[i].op == po->op)
1501 return op_table[i].name;
1507 static const char *dump_op(struct parsed_op *po)
1509 static char out[128];
1516 snprintf(out, sizeof(out), "%s", op_name(po));
1517 for (i = 0; i < po->operand_cnt; i++) {
1521 snprintf(p, sizeof(out) - (p - out),
1522 po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1523 po->operand[i].name);
1529 static const char *lmod_type_u(struct parsed_op *po,
1530 enum opr_lenmod lmod)
1542 ferr(po, "invalid lmod: %d\n", lmod);
1543 return "(_invalid_)";
1547 static const char *lmod_cast_u(struct parsed_op *po,
1548 enum opr_lenmod lmod)
1560 ferr(po, "invalid lmod: %d\n", lmod);
1561 return "(_invalid_)";
1565 static const char *lmod_cast_u_ptr(struct parsed_op *po,
1566 enum opr_lenmod lmod)
1578 ferr(po, "invalid lmod: %d\n", lmod);
1579 return "(_invalid_)";
1583 static const char *lmod_cast_s(struct parsed_op *po,
1584 enum opr_lenmod lmod)
1596 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1597 return "(_invalid_)";
1601 static const char *lmod_cast(struct parsed_op *po,
1602 enum opr_lenmod lmod, int is_signed)
1605 lmod_cast_s(po, lmod) :
1606 lmod_cast_u(po, lmod);
1609 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1621 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1626 static const char *opr_name(struct parsed_op *po, int opr_num)
1628 if (opr_num >= po->operand_cnt)
1629 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1630 return po->operand[opr_num].name;
1633 static unsigned int opr_const(struct parsed_op *po, int opr_num)
1635 if (opr_num >= po->operand_cnt)
1636 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1637 if (po->operand[opr_num].type != OPT_CONST)
1638 ferr(po, "opr %d: const expected\n", opr_num);
1639 return po->operand[opr_num].val;
1642 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1644 if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
1645 ferr(po, "invalid reg: %d\n", popr->reg);
1646 return regs_r32[popr->reg];
1649 static int check_simple_cast(const char *cast, int *bits, int *is_signed)
1651 if (IS_START(cast, "(s8)") || IS_START(cast, "(u8)"))
1653 else if (IS_START(cast, "(s16)") || IS_START(cast, "(u16)"))
1655 else if (IS_START(cast, "(s32)") || IS_START(cast, "(u32)"))
1657 else if (IS_START(cast, "(s64)") || IS_START(cast, "(u64)"))
1662 *is_signed = cast[1] == 's' ? 1 : 0;
1666 static int check_deref_cast(const char *cast, int *bits)
1668 if (IS_START(cast, "*(u8 *)"))
1670 else if (IS_START(cast, "*(u16 *)"))
1672 else if (IS_START(cast, "*(u32 *)"))
1674 else if (IS_START(cast, "*(u64 *)"))
1682 // cast1 is the "final" cast
1683 static const char *simplify_cast(const char *cast1, const char *cast2)
1685 static char buf[256];
1693 if (IS(cast1, cast2))
1696 if (check_simple_cast(cast1, &bits1, &s1) == 0
1697 && check_simple_cast(cast2, &bits2, &s2) == 0)
1702 if (check_simple_cast(cast1, &bits1, &s1) == 0
1703 && check_deref_cast(cast2, &bits2) == 0)
1705 if (bits1 == bits2) {
1706 snprintf(buf, sizeof(buf), "*(%c%d *)", s1 ? 's' : 'u', bits1);
1711 if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1714 snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1718 static const char *simplify_cast_num(const char *cast, unsigned int val)
1720 if (IS(cast, "(u8)") && val < 0x100)
1722 if (IS(cast, "(s8)") && val < 0x80)
1724 if (IS(cast, "(u16)") && val < 0x10000)
1726 if (IS(cast, "(s16)") && val < 0x8000)
1728 if (IS(cast, "(s32)") && val < 0x80000000)
1734 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1743 namelen = strlen(name);
1745 p = strpbrk(name, "+-");
1749 ferr(po, "equ parse failed for '%s'\n", name);
1752 *extra_offs = strtol(p, &endp, 16);
1753 if (*endp != 0 || errno != 0)
1754 ferr(po, "equ parse failed for '%s'\n", name);
1757 for (i = 0; i < g_eqcnt; i++)
1758 if (strncmp(g_eqs[i].name, name, namelen) == 0
1759 && g_eqs[i].name[namelen] == 0)
1763 ferr(po, "unresolved equ name: '%s'\n", name);
1770 static int is_stack_access(struct parsed_op *po,
1771 const struct parsed_opr *popr)
1773 return (parse_stack_el(popr->name, NULL, NULL, 0)
1774 || (g_bp_frame && !(po->flags & OPF_EBP_S)
1775 && IS_START(popr->name, "ebp")));
1778 static void parse_stack_access(struct parsed_op *po,
1779 const char *name, char *ofs_reg, int *offset_out,
1780 int *stack_ra_out, const char **bp_arg_out, int is_lea)
1782 const char *bp_arg = "";
1783 const char *p = NULL;
1784 struct parsed_equ *eq;
1791 if (IS_START(name, "ebp-")
1792 || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1795 if (IS_START(p, "0x"))
1798 offset = strtoul(p, &endp, 16);
1801 if (*endp != 0 || errno != 0)
1802 ferr(po, "ebp- parse of '%s' failed\n", name);
1805 bp_arg = parse_stack_el(name, ofs_reg, NULL, 0);
1806 eq = equ_find(po, bp_arg, &offset);
1808 ferr(po, "detected but missing eq\n");
1809 offset += eq->offset;
1812 if (!strncmp(name, "ebp", 3))
1815 // yes it sometimes LEAs ra for compares..
1816 if (!is_lea && ofs_reg[0] == 0
1817 && stack_ra <= offset && offset < stack_ra + 4)
1819 ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1822 *offset_out = offset;
1824 *stack_ra_out = stack_ra;
1826 *bp_arg_out = bp_arg;
1829 static int parse_stack_esp_offset(struct parsed_op *po,
1830 const char *name, int *offset_out)
1832 char ofs_reg[16] = { 0, };
1833 struct parsed_equ *eq;
1839 if (strstr(name, "esp") == NULL)
1841 bp_arg = parse_stack_el(name, ofs_reg, &base_val, 0);
1842 if (bp_arg == NULL) {
1843 // just plain offset?
1844 if (!IS_START(name, "esp+"))
1847 offset = strtol(name + 4, &endp, 0);
1848 if (endp == NULL || *endp != 0 || errno != 0)
1850 *offset_out = offset;
1854 if (ofs_reg[0] != 0)
1856 eq = equ_find(po, bp_arg, &offset);
1858 ferr(po, "detected but missing eq\n");
1859 offset += eq->offset;
1860 *offset_out = base_val + offset;
1864 static int stack_frame_access(struct parsed_op *po,
1865 struct parsed_opr *popr, char *buf, size_t buf_size,
1866 const char *name, const char *cast, int is_src, int is_lea)
1868 enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1869 const char *prefix = "";
1870 const char *bp_arg = NULL;
1871 char ofs_reg[16] = { 0, };
1872 int i, arg_i, arg_s;
1879 if (po->flags & OPF_EBP_S)
1880 ferr(po, "stack_frame_access while ebp is scratch\n");
1882 parse_stack_access(po, name, ofs_reg, &offset,
1883 &stack_ra, &bp_arg, is_lea);
1885 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1887 if (offset > stack_ra)
1889 arg_i = (offset - stack_ra - 4) / 4;
1890 if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1892 if (g_func_pp->is_vararg
1893 && arg_i == g_func_pp->argc_stack && is_lea)
1895 // should be va_list
1898 snprintf(buf, buf_size, "%sap", cast);
1901 ferr(po, "offset %d (%s,%d) doesn't map to any arg\n",
1902 offset, bp_arg, arg_i);
1904 if (ofs_reg[0] != 0)
1905 ferr(po, "offset reg on arg access?\n");
1907 for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1908 if (g_func_pp->arg[i].reg != NULL)
1914 if (i == g_func_pp->argc)
1915 ferr(po, "arg %d not in prototype?\n", arg_i);
1917 popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
1924 ferr(po, "lea/byte to arg?\n");
1925 if (is_src && (offset & 3) == 0)
1926 snprintf(buf, buf_size, "%sa%d",
1927 simplify_cast(cast, "(u8)"), i + 1);
1929 snprintf(buf, buf_size, "%sBYTE%d(a%d)",
1930 cast, offset & 3, i + 1);
1935 ferr(po, "lea/word to arg?\n");
1940 ferr(po, "problematic arg store\n");
1941 snprintf(buf, buf_size, "%s((char *)&a%d + 1)",
1942 simplify_cast(cast, "*(u16 *)"), i + 1);
1945 ferr(po, "unaligned arg word load\n");
1947 else if (is_src && (offset & 2) == 0)
1948 snprintf(buf, buf_size, "%sa%d",
1949 simplify_cast(cast, "(u16)"), i + 1);
1951 snprintf(buf, buf_size, "%s%sWORD(a%d)",
1952 cast, (offset & 2) ? "HI" : "LO", i + 1);
1964 snprintf(buf, buf_size, "(u32)&a%d + %d",
1967 ferr(po, "unaligned arg store\n");
1969 // mov edx, [ebp+arg_4+2]; movsx ecx, dx
1970 snprintf(buf, buf_size, "%s(a%d >> %d)",
1971 prefix, i + 1, (offset & 3) * 8);
1975 snprintf(buf, buf_size, "%s%sa%d",
1976 prefix, is_lea ? "&" : "", i + 1);
1981 ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
1985 strcat(g_comment, " unaligned");
1988 guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
1989 if (tmp_lmod != OPLM_DWORD
1990 && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
1991 < lmod_bytes(po, popr->lmod) + (offset & 3))))
1993 ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
1994 i + 1, offset, g_func_pp->arg[i].type.name);
1996 // can't check this because msvc likes to reuse
1997 // arg space for scratch..
1998 //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
1999 // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
2003 if (g_stack_fsz == 0)
2004 ferr(po, "stack var access without stackframe\n");
2005 g_stack_frame_used = 1;
2007 sf_ofs = g_stack_fsz + offset;
2008 if (ofs_reg[0] == 0 && (offset > 0 || sf_ofs < 0))
2009 ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
2019 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2020 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2024 if ((sf_ofs & 1) || ofs_reg[0] != 0) {
2025 // known unaligned or possibly unaligned
2026 strcat(g_comment, " unaligned");
2028 prefix = "*(u16 *)&";
2029 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2030 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2033 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
2037 if ((sf_ofs & 3) || ofs_reg[0] != 0) {
2038 // known unaligned or possibly unaligned
2039 strcat(g_comment, " unaligned");
2041 prefix = "*(u32 *)&";
2042 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2043 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2046 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
2050 ferr_assert(po, !(sf_ofs & 7));
2051 ferr_assert(po, ofs_reg[0] == 0);
2052 // only used for x87 int64/float, float sets is_lea
2054 snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
2056 snprintf(buf, buf_size, "*(s64 *)&sf.q[%d]", sf_ofs / 8);
2060 ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
2067 static void check_func_pp(struct parsed_op *po,
2068 const struct parsed_proto *pp, const char *pfx)
2070 enum opr_lenmod tmp_lmod;
2074 if (pp->argc_reg != 0) {
2075 if (!g_allow_user_icall && !pp->is_fastcall) {
2076 pp_print(buf, sizeof(buf), pp);
2077 ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
2079 if (pp->argc_stack > 0 && pp->argc_reg != 2)
2080 ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
2081 pfx, pp->argc_reg, pp->argc_stack);
2084 // fptrs must use 32bit args, callsite might have no information and
2085 // lack a cast to smaller types, which results in incorrectly masked
2086 // args passed (callee may assume masked args, it does on ARM)
2087 if (!pp->is_osinc) {
2088 for (i = 0; i < pp->argc; i++) {
2089 ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
2090 if (ret && tmp_lmod != OPLM_DWORD)
2091 ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
2092 i + 1, pp->arg[i].type.name);
2097 static const char *check_label_read_ref(struct parsed_op *po,
2100 const struct parsed_proto *pp;
2102 pp = proto_parse(g_fhdr, name, 0);
2104 ferr(po, "proto_parse failed for ref '%s'\n", name);
2107 check_func_pp(po, pp, "ref");
2112 static char *out_src_opr(char *buf, size_t buf_size,
2113 struct parsed_op *po, struct parsed_opr *popr, const char *cast,
2116 char tmp1[256], tmp2[256];
2125 switch (popr->type) {
2128 ferr(po, "lea from reg?\n");
2130 switch (popr->lmod) {
2132 snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2135 snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2138 snprintf(buf, buf_size, "%s%s",
2139 simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2142 if (popr->name[1] == 'h') // XXX..
2143 snprintf(buf, buf_size, "%s(%s >> 8)",
2144 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2146 snprintf(buf, buf_size, "%s%s",
2147 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2150 ferr(po, "invalid src lmod: %d\n", popr->lmod);
2155 if (is_stack_access(po, popr)) {
2156 stack_frame_access(po, popr, buf, buf_size,
2157 popr->name, cast, 1, is_lea);
2161 strcpy(expr, popr->name);
2162 if (strchr(expr, '[')) {
2163 // special case: '[' can only be left for label[reg] form
2164 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2166 ferr(po, "parse failure for '%s'\n", expr);
2167 if (tmp1[0] == '(') {
2168 // (off_4FFF50+3)[eax]
2169 p = strchr(tmp1 + 1, ')');
2170 if (p == NULL || p[1] != 0)
2171 ferr(po, "parse failure (2) for '%s'\n", expr);
2173 memmove(tmp1, tmp1 + 1, strlen(tmp1));
2175 snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2178 // XXX: do we need more parsing?
2180 snprintf(buf, buf_size, "%s", expr);
2184 snprintf(buf, buf_size, "%s(%s)",
2185 simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2189 name = check_label_read_ref(po, popr->name);
2190 if (cast[0] == 0 && popr->is_ptr)
2194 snprintf(buf, buf_size, "(u32)&%s", name);
2195 else if (popr->size_lt)
2196 snprintf(buf, buf_size, "%s%s%s%s", cast,
2197 lmod_cast_u_ptr(po, popr->lmod),
2198 popr->is_array ? "" : "&", name);
2200 snprintf(buf, buf_size, "%s%s%s", cast, name,
2201 popr->is_array ? "[0]" : "");
2205 name = check_label_read_ref(po, popr->name);
2209 ferr(po, "lea an offset?\n");
2210 snprintf(buf, buf_size, "%s&%s", cast, name);
2215 ferr(po, "lea from const?\n");
2217 printf_number(tmp1, sizeof(tmp1), popr->val);
2218 if (popr->val == 0 && strchr(cast, '*'))
2219 snprintf(buf, buf_size, "NULL");
2221 snprintf(buf, buf_size, "%s%s",
2222 simplify_cast_num(cast, popr->val), tmp1);
2226 ferr(po, "invalid src type: %d\n", popr->type);
2232 // note: may set is_ptr (we find that out late for ebp frame..)
2233 static char *out_dst_opr(char *buf, size_t buf_size,
2234 struct parsed_op *po, struct parsed_opr *popr)
2236 switch (popr->type) {
2238 switch (popr->lmod) {
2240 snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2243 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2247 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2251 if (popr->name[1] == 'h') // XXX..
2252 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2254 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2257 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2262 if (is_stack_access(po, popr)) {
2263 stack_frame_access(po, popr, buf, buf_size,
2264 popr->name, "", 0, 0);
2268 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2271 if (popr->size_mismatch)
2272 snprintf(buf, buf_size, "%s%s%s",
2273 lmod_cast_u_ptr(po, popr->lmod),
2274 popr->is_array ? "" : "&", popr->name);
2276 snprintf(buf, buf_size, "%s%s", popr->name,
2277 popr->is_array ? "[0]" : "");
2281 ferr(po, "invalid dst type: %d\n", popr->type);
2287 static char *out_src_opr_u32(char *buf, size_t buf_size,
2288 struct parsed_op *po, struct parsed_opr *popr)
2290 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2293 static char *out_src_opr_float(char *buf, size_t buf_size,
2294 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2296 const char *cast = NULL;
2299 switch (popr->type) {
2301 if (popr->reg < xST0 || popr->reg > xST7)
2302 ferr(po, "bad reg: %d\n", popr->reg);
2304 if (need_float_stack) {
2305 if (popr->reg == xST0)
2306 snprintf(buf, buf_size, "f_st[f_stp & 7]");
2308 snprintf(buf, buf_size, "f_st[(f_stp + %d) & 7]",
2312 snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2318 switch (popr->lmod) {
2326 ferr(po, "unhandled lmod: %d\n", popr->lmod);
2329 out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2330 snprintf(buf, buf_size, "*(%s *)(%s)", cast, tmp);
2334 ferr(po, "invalid float type: %d\n", popr->type);
2340 static char *out_dst_opr_float(char *buf, size_t buf_size,
2341 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2344 return out_src_opr_float(buf, buf_size, po, popr, need_float_stack);
2347 static void out_test_for_cc(char *buf, size_t buf_size,
2348 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2349 enum opr_lenmod lmod, const char *expr)
2351 const char *cast, *scast;
2353 cast = lmod_cast_u(po, lmod);
2354 scast = lmod_cast_s(po, lmod);
2358 case PFO_BE: // CF==1||ZF==1; CF=0
2359 snprintf(buf, buf_size, "(%s%s %s 0)",
2360 cast, expr, is_inv ? "!=" : "==");
2364 case PFO_L: // SF!=OF; OF=0
2365 snprintf(buf, buf_size, "(%s%s %s 0)",
2366 scast, expr, is_inv ? ">=" : "<");
2369 case PFO_LE: // ZF==1||SF!=OF; OF=0
2370 snprintf(buf, buf_size, "(%s%s %s 0)",
2371 scast, expr, is_inv ? ">" : "<=");
2376 snprintf(buf, buf_size, "(%d)", !!is_inv);
2380 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2384 static void out_cmp_for_cc(char *buf, size_t buf_size,
2385 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2388 const char *cast, *scast, *cast_use;
2389 char buf1[256], buf2[256];
2390 enum opr_lenmod lmod;
2392 if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2393 ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2394 po->operand[0].lmod, po->operand[1].lmod);
2395 lmod = po->operand[0].lmod;
2397 cast = lmod_cast_u(po, lmod);
2398 scast = lmod_cast_s(po, lmod);
2414 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2417 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2418 if (po->op == OP_DEC)
2419 snprintf(buf2, sizeof(buf2), "1");
2422 snprintf(cast_op2, sizeof(cast_op2) - 1, "%s", cast_use);
2424 strcat(cast_op2, "-");
2425 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_op2, 0);
2430 // note: must be unsigned compare
2431 snprintf(buf, buf_size, "(%s %s %s)",
2432 buf1, is_inv ? ">=" : "<", buf2);
2436 snprintf(buf, buf_size, "(%s %s %s)",
2437 buf1, is_inv ? "!=" : "==", buf2);
2441 // note: must be unsigned compare
2442 snprintf(buf, buf_size, "(%s %s %s)",
2443 buf1, is_inv ? ">" : "<=", buf2);
2446 if (is_inv && lmod == OPLM_BYTE
2447 && po->operand[1].type == OPT_CONST
2448 && po->operand[1].val == 0xff)
2450 snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2451 snprintf(buf, buf_size, "(0)");
2455 // note: must be signed compare
2457 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2458 scast, buf1, buf2, is_inv ? ">=" : "<");
2462 snprintf(buf, buf_size, "(%s %s %s)",
2463 buf1, is_inv ? ">=" : "<", buf2);
2467 snprintf(buf, buf_size, "(%s %s %s)",
2468 buf1, is_inv ? ">" : "<=", buf2);
2476 static void out_cmp_test(char *buf, size_t buf_size,
2477 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2479 char buf1[256], buf2[256], buf3[256];
2481 if (po->op == OP_TEST) {
2482 if (IS(opr_name(po, 0), opr_name(po, 1))) {
2483 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2486 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2487 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2488 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2490 out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2491 po->operand[0].lmod, buf3);
2493 else if (po->op == OP_CMP) {
2494 out_cmp_for_cc(buf, buf_size, po, pfo, is_inv, 0);
2497 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2500 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2501 struct parsed_opr *popr2)
2503 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2504 ferr(po, "missing lmod for both operands\n");
2506 if (popr1->lmod == OPLM_UNSPEC)
2507 popr1->lmod = popr2->lmod;
2508 else if (popr2->lmod == OPLM_UNSPEC)
2509 popr2->lmod = popr1->lmod;
2510 else if (popr1->lmod != popr2->lmod) {
2511 if (popr1->type_from_var) {
2512 popr1->size_mismatch = 1;
2513 if (popr1->lmod < popr2->lmod)
2515 popr1->lmod = popr2->lmod;
2517 else if (popr2->type_from_var) {
2518 popr2->size_mismatch = 1;
2519 if (popr2->lmod < popr1->lmod)
2521 popr2->lmod = popr1->lmod;
2524 ferr(po, "conflicting lmods: %d vs %d\n",
2525 popr1->lmod, popr2->lmod);
2529 static const char *op_to_c(struct parsed_op *po)
2553 ferr(po, "op_to_c was supplied with %d\n", po->op);
2557 // last op in stream - unconditional branch or ret
2558 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2559 || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2560 && ops[_i].op != OP_CALL))
2562 #define check_i(po, i) \
2564 ferr(po, "bad " #i ": %d\n", i)
2566 // note: this skips over calls and rm'd stuff assuming they're handled
2567 // so it's intended to use at one of final passes
2568 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2569 int depth, int seen_noreturn, int flags_set)
2571 struct parsed_op *po;
2576 for (; i < opcnt; i++) {
2578 if (po->cc_scratch == magic)
2579 return ret; // already checked
2580 po->cc_scratch = magic;
2582 if (po->flags & OPF_TAIL) {
2583 if (po->op == OP_CALL) {
2584 if (po->pp != NULL && po->pp->is_noreturn)
2593 if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
2596 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2597 if (po->btj != NULL) {
2599 for (j = 0; j < po->btj->count; j++) {
2600 check_i(po, po->btj->d[j].bt_i);
2601 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2602 depth, seen_noreturn, flags_set);
2604 return ret; // dead end
2609 check_i(po, po->bt_i);
2610 if (po->flags & OPF_CJMP) {
2611 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2612 depth, seen_noreturn, flags_set);
2614 return ret; // dead end
2623 if ((po->op == OP_POP || po->op == OP_PUSH)
2624 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2629 if (po->op == OP_PUSH) {
2632 else if (po->op == OP_POP) {
2633 if (relevant && depth == 0) {
2634 po->flags |= flags_set;
2642 // for noreturn, assume msvc skipped stack cleanup
2643 return seen_noreturn ? 1 : -1;
2646 // scan for 'reg' pop backwards starting from i
2647 // intended to use for register restore search, so other reg
2648 // references are considered an error
2649 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2651 struct parsed_op *po;
2652 struct label_ref *lr;
2655 ops[i].cc_scratch = magic;
2659 if (g_labels[i] != NULL) {
2660 lr = &g_label_refs[i];
2661 for (; lr != NULL; lr = lr->next) {
2662 check_i(&ops[i], lr->i);
2663 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2667 if (i > 0 && LAST_OP(i - 1))
2675 if (ops[i].cc_scratch == magic)
2677 ops[i].cc_scratch = magic;
2680 if (po->op == OP_POP && po->operand[0].reg == reg) {
2681 if (po->flags & (OPF_RMD|OPF_DONE))
2684 po->flags |= set_flags;
2688 // this also covers the case where we reach corresponding push
2689 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2693 // nothing interesting on this path,
2694 // still return ret for something recursive calls could find
2698 static void find_reachable_exits(int i, int opcnt, int magic,
2699 int *exits, int *exit_count)
2701 struct parsed_op *po;
2704 for (; i < opcnt; i++)
2707 if (po->cc_scratch == magic)
2709 po->cc_scratch = magic;
2711 if (po->flags & OPF_TAIL) {
2712 ferr_assert(po, *exit_count < MAX_EXITS);
2713 exits[*exit_count] = i;
2718 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2719 if (po->flags & OPF_RMD)
2722 if (po->btj != NULL) {
2723 for (j = 0; j < po->btj->count; j++) {
2724 check_i(po, po->btj->d[j].bt_i);
2725 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2731 check_i(po, po->bt_i);
2732 if (po->flags & OPF_CJMP)
2733 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2741 // scan for 'reg' pop backwards starting from exits (all paths)
2742 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2744 static int exits[MAX_EXITS];
2745 static int exit_count;
2751 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2753 ferr_assert(&ops[i], exit_count > 0);
2756 for (j = 0; j < exit_count; j++) {
2758 ret = scan_for_rsave_pop_reg(e, i + opcnt * 16 + set_flags,
2764 if (ops[e].op == OP_CALL && ops[e].pp != NULL
2765 && ops[e].pp->is_noreturn)
2767 // assume stack cleanup was skipped
2776 // scan for one or more pop of push <const>
2777 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2778 int push_i, int is_probe)
2780 struct parsed_op *po;
2781 struct label_ref *lr;
2785 for (; i < opcnt; i++)
2788 if (po->cc_scratch == magic)
2789 return ret; // already checked
2790 po->cc_scratch = magic;
2792 if (po->flags & OPF_JMP) {
2793 if (po->flags & OPF_RMD)
2795 if (po->op == OP_CALL)
2798 if (po->btj != NULL) {
2799 for (j = 0; j < po->btj->count; j++) {
2800 check_i(po, po->btj->d[j].bt_i);
2801 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2809 check_i(po, po->bt_i);
2810 if (po->flags & OPF_CJMP) {
2811 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2822 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2825 if (g_labels[i] != NULL) {
2826 // all refs must be visited
2827 lr = &g_label_refs[i];
2828 for (; lr != NULL; lr = lr->next) {
2830 if (ops[lr->i].cc_scratch != magic)
2833 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2837 if (po->op == OP_POP)
2839 if (po->flags & (OPF_RMD|OPF_DONE))
2843 po->flags |= OPF_DONE;
2844 po->datap = &ops[push_i];
2853 static void scan_for_pop_const(int i, int opcnt, int magic)
2857 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
2859 ops[i].flags |= OPF_RMD | OPF_DONE;
2860 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
2864 // check if all branch targets within a marked path are also marked
2865 // note: the path checked must not be empty or end with a branch
2866 static int check_path_branches(int opcnt, int magic)
2868 struct parsed_op *po;
2871 for (i = 0; i < opcnt; i++) {
2873 if (po->cc_scratch != magic)
2876 if (po->flags & OPF_JMP) {
2877 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
2880 if (po->btj != NULL) {
2881 for (j = 0; j < po->btj->count; j++) {
2882 check_i(po, po->btj->d[j].bt_i);
2883 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
2888 check_i(po, po->bt_i);
2889 if (ops[po->bt_i].cc_scratch != magic)
2891 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
2899 // scan for multiple pushes for given pop
2900 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
2903 int reg = ops[pop_i].operand[0].reg;
2904 struct parsed_op *po;
2905 struct label_ref *lr;
2908 ops[i].cc_scratch = magic;
2912 if (g_labels[i] != NULL) {
2913 lr = &g_label_refs[i];
2914 for (; lr != NULL; lr = lr->next) {
2915 check_i(&ops[i], lr->i);
2916 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
2920 if (i > 0 && LAST_OP(i - 1))
2928 if (ops[i].cc_scratch == magic)
2930 ops[i].cc_scratch = magic;
2933 if (po->op == OP_CALL)
2935 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
2938 if (po->op == OP_PUSH)
2940 if (po->datap != NULL)
2942 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2943 // leave this case for reg save/restore handlers
2947 po->flags |= OPF_PPUSH | OPF_DONE;
2948 po->datap = &ops[pop_i];
2957 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
2959 int magic = i + opcnt * 14;
2962 ret = scan_pushes_for_pop_r(i, magic, i, 1);
2964 ret = check_path_branches(opcnt, magic);
2966 ops[i].flags |= OPF_PPUSH | OPF_DONE;
2967 *regmask_pp |= 1 << ops[i].operand[0].reg;
2968 scan_pushes_for_pop_r(i, magic + 1, i, 0);
2973 static void scan_propagate_df(int i, int opcnt)
2975 struct parsed_op *po = &ops[i];
2978 for (; i < opcnt; i++) {
2980 if (po->flags & OPF_DF)
2981 return; // already resolved
2982 po->flags |= OPF_DF;
2984 if (po->op == OP_CALL)
2985 ferr(po, "call with DF set?\n");
2987 if (po->flags & OPF_JMP) {
2988 if (po->btj != NULL) {
2990 for (j = 0; j < po->btj->count; j++) {
2991 check_i(po, po->btj->d[j].bt_i);
2992 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
2997 if (po->flags & OPF_RMD)
2999 check_i(po, po->bt_i);
3000 if (po->flags & OPF_CJMP)
3001 scan_propagate_df(po->bt_i, opcnt);
3007 if (po->flags & OPF_TAIL)
3010 if (po->op == OP_CLD) {
3011 po->flags |= OPF_RMD | OPF_DONE;
3016 ferr(po, "missing DF clear?\n");
3019 // is operand 'opr' referenced by parsed_op 'po'?
3020 static int is_opr_referenced(const struct parsed_opr *opr,
3021 const struct parsed_op *po)
3025 if (opr->type == OPT_REG) {
3026 mask = po->regmask_dst | po->regmask_src;
3027 if (po->op == OP_CALL)
3028 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
3029 if ((1 << opr->reg) & mask)
3035 for (i = 0; i < po->operand_cnt; i++)
3036 if (IS(po->operand[0].name, opr->name))
3042 // is operand 'opr' read by parsed_op 'po'?
3043 static int is_opr_read(const struct parsed_opr *opr,
3044 const struct parsed_op *po)
3046 if (opr->type == OPT_REG) {
3047 if (po->regmask_src & (1 << opr->reg))
3057 // is operand 'opr' modified by parsed_op 'po'?
3058 static int is_opr_modified(const struct parsed_opr *opr,
3059 const struct parsed_op *po)
3063 if (opr->type == OPT_REG) {
3064 if (po->op == OP_CALL) {
3065 mask = po->regmask_dst;
3066 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
3067 if (mask & (1 << opr->reg))
3073 if (po->regmask_dst & (1 << opr->reg))
3079 return IS(po->operand[0].name, opr->name);
3082 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
3083 static int is_any_opr_modified(const struct parsed_op *po_test,
3084 const struct parsed_op *po, int c_mode)
3089 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
3092 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3095 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
3098 // in reality, it can wreck any register, but in decompiled C
3099 // version it can only overwrite eax or edx:eax
3100 mask = (1 << xAX) | (1 << xDX);
3104 if (po->op == OP_CALL
3105 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
3108 for (i = 0; i < po_test->operand_cnt; i++)
3109 if (IS(po_test->operand[i].name, po->operand[0].name))
3115 // scan for any po_test operand modification in range given
3116 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
3119 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3122 for (; i < opcnt; i++) {
3123 if (is_any_opr_modified(po_test, &ops[i], c_mode))
3130 // scan for po_test operand[0] modification in range given
3131 static int scan_for_mod_opr0(struct parsed_op *po_test,
3134 for (; i < opcnt; i++) {
3135 if (is_opr_modified(&po_test->operand[0], &ops[i]))
3142 static int try_resolve_const(int i, const struct parsed_opr *opr,
3143 int magic, unsigned int *val);
3145 static int scan_for_flag_set(int i, int opcnt, int magic,
3146 int *branched, int *setters, int *setter_cnt)
3148 struct label_ref *lr;
3152 if (ops[i].cc_scratch == magic) {
3153 // is this a problem?
3154 //ferr(&ops[i], "%s looped\n", __func__);
3157 ops[i].cc_scratch = magic;
3159 if (g_labels[i] != NULL) {
3162 lr = &g_label_refs[i];
3163 for (; lr->next; lr = lr->next) {
3164 check_i(&ops[i], lr->i);
3165 ret = scan_for_flag_set(lr->i, opcnt, magic,
3166 branched, setters, setter_cnt);
3171 check_i(&ops[i], lr->i);
3172 if (i > 0 && LAST_OP(i - 1)) {
3176 ret = scan_for_flag_set(lr->i, opcnt, magic,
3177 branched, setters, setter_cnt);
3183 if (ops[i].flags & OPF_FLAGS) {
3184 setters[*setter_cnt] = i;
3187 if (ops[i].flags & OPF_REP) {
3188 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
3191 ret = try_resolve_const(i, &opr, i + opcnt * 7, &uval);
3192 if (ret != 1 || uval == 0) {
3193 // can't treat it as full setter because of ecx=0 case,
3194 // also disallow delayed compare
3203 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3210 // scan back for cdq, if anything modifies edx, fail
3211 static int scan_for_cdq_edx(int i)
3214 if (g_labels[i] != NULL) {
3215 if (g_label_refs[i].next != NULL)
3217 if (i > 0 && LAST_OP(i - 1)) {
3218 i = g_label_refs[i].i;
3225 if (ops[i].op == OP_CDQ)
3228 if (ops[i].regmask_dst & (1 << xDX))
3235 static int scan_for_reg_clear(int i, int reg)
3238 if (g_labels[i] != NULL) {
3239 if (g_label_refs[i].next != NULL)
3241 if (i > 0 && LAST_OP(i - 1)) {
3242 i = g_label_refs[i].i;
3249 if (ops[i].op == OP_XOR
3250 && ops[i].operand[0].lmod == OPLM_DWORD
3251 && ops[i].operand[0].reg == ops[i].operand[1].reg
3252 && ops[i].operand[0].reg == reg)
3255 if (ops[i].regmask_dst & (1 << reg))
3262 static void patch_esp_adjust(struct parsed_op *po, int adj)
3264 ferr_assert(po, po->op == OP_ADD);
3265 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3266 ferr_assert(po, po->operand[1].type == OPT_CONST);
3268 // this is a bit of a hack, but deals with use of
3269 // single adj for multiple calls
3270 po->operand[1].val -= adj;
3271 po->flags |= OPF_RMD;
3272 if (po->operand[1].val == 0)
3273 po->flags |= OPF_DONE;
3274 ferr_assert(po, (int)po->operand[1].val >= 0);
3277 // scan for positive, constant esp adjust
3278 // multipath case is preliminary
3279 static int scan_for_esp_adjust(int i, int opcnt,
3280 int adj_expect, int *adj, int *is_multipath, int do_update)
3282 int adj_expect_unknown = 0;
3283 struct parsed_op *po;
3287 *adj = *is_multipath = 0;
3288 if (adj_expect < 0) {
3289 adj_expect_unknown = 1;
3290 adj_expect = 32 * 4; // enough?
3293 for (; i < opcnt && *adj < adj_expect; i++) {
3294 if (g_labels[i] != NULL)
3298 if (po->flags & OPF_DONE)
3301 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3302 if (po->operand[1].type != OPT_CONST)
3303 ferr(&ops[i], "non-const esp adjust?\n");
3304 *adj += po->operand[1].val;
3306 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3309 patch_esp_adjust(po, adj_expect);
3311 po->flags |= OPF_RMD;
3315 else if (po->op == OP_PUSH) {
3316 //if (first_pop == -1)
3317 // first_pop = -2; // none
3318 *adj -= lmod_bytes(po, po->operand[0].lmod);
3320 else if (po->op == OP_POP) {
3321 if (!(po->flags & OPF_DONE)) {
3322 // seems like msvc only uses 'pop ecx' for stack realignment..
3323 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3325 if (first_pop == -1 && *adj >= 0)
3328 if (do_update && *adj >= 0) {
3329 po->flags |= OPF_RMD;
3331 po->flags |= OPF_DONE | OPF_NOREGS;
3334 *adj += lmod_bytes(po, po->operand[0].lmod);
3335 if (*adj > adj_best)
3338 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3339 if (po->op == OP_JMP && po->btj == NULL) {
3345 if (po->op != OP_CALL)
3347 if (po->operand[0].type != OPT_LABEL)
3349 if (po->pp != NULL && po->pp->is_stdcall)
3351 if (adj_expect_unknown && first_pop >= 0)
3353 // assume it's another cdecl call
3357 if (first_pop >= 0) {
3358 // probably only 'pop ecx' was used
3366 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3368 struct parsed_op *po;
3372 ferr(ops, "%s: followed bad branch?\n", __func__);
3374 for (; i < opcnt; i++) {
3376 if (po->cc_scratch == magic)
3378 po->cc_scratch = magic;
3381 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3382 if (po->btj != NULL) {
3384 for (j = 0; j < po->btj->count; j++)
3385 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3389 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3390 if (!(po->flags & OPF_CJMP))
3393 if (po->flags & OPF_TAIL)
3398 static const struct parsed_proto *try_recover_pp(
3399 struct parsed_op *po, const struct parsed_opr *opr,
3400 int is_call, int *search_instead)
3402 const struct parsed_proto *pp = NULL;
3406 // maybe an arg of g_func?
3407 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3409 char ofs_reg[16] = { 0, };
3410 int arg, arg_s, arg_i;
3417 parse_stack_access(po, opr->name, ofs_reg,
3418 &offset, &stack_ra, NULL, 0);
3419 if (ofs_reg[0] != 0)
3420 ferr(po, "offset reg on arg access?\n");
3421 if (offset <= stack_ra) {
3422 // search who set the stack var instead
3423 if (search_instead != NULL)
3424 *search_instead = 1;
3428 arg_i = (offset - stack_ra - 4) / 4;
3429 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3430 if (g_func_pp->arg[arg].reg != NULL)
3436 if (arg == g_func_pp->argc)
3437 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3439 pp = g_func_pp->arg[arg].pp;
3442 ferr(po, "icall arg: arg%d has no pp\n", arg + 1);
3443 check_func_pp(po, pp, "icall arg");
3446 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3448 p = strchr(opr->name + 1, '[');
3449 memcpy(buf, opr->name, p - opr->name);
3450 buf[p - opr->name] = 0;
3451 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3453 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3454 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3457 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3460 check_func_pp(po, pp, "reg-fptr ref");
3466 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3467 int magic, const struct parsed_proto **pp_found, int *pp_i,
3470 const struct parsed_proto *pp = NULL;
3471 struct parsed_op *po;
3472 struct label_ref *lr;
3474 ops[i].cc_scratch = magic;
3477 if (g_labels[i] != NULL) {
3478 lr = &g_label_refs[i];
3479 for (; lr != NULL; lr = lr->next) {
3480 check_i(&ops[i], lr->i);
3481 scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3483 if (i > 0 && LAST_OP(i - 1))
3491 if (ops[i].cc_scratch == magic)
3493 ops[i].cc_scratch = magic;
3495 if (!(ops[i].flags & OPF_DATA))
3497 if (!is_opr_modified(opr, &ops[i]))
3499 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3500 // most probably trashed by some processing
3505 opr = &ops[i].operand[1];
3506 if (opr->type != OPT_REG)
3510 po = (i >= 0) ? &ops[i] : ops;
3513 // reached the top - can only be an arg-reg
3514 if (opr->type != OPT_REG || g_func_pp == NULL)
3517 for (i = 0; i < g_func_pp->argc; i++) {
3518 if (g_func_pp->arg[i].reg == NULL)
3520 if (IS(opr->name, g_func_pp->arg[i].reg))
3523 if (i == g_func_pp->argc)
3525 pp = g_func_pp->arg[i].pp;
3527 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3528 i + 1, g_func_pp->arg[i].reg);
3529 check_func_pp(po, pp, "icall reg-arg");
3532 pp = try_recover_pp(po, opr, 1, NULL);
3534 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3535 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3536 || (*pp_found)->is_stdcall != pp->is_stdcall
3537 || (*pp_found)->is_fptr != pp->is_fptr
3538 || (*pp_found)->argc != pp->argc
3539 || (*pp_found)->argc_reg != pp->argc_reg
3540 || (*pp_found)->argc_stack != pp->argc_stack)
3542 ferr(po, "icall: parsed_proto mismatch\n");
3552 static void add_label_ref(struct label_ref *lr, int op_i)
3554 struct label_ref *lr_new;
3561 lr_new = calloc(1, sizeof(*lr_new));
3563 lr_new->next = lr->next;
3567 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3569 struct parsed_op *po = &ops[i];
3570 struct parsed_data *pd;
3571 char label[NAMELEN], *p;
3574 p = strchr(po->operand[0].name, '[');
3578 len = p - po->operand[0].name;
3579 strncpy(label, po->operand[0].name, len);
3582 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3583 if (IS(g_func_pd[j].label, label)) {
3589 //ferr(po, "label '%s' not parsed?\n", label);
3592 if (pd->type != OPT_OFFSET)
3593 ferr(po, "label '%s' with non-offset data?\n", label);
3595 // find all labels, link
3596 for (j = 0; j < pd->count; j++) {
3597 for (l = 0; l < opcnt; l++) {
3598 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3599 add_label_ref(&g_label_refs[l], i);
3609 static void clear_labels(int count)
3613 for (i = 0; i < count; i++) {
3614 if (g_labels[i] != NULL) {
3621 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3626 for (i = 0; i < pp->argc; i++) {
3627 if (pp->arg[i].reg != NULL) {
3628 reg = char_array_i(regs_r32,
3629 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3631 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3632 pp->arg[i].reg, pp->name);
3633 regmask |= 1 << reg;
3640 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3645 if (pp->has_retreg) {
3646 for (i = 0; i < pp->argc; i++) {
3647 if (pp->arg[i].type.is_retreg) {
3648 reg = char_array_i(regs_r32,
3649 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3650 ferr_assert(ops, reg >= 0);
3651 regmask |= 1 << reg;
3656 if (strstr(pp->ret_type.name, "int64"))
3657 return regmask | (1 << xAX) | (1 << xDX);
3658 if (IS(pp->ret_type.name, "float")
3659 || IS(pp->ret_type.name, "double"))
3661 return regmask | mxST0;
3663 if (strcasecmp(pp->ret_type.name, "void") == 0)
3666 return regmask | mxAX;
3669 static int are_ops_same(struct parsed_op *po1, struct parsed_op *po2)
3671 return po1->op == po2->op && po1->operand_cnt == po2->operand_cnt
3672 && memcmp(po1->operand, po2->operand,
3673 sizeof(po1->operand[0]) * po1->operand_cnt) == 0;
3676 static void resolve_branches_parse_calls(int opcnt)
3678 static const struct {
3682 unsigned int regmask_src;
3683 unsigned int regmask_dst;
3685 { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3686 { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3687 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3688 { "__CIpow", OPP_CIPOW, OPF_FPOP, mxST0|mxST1, mxST0 },
3690 const struct parsed_proto *pp_c;
3691 struct parsed_proto *pp;
3692 struct parsed_data *pd;
3693 struct parsed_op *po;
3694 const char *tmpname;
3699 for (i = 0; i < opcnt; i++)
3705 if (po->datap != NULL) {
3706 pp = calloc(1, sizeof(*pp));
3707 my_assert_not(pp, NULL);
3709 ret = parse_protostr(po->datap, pp);
3711 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3717 if (po->op == OP_CALL) {
3722 else if (po->operand[0].type == OPT_LABEL)
3724 tmpname = opr_name(po, 0);
3725 if (IS_START(tmpname, "loc_"))
3726 ferr(po, "call to loc_*\n");
3727 if (IS(tmpname, "__alloca_probe"))
3730 // convert some calls to pseudo-ops
3731 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3732 if (!IS(tmpname, pseudo_ops[l].name))
3735 po->op = pseudo_ops[l].op;
3736 po->operand_cnt = 0;
3737 po->regmask_src = pseudo_ops[l].regmask_src;
3738 po->regmask_dst = pseudo_ops[l].regmask_dst;
3739 po->flags = pseudo_ops[l].flags;
3740 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3743 if (l < ARRAY_SIZE(pseudo_ops))
3746 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3747 if (!g_header_mode && pp_c == NULL)
3748 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3751 pp = proto_clone(pp_c);
3752 my_assert_not(pp, NULL);
3758 check_func_pp(po, pp, "fptr var call");
3759 if (pp->is_noreturn) {
3760 po->flags |= OPF_TAIL;
3761 po->flags &= ~OPF_ATAIL; // most likely...
3768 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3771 if (po->operand[0].type == OPT_REGMEM) {
3772 pd = try_resolve_jumptab(i, opcnt);
3780 for (l = 0; l < opcnt; l++) {
3781 if (g_labels[l] != NULL
3782 && IS(po->operand[0].name, g_labels[l]))
3784 if (l == i + 1 && po->op == OP_JMP) {
3785 // yet another alignment type..
3786 po->flags |= OPF_RMD|OPF_DONE;
3789 add_label_ref(&g_label_refs[l], i);
3795 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3798 if (po->operand[0].type == OPT_LABEL)
3802 ferr(po, "unhandled branch\n");
3806 po->flags |= OPF_TAIL;
3807 prev_op = i > 0 ? ops[i - 1].op : OP_UD2;
3808 if (prev_op == OP_POP)
3809 po->flags |= OPF_ATAIL;
3810 if (g_stack_fsz + g_bp_frame == 0 && prev_op != OP_PUSH
3811 && (g_func_pp == NULL || g_func_pp->argc_stack > 0))
3813 po->flags |= OPF_ATAIL;
3819 static void scan_prologue_epilogue(int opcnt)
3821 int ecx_push = 0, esp_sub = 0, pusha = 0;
3822 int sandard_epilogue;
3826 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
3827 && ops[1].op == OP_MOV
3828 && IS(opr_name(&ops[1], 0), "ebp")
3829 && IS(opr_name(&ops[1], 1), "esp"))
3832 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3833 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3836 if (ops[i].op == OP_PUSHA) {
3837 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3842 if (ops[i].op == OP_SUB && IS(opr_name(&ops[i], 0), "esp")) {
3843 g_stack_fsz = opr_const(&ops[i], 1);
3844 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3848 // another way msvc builds stack frame..
3849 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3851 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3855 // and another way..
3856 if (i == 2 && ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3857 && ops[i].operand[1].type == OPT_CONST
3858 && ops[i + 1].op == OP_CALL
3859 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3861 g_stack_fsz += ops[i].operand[1].val;
3862 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3864 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3871 for (; i < opcnt; i++)
3872 if (ops[i].flags & OPF_TAIL)
3875 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3876 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3882 sandard_epilogue = 0;
3883 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
3885 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3886 // the standard epilogue is sometimes even used without a sf
3887 if (ops[j - 1].op == OP_MOV
3888 && IS(opr_name(&ops[j - 1], 0), "esp")
3889 && IS(opr_name(&ops[j - 1], 1), "ebp"))
3890 sandard_epilogue = 1;
3892 else if (ops[j].op == OP_LEAVE)
3894 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3895 sandard_epilogue = 1;
3897 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
3898 && ops[i].pp->is_noreturn)
3900 // on noreturn, msvc sometimes cleans stack, sometimes not
3905 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3906 ferr(&ops[j], "'pop ebp' expected\n");
3908 if (g_stack_fsz != 0 || sandard_epilogue) {
3909 if (ops[j].op == OP_LEAVE)
3911 else if (sandard_epilogue) // mov esp, ebp
3913 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3916 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3918 ferr(&ops[j], "esp restore expected\n");
3921 if (ecx_push && j >= 0 && ops[j].op == OP_POP
3922 && IS(opr_name(&ops[j], 0), "ecx"))
3924 ferr(&ops[j], "unexpected ecx pop\n");
3929 if (ops[j].op == OP_POPA)
3930 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3932 ferr(&ops[j], "popa expected\n");
3937 } while (i < opcnt);
3940 ferr(ops, "missing ebp epilogue\n");
3946 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3947 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3953 for (; i < opcnt; i++) {
3954 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
3956 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
3957 && ops[i].operand[1].type == OPT_CONST)
3959 g_stack_fsz = ops[i].operand[1].val;
3960 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3965 else if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3966 && ops[i].operand[1].type == OPT_CONST
3967 && ops[i + 1].op == OP_CALL
3968 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3970 g_stack_fsz += ops[i].operand[1].val;
3971 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3973 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3980 if (ecx_push && !esp_sub) {
3981 // could actually be args for a call..
3982 for (; i < opcnt; i++)
3983 if (ops[i].op != OP_PUSH)
3986 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
3987 const struct parsed_proto *pp;
3988 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
3989 j = pp ? pp->argc_stack : 0;
3990 while (i > 0 && j > 0) {
3992 if (ops[i].op == OP_PUSH) {
3993 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
3998 ferr(&ops[i], "unhandled prologue\n");
4001 i = g_stack_fsz = ecx_push = 0;
4002 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4003 if (!(ops[i].flags & OPF_RMD))
4013 if (ecx_push || esp_sub)
4018 for (; i < opcnt; i++)
4019 if (ops[i].flags & OPF_TAIL)
4023 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4024 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4031 for (l = 0; l < ecx_push; l++) {
4032 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
4034 else if (ops[j].op == OP_ADD
4035 && IS(opr_name(&ops[j], 0), "esp")
4036 && ops[j].operand[1].type == OPT_CONST)
4039 l += ops[j].operand[1].val / 4 - 1;
4044 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4047 if (l != ecx_push) {
4048 if (i < opcnt && ops[i].op == OP_CALL
4049 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4051 // noreturn tailcall with no epilogue
4056 ferr(&ops[j], "epilogue scan failed\n");
4063 if (ops[j].op != OP_ADD
4064 || !IS(opr_name(&ops[j], 0), "esp")
4065 || ops[j].operand[1].type != OPT_CONST)
4067 if (i < opcnt && ops[i].op == OP_CALL
4068 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4070 // noreturn tailcall with no epilogue
4075 ferr(&ops[j], "'add esp' expected\n");
4078 if (ops[j].operand[1].val < g_stack_fsz)
4079 ferr(&ops[j], "esp adj is too low (need %d)\n", g_stack_fsz);
4081 ops[j].operand[1].val -= g_stack_fsz; // for stack arg scanner
4082 if (ops[j].operand[1].val == 0)
4083 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4088 } while (i < opcnt);
4091 ferr(ops, "missing esp epilogue\n");
4095 // find an instruction that changed opr before i op
4096 // *op_i must be set to -1 by the caller
4097 // *is_caller is set to 1 if one source is determined to be g_func arg
4098 // returns 1 if found, *op_i is then set to origin
4099 // returns -1 if multiple origins are found
4100 static int resolve_origin(int i, const struct parsed_opr *opr,
4101 int magic, int *op_i, int *is_caller)
4103 struct label_ref *lr;
4107 if (g_labels[i] != NULL) {
4108 lr = &g_label_refs[i];
4109 for (; lr != NULL; lr = lr->next) {
4110 check_i(&ops[i], lr->i);
4111 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4113 if (i > 0 && LAST_OP(i - 1))
4119 if (is_caller != NULL)
4124 if (ops[i].cc_scratch == magic)
4126 ops[i].cc_scratch = magic;
4128 if (!(ops[i].flags & OPF_DATA))
4130 if (!is_opr_modified(opr, &ops[i]))
4134 if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4145 // find an instruction that previously referenced opr
4146 // if multiple results are found - fail
4147 // *op_i must be set to -1 by the caller
4148 // returns 1 if found, *op_i is then set to referencer insn
4149 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4150 int magic, int *op_i)
4152 struct label_ref *lr;
4156 if (g_labels[i] != NULL) {
4157 lr = &g_label_refs[i];
4158 for (; lr != NULL; lr = lr->next) {
4159 check_i(&ops[i], lr->i);
4160 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4162 if (i > 0 && LAST_OP(i - 1))
4170 if (ops[i].cc_scratch == magic)
4172 ops[i].cc_scratch = magic;
4174 if (!is_opr_referenced(opr, &ops[i]))
4185 // adjust datap of all reachable 'op' insns when moving back
4186 // returns 1 if at least 1 op was found
4187 // returns -1 if path without an op was found
4188 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4190 struct label_ref *lr;
4193 if (ops[i].cc_scratch == magic)
4195 ops[i].cc_scratch = magic;
4198 if (g_labels[i] != NULL) {
4199 lr = &g_label_refs[i];
4200 for (; lr != NULL; lr = lr->next) {
4201 check_i(&ops[i], lr->i);
4202 ret |= adjust_prev_op(lr->i, op, magic, datap);
4204 if (i > 0 && LAST_OP(i - 1))
4212 if (ops[i].cc_scratch == magic)
4214 ops[i].cc_scratch = magic;
4216 if (ops[i].op != op)
4219 ops[i].datap = datap;
4224 // find next instruction that reads opr
4225 // *op_i must be set to -1 by the caller
4226 // on return, *op_i is set to first referencer insn
4227 // returns 1 if exactly 1 referencer is found
4228 static int find_next_read(int i, int opcnt,
4229 const struct parsed_opr *opr, int magic, int *op_i)
4231 struct parsed_op *po;
4234 for (; i < opcnt; i++)
4236 if (ops[i].cc_scratch == magic)
4238 ops[i].cc_scratch = magic;
4241 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4242 if (po->btj != NULL) {
4244 for (j = 0; j < po->btj->count; j++) {
4245 check_i(po, po->btj->d[j].bt_i);
4246 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4252 if (po->flags & OPF_RMD)
4254 check_i(po, po->bt_i);
4255 if (po->flags & OPF_CJMP) {
4256 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4265 if (!is_opr_read(opr, po)) {
4267 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4268 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4270 full_opr = po->operand[0].lmod >= opr->lmod;
4272 if (is_opr_modified(opr, po) && full_opr) {
4276 if (po->flags & OPF_TAIL)
4291 // find next instruction that reads opr
4292 // *op_i must be set to -1 by the caller
4293 // on return, *op_i is set to first flag user insn
4294 // returns 1 if exactly 1 flag user is found
4295 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4297 struct parsed_op *po;
4300 for (; i < opcnt; i++)
4302 if (ops[i].cc_scratch == magic)
4304 ops[i].cc_scratch = magic;
4307 if (po->op == OP_CALL)
4309 if (po->flags & OPF_JMP) {
4310 if (po->btj != NULL) {
4312 for (j = 0; j < po->btj->count; j++) {
4313 check_i(po, po->btj->d[j].bt_i);
4314 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4320 if (po->flags & OPF_RMD)
4322 check_i(po, po->bt_i);
4323 if (po->flags & OPF_CJMP)
4330 if (!(po->flags & OPF_CC)) {
4331 if (po->flags & OPF_FLAGS)
4334 if (po->flags & OPF_TAIL)
4350 static int try_resolve_const(int i, const struct parsed_opr *opr,
4351 int magic, unsigned int *val)
4356 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4359 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4362 *val = ops[i].operand[1].val;
4369 static int resolve_used_bits(int i, int opcnt, int reg,
4370 int *mask, int *is_z_check)
4372 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4376 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4380 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4382 fnote(&ops[j], "(first read)\n");
4383 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4386 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4387 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4389 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4390 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4392 *mask = ops[j].operand[1].val;
4393 if (ops[j].operand[0].lmod == OPLM_BYTE
4394 && ops[j].operand[0].name[1] == 'h')
4398 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4401 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4403 *is_z_check = ops[k].pfo == PFO_Z;
4408 static const struct parsed_proto *resolve_deref(int i, int magic,
4409 struct parsed_opr *opr, int level)
4411 struct parsed_opr opr_s = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
4412 const struct parsed_proto *pp = NULL;
4413 int from_caller = 0;
4422 ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4423 if (ret != 2 || len != strlen(opr->name)) {
4424 ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4425 if (ret != 1 || len != strlen(opr->name))
4429 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4434 ret = resolve_origin(i, &opr_s, i + magic, &j, NULL);
4438 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4439 && strlen(ops[j].operand[1].name) == 3
4440 && ops[j].operand[0].lmod == OPLM_DWORD
4441 && ops[j].pp == NULL // no hint
4444 // allow one simple dereference (com/directx)
4445 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4446 ops[j].operand[1].name);
4450 ret = resolve_origin(j, &opr_s, j + magic, &k, NULL);
4455 if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
4458 if (ops[j].pp != NULL) {
4462 else if (ops[j].operand[1].type == OPT_REGMEM) {
4463 pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
4465 // maybe structure ptr in structure
4466 pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
4469 else if (ops[j].operand[1].type == OPT_LABEL)
4470 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4471 else if (ops[j].operand[1].type == OPT_REG) {
4474 ret = resolve_origin(j, &ops[j].operand[1], i + magic,
4476 if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
4477 for (k = 0; k < g_func_pp->argc; k++) {
4478 if (g_func_pp->arg[k].reg == NULL)
4480 if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
4481 pp = g_func_pp->arg[k].pp;
4490 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4492 ferr(&ops[j], "expected struct, got '%s %s'\n",
4493 pp->type.name, pp->name);
4497 return proto_lookup_struct(g_fhdr, pp->type.name, offset);
4500 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4501 int *pp_i, int *multi_src)
4503 const struct parsed_proto *pp = NULL;
4504 int search_advice = 0;
4509 switch (ops[i].operand[0].type) {
4511 // try to resolve struct member calls
4512 pp = resolve_deref(i, i + opcnt * 19, &ops[i].operand[0], 0);
4518 pp = try_recover_pp(&ops[i], &ops[i].operand[0],
4524 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4532 static struct parsed_proto *process_call_early(int i, int opcnt,
4535 struct parsed_op *po = &ops[i];
4536 struct parsed_proto *pp;
4542 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4546 // look for and make use of esp adjust
4548 if (!pp->is_stdcall && pp->argc_stack > 0)
4549 ret = scan_for_esp_adjust(i + 1, opcnt,
4550 pp->argc_stack * 4, &adj, &multipath, 0);
4552 if (pp->argc_stack > adj / 4)
4556 if (ops[ret].op == OP_POP) {
4557 for (j = 1; j < adj / 4; j++) {
4558 if (ops[ret + j].op != OP_POP
4559 || ops[ret + j].operand[0].reg != xCX)
4571 static struct parsed_proto *process_call(int i, int opcnt)
4573 struct parsed_op *po = &ops[i];
4574 const struct parsed_proto *pp_c;
4575 struct parsed_proto *pp;
4576 const char *tmpname;
4577 int call_i = -1, ref_i = -1;
4578 int adj = 0, multipath = 0;
4581 tmpname = opr_name(po, 0);
4586 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4588 if (!pp_c->is_func && !pp_c->is_fptr)
4589 ferr(po, "call to non-func: %s\n", pp_c->name);
4590 pp = proto_clone(pp_c);
4591 my_assert_not(pp, NULL);
4593 // not resolved just to single func
4596 switch (po->operand[0].type) {
4598 // we resolved this call and no longer need the register
4599 po->regmask_src &= ~(1 << po->operand[0].reg);
4601 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4602 && ops[call_i].operand[1].type == OPT_LABEL)
4604 // no other source users?
4605 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4607 if (ret == 1 && call_i == ref_i) {
4608 // and nothing uses it after us?
4610 find_next_read(i + 1, opcnt, &po->operand[0],
4611 i + opcnt * 11, &ref_i);
4613 // then also don't need the source mov
4614 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4626 pp = calloc(1, sizeof(*pp));
4627 my_assert_not(pp, NULL);
4630 ret = scan_for_esp_adjust(i + 1, opcnt,
4631 -1, &adj, &multipath, 0);
4632 if (ret < 0 || adj < 0) {
4633 if (!g_allow_regfunc)
4634 ferr(po, "non-__cdecl indirect call unhandled yet\n");
4635 pp->is_unresolved = 1;
4639 if (adj > ARRAY_SIZE(pp->arg))
4640 ferr(po, "esp adjust too large: %d\n", adj);
4641 pp->ret_type.name = strdup("int");
4642 pp->argc = pp->argc_stack = adj;
4643 for (arg = 0; arg < pp->argc; arg++)
4644 pp->arg[arg].type.name = strdup("int");
4649 // look for and make use of esp adjust
4652 if (!pp->is_stdcall && pp->argc_stack > 0) {
4653 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
4654 ret = scan_for_esp_adjust(i + 1, opcnt,
4655 adj_expect, &adj, &multipath, 0);
4658 if (pp->is_vararg) {
4659 if (adj / 4 < pp->argc_stack) {
4660 fnote(po, "(this call)\n");
4661 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
4662 adj, pp->argc_stack * 4);
4664 // modify pp to make it have varargs as normal args
4666 pp->argc += adj / 4 - pp->argc_stack;
4667 for (; arg < pp->argc; arg++) {
4668 pp->arg[arg].type.name = strdup("int");
4671 if (pp->argc > ARRAY_SIZE(pp->arg))
4672 ferr(po, "too many args for '%s'\n", tmpname);
4674 if (pp->argc_stack > adj / 4) {
4675 if (pp->is_noreturn)
4676 // assume no stack adjust was emited
4678 fnote(po, "(this call)\n");
4679 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
4680 tmpname, pp->argc_stack * 4, adj);
4683 scan_for_esp_adjust(i + 1, opcnt,
4684 pp->argc_stack * 4, &adj, &multipath, 1);
4686 else if (pp->is_vararg)
4687 ferr(po, "missing esp_adjust for vararg func '%s'\n",
4694 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
4697 struct parsed_op *po;
4703 for (base_arg = 0; base_arg < pp->argc; base_arg++)
4704 if (pp->arg[base_arg].reg == NULL)
4707 for (j = i; j > 0; )
4709 ferr_assert(&ops[j], g_labels[j] == NULL);
4713 ferr_assert(po, po->op != OP_PUSH);
4714 if (po->op == OP_FST)
4716 if (po->operand[0].type != OPT_REGMEM)
4718 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
4721 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3)) {
4722 //ferr(po, "offset %d, %d args\n", offset, pp->argc_stack);
4726 arg = base_arg + offset / 4;
4728 po->p_argnum = arg + 1;
4729 ferr_assert(po, pp->arg[arg].datap == NULL);
4730 pp->arg[arg].datap = po;
4731 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
4732 if (regmask_ffca != NULL)
4733 *regmask_ffca |= 1 << arg;
4735 else if (po->op == OP_SUB && po->operand[0].reg == xSP
4736 && po->operand[1].type == OPT_CONST)
4738 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4743 for (arg = base_arg; arg < pp->argc; arg++) {
4744 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
4745 po = pp->arg[arg].datap;
4747 ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
4748 if (po->operand[0].lmod == OPLM_QWORD)
4755 static int collect_call_args_early(int i, struct parsed_proto *pp,
4756 int *regmask, int *regmask_ffca)
4758 struct parsed_op *po;
4762 for (arg = 0; arg < pp->argc; arg++)
4763 if (pp->arg[arg].reg == NULL)
4766 // first see if it can be easily done
4767 for (j = i; j > 0 && arg < pp->argc; )
4769 if (g_labels[j] != NULL)
4774 if (po->op == OP_CALL)
4776 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
4778 else if (po->op == OP_POP)
4780 else if (po->flags & OPF_CJMP)
4782 else if (po->op == OP_PUSH) {
4783 if (po->flags & (OPF_FARG|OPF_FARGNR))
4785 if (!g_header_mode) {
4786 ret = scan_for_mod(po, j + 1, i, 1);
4791 if (pp->arg[arg].type.is_va_list)
4795 for (arg++; arg < pp->argc; arg++)
4796 if (pp->arg[arg].reg == NULL)
4799 else if (po->op == OP_SUB && po->operand[0].reg == xSP
4800 && po->operand[1].type == OPT_CONST)
4802 if (po->flags & (OPF_RMD|OPF_DONE))
4804 if (po->operand[1].val != pp->argc_stack * 4)
4805 ferr(po, "unexpected esp adjust: %d\n",
4806 po->operand[1].val * 4);
4807 ferr_assert(po, pp->argc - arg == pp->argc_stack);
4808 return collect_call_args_no_push(i, pp, regmask_ffca);
4816 for (arg = 0; arg < pp->argc; arg++)
4817 if (pp->arg[arg].reg == NULL)
4820 for (j = i; j > 0 && arg < pp->argc; )
4824 if (ops[j].op == OP_PUSH)
4826 ops[j].p_argnext = -1;
4827 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
4828 pp->arg[arg].datap = &ops[j];
4830 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
4831 *regmask |= 1 << ops[j].operand[0].reg;
4833 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4834 ops[j].flags &= ~OPF_RSAVE;
4837 for (arg++; arg < pp->argc; arg++)
4838 if (pp->arg[arg].reg == NULL)
4846 static int sync_argnum(struct parsed_op *po, int argnum)
4848 struct parsed_op *po_tmp;
4850 // see if other branches don't have higher argnum
4851 for (po_tmp = po; po_tmp != NULL; ) {
4852 if (argnum < po_tmp->p_argnum)
4853 argnum = po_tmp->p_argnum;
4854 // note: p_argnext is active on current collect_call_args only
4855 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
4858 // make all argnums consistent
4859 for (po_tmp = po; po_tmp != NULL; ) {
4860 if (po_tmp->p_argnum != 0)
4861 po_tmp->p_argnum = argnum;
4862 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
4868 static int collect_call_args_r(struct parsed_op *po, int i,
4869 struct parsed_proto *pp, int *regmask, int *arg_grp,
4870 int arg, int argnum, int magic, int need_op_saving, int may_reuse)
4872 struct parsed_proto *pp_tmp;
4873 struct parsed_op *po_tmp;
4874 struct label_ref *lr;
4875 int need_to_save_current;
4876 int arg_grp_current = 0;
4877 int save_args_seen = 0;
4884 ferr(po, "dead label encountered\n");
4888 for (; arg < pp->argc; arg++, argnum++)
4889 if (pp->arg[arg].reg == NULL)
4891 magic = (magic & 0xffffff) | (arg << 24);
4893 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
4895 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
4896 if (ops[j].cc_scratch != magic) {
4897 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
4901 // ok: have already been here
4904 ops[j].cc_scratch = magic;
4906 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
4907 lr = &g_label_refs[j];
4908 if (lr->next != NULL)
4910 for (; lr->next; lr = lr->next) {
4911 check_i(&ops[j], lr->i);
4912 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4914 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
4915 arg, argnum, magic, need_op_saving, may_reuse);
4920 check_i(&ops[j], lr->i);
4921 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4923 if (j > 0 && LAST_OP(j - 1)) {
4924 // follow last branch in reverse
4929 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
4930 arg, argnum, magic, need_op_saving, may_reuse);
4936 if (ops[j].op == OP_CALL)
4938 if (pp->is_unresolved)
4943 ferr(po, "arg collect %d/%d hit unparsed call '%s'\n",
4944 arg, pp->argc, ops[j].operand[0].name);
4945 if (may_reuse && pp_tmp->argc_stack > 0)
4946 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
4947 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
4949 // esp adjust of 0 means we collected it before
4950 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
4951 && (ops[j].operand[1].type != OPT_CONST
4952 || ops[j].operand[1].val != 0))
4954 if (pp->is_unresolved)
4957 fnote(po, "(this call)\n");
4958 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
4959 arg, pp->argc, ops[j].operand[1].val);
4961 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
4963 if (pp->is_unresolved)
4966 fnote(po, "(this call)\n");
4967 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
4969 else if (ops[j].flags & OPF_CJMP)
4971 if (pp->is_unresolved)
4976 else if (ops[j].op == OP_PUSH
4977 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
4979 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
4982 ops[j].p_argnext = -1;
4983 po_tmp = pp->arg[arg].datap;
4985 ops[j].p_argnext = po_tmp - ops;
4986 pp->arg[arg].datap = &ops[j];
4988 argnum = sync_argnum(&ops[j], argnum);
4990 need_to_save_current = 0;
4992 if (ops[j].operand[0].type == OPT_REG)
4993 reg = ops[j].operand[0].reg;
4995 if (!need_op_saving) {
4996 ret = scan_for_mod(&ops[j], j + 1, i, 1);
4997 need_to_save_current = (ret >= 0);
4999 if (need_op_saving || need_to_save_current) {
5000 // mark this arg as one that needs operand saving
5001 pp->arg[arg].is_saved = 1;
5003 if (save_args_seen & (1 << (argnum - 1))) {
5006 if (arg_grp_current >= MAX_ARG_GRP)
5007 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
5011 else if (ops[j].p_argnum == 0)
5012 ops[j].flags |= OPF_RMD;
5014 // some PUSHes are reused by different calls on other branches,
5015 // but that can't happen if we didn't branch, so they
5016 // can be removed from future searches (handles nested calls)
5018 ops[j].flags |= OPF_FARGNR;
5020 ops[j].flags |= OPF_FARG;
5021 ops[j].flags &= ~OPF_RSAVE;
5023 // check for __VALIST
5024 if (!pp->is_unresolved && g_func_pp != NULL
5025 && pp->arg[arg].type.is_va_list)
5028 ret = resolve_origin(j, &ops[j].operand[0],
5029 magic + 1, &k, NULL);
5030 if (ret == 1 && k >= 0)
5032 if (ops[k].op == OP_LEA) {
5033 if (!g_func_pp->is_vararg)
5034 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
5037 snprintf(buf, sizeof(buf), "arg_%X",
5038 g_func_pp->argc_stack * 4);
5039 if (strstr(ops[k].operand[1].name, buf)
5040 || strstr(ops[k].operand[1].name, "arglist"))
5042 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
5043 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
5044 pp->arg[arg].is_saved = 0;
5048 ferr(&ops[k], "va_list arg detection failed\n");
5050 // check for va_list from g_func_pp arg too
5051 else if (ops[k].op == OP_MOV
5052 && is_stack_access(&ops[k], &ops[k].operand[1]))
5054 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5055 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5057 ops[k].flags |= OPF_RMD | OPF_DONE;
5058 ops[j].flags |= OPF_RMD;
5059 ops[j].p_argpass = ret + 1;
5060 pp->arg[arg].is_saved = 0;
5067 if (pp->arg[arg].is_saved) {
5068 ops[j].flags &= ~OPF_RMD;
5069 ops[j].p_argnum = argnum;
5072 // tracking reg usage
5074 *regmask |= 1 << reg;
5078 if (!pp->is_unresolved) {
5080 for (; arg < pp->argc; arg++, argnum++)
5081 if (pp->arg[arg].reg == NULL)
5084 magic = (magic & 0xffffff) | (arg << 24);
5087 if (ops[j].p_arggrp > arg_grp_current) {
5089 arg_grp_current = ops[j].p_arggrp;
5091 if (ops[j].p_argnum > 0)
5092 save_args_seen |= 1 << (ops[j].p_argnum - 1);
5095 if (arg < pp->argc) {
5096 ferr(po, "arg collect failed for '%s': %d/%d\n",
5097 pp->name, arg, pp->argc);
5101 if (arg_grp_current > *arg_grp)
5102 *arg_grp = arg_grp_current;
5107 static int collect_call_args(struct parsed_op *po, int i,
5108 struct parsed_proto *pp, int *regmask, int magic)
5110 // arg group is for cases when pushes for
5111 // multiple funcs are going on
5112 struct parsed_op *po_tmp;
5117 ret = collect_call_args_r(po, i, pp, regmask, &arg_grp,
5123 // propagate arg_grp
5124 for (a = 0; a < pp->argc; a++) {
5125 if (pp->arg[a].reg != NULL)
5128 po_tmp = pp->arg[a].datap;
5129 while (po_tmp != NULL) {
5130 po_tmp->p_arggrp = arg_grp;
5131 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5136 if (pp->is_unresolved) {
5138 pp->argc_stack += ret;
5139 for (a = 0; a < pp->argc; a++)
5140 if (pp->arg[a].type.name == NULL)
5141 pp->arg[a].type.name = strdup("int");
5147 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5148 int regmask_now, int *regmask,
5149 int regmask_save_now, int *regmask_save,
5150 int *regmask_init, int regmask_arg)
5152 struct parsed_op *po;
5160 for (; i < opcnt; i++)
5163 if (cbits[i >> 3] & (1 << (i & 7)))
5165 cbits[i >> 3] |= (1 << (i & 7));
5167 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5168 if (po->flags & (OPF_RMD|OPF_DONE))
5170 if (po->btj != NULL) {
5171 for (j = 0; j < po->btj->count; j++) {
5172 check_i(po, po->btj->d[j].bt_i);
5173 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5174 regmask_now, regmask, regmask_save_now, regmask_save,
5175 regmask_init, regmask_arg);
5180 check_i(po, po->bt_i);
5181 if (po->flags & OPF_CJMP)
5182 reg_use_pass(po->bt_i, opcnt, cbits,
5183 regmask_now, regmask, regmask_save_now, regmask_save,
5184 regmask_init, regmask_arg);
5190 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5191 && !g_func_pp->is_userstack
5192 && po->operand[0].type == OPT_REG)
5194 reg = po->operand[0].reg;
5195 ferr_assert(po, reg >= 0);
5198 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5199 if (regmask_now & (1 << reg)) {
5200 already_saved = regmask_save_now & (1 << reg);
5201 flags_set = OPF_RSAVE | OPF_DONE;
5204 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, 0);
5206 scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5207 reg, 0, 0, flags_set);
5210 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5212 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5217 ferr_assert(po, !already_saved);
5218 po->flags |= flags_set;
5220 if (regmask_now & (1 << reg)) {
5221 regmask_save_now |= (1 << reg);
5222 *regmask_save |= regmask_save_now;
5227 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5228 reg = po->operand[0].reg;
5229 ferr_assert(po, reg >= 0);
5231 if (regmask_save_now & (1 << reg))
5232 regmask_save_now &= ~(1 << reg);
5234 regmask_now &= ~(1 << reg);
5237 else if (po->op == OP_CALL) {
5238 if ((po->regmask_dst & (1 << xAX))
5239 && !(po->regmask_dst & (1 << xDX)))
5241 if (po->flags & OPF_TAIL)
5242 // don't need eax, will do "return f();" or "f(); return;"
5243 po->regmask_dst &= ~(1 << xAX);
5245 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
5247 find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
5250 po->regmask_dst &= ~(1 << xAX);
5254 // not "full stack" mode and have something in stack
5255 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5256 ferr(po, "float stack is not empty on func call\n");
5259 if (po->flags & OPF_NOREGS)
5262 // if incomplete register is used, clear it on init to avoid
5263 // later use of uninitialized upper part in some situations
5264 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5265 && po->operand[0].lmod != OPLM_DWORD)
5267 reg = po->operand[0].reg;
5268 ferr_assert(po, reg >= 0);
5270 if (!(regmask_now & (1 << reg)))
5271 *regmask_init |= 1 << reg;
5274 regmask_op = po->regmask_src | po->regmask_dst;
5276 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5277 regmask_new &= ~(1 << xSP);
5278 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5279 regmask_new &= ~(1 << xBP);
5281 if (regmask_new != 0)
5282 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5284 if (regmask_op & (1 << xBP)) {
5285 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5286 if (po->regmask_dst & (1 << xBP))
5287 // compiler decided to drop bp frame and use ebp as scratch
5288 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5290 regmask_op &= ~(1 << xBP);
5294 if (po->flags & OPF_FPUSH) {
5295 if (regmask_now & mxST1)
5296 regmask_now |= mxSTa; // switch to "full stack" mode
5297 if (regmask_now & mxSTa)
5298 po->flags |= OPF_FSHIFT;
5299 if (!(regmask_now & mxST7_2)) {
5301 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5305 regmask_now |= regmask_op;
5306 *regmask |= regmask_now;
5309 if (po->flags & OPF_FPOP) {
5310 if ((regmask_now & mxSTa) == 0)
5311 ferr(po, "float pop on empty stack?\n");
5312 if (regmask_now & (mxST7_2 | mxST1))
5313 po->flags |= OPF_FSHIFT;
5314 if (!(regmask_now & mxST7_2)) {
5316 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5320 if (po->flags & OPF_TAIL) {
5321 if (!(regmask_now & mxST7_2)) {
5322 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5323 if (!(regmask_now & mxST0))
5324 ferr(po, "no st0 on float return, mask: %x\n",
5327 else if (regmask_now & mxST1_0)
5328 ferr(po, "float regs on tail: %x\n", regmask_now);
5331 // there is support for "conditional tailcall", sort of
5332 if (!(po->flags & OPF_CC))
5338 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5342 for (i = 0; i < pp->argc; i++)
5343 if (pp->arg[i].reg == NULL)
5347 memmove(&pp->arg[i + 1], &pp->arg[i],
5348 sizeof(pp->arg[0]) * pp->argc_stack);
5349 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5350 pp->arg[i].reg = strdup(reg);
5351 pp->arg[i].type.name = strdup("int");
5356 static void output_std_flags(FILE *fout, struct parsed_op *po,
5357 int *pfomask, const char *dst_opr_text)
5359 if (*pfomask & (1 << PFO_Z)) {
5360 fprintf(fout, "\n cond_z = (%s%s == 0);",
5361 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5362 *pfomask &= ~(1 << PFO_Z);
5364 if (*pfomask & (1 << PFO_S)) {
5365 fprintf(fout, "\n cond_s = (%s%s < 0);",
5366 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5367 *pfomask &= ~(1 << PFO_S);
5372 OPP_FORCE_NORETURN = (1 << 0),
5373 OPP_SIMPLE_ARGS = (1 << 1),
5374 OPP_ALIGN = (1 << 2),
5377 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
5380 const char *cconv = "";
5382 if (pp->is_fastcall)
5383 cconv = "__fastcall ";
5384 else if (pp->is_stdcall && pp->argc_reg == 0)
5385 cconv = "__stdcall ";
5387 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5389 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
5390 fprintf(fout, "noreturn ");
5393 static void output_pp(FILE *fout, const struct parsed_proto *pp,
5398 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5402 output_pp_attrs(fout, pp, flags);
5405 fprintf(fout, "%s", pp->name);
5410 for (i = 0; i < pp->argc; i++) {
5412 fprintf(fout, ", ");
5413 if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
5414 && !(flags & OPP_SIMPLE_ARGS))
5417 output_pp(fout, pp->arg[i].pp, 0);
5419 else if (pp->arg[i].type.is_retreg) {
5420 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
5423 fprintf(fout, "%s", pp->arg[i].type.name);
5425 fprintf(fout, " a%d", i + 1);
5428 if (pp->is_vararg) {
5430 fprintf(fout, ", ");
5431 fprintf(fout, "...");
5436 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
5442 snprintf(buf1, sizeof(buf1), "%d", grp);
5443 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
5448 static void gen_x_cleanup(int opcnt);
5450 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
5452 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
5453 struct parsed_opr *last_arith_dst = NULL;
5454 char buf1[256], buf2[256], buf3[256], cast[64];
5455 struct parsed_proto *pp, *pp_tmp;
5456 struct parsed_data *pd;
5457 int save_arg_vars[MAX_ARG_GRP] = { 0, };
5458 unsigned char cbits[MAX_OPS / 8];
5459 const char *float_type;
5460 const char *float_st0;
5461 const char *float_st1;
5462 int need_float_stack = 0;
5463 int need_float_sw = 0; // status word
5464 int need_tmp_var = 0;
5468 int label_pending = 0;
5469 int need_double = 0;
5470 int regmask_save = 0; // used regs saved/restored in this func
5471 int regmask_arg; // regs from this function args (fastcall, etc)
5472 int regmask_ret; // regs needed on ret
5473 int regmask_now; // temp
5474 int regmask_init = 0; // regs that need zero initialization
5475 int regmask_pp = 0; // regs used in complex push-pop graph
5476 int regmask_ffca = 0; // float function call args
5477 int regmask = 0; // used regs
5487 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
5488 g_stack_frame_used = 0;
5489 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
5490 regmask_init = g_regmask_init;
5492 g_func_pp = proto_parse(fhdr, funcn, 0);
5493 if (g_func_pp == NULL)
5494 ferr(ops, "proto_parse failed for '%s'\n", funcn);
5496 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
5497 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
5500 // - resolve all branches
5501 // - parse calls with labels
5502 resolve_branches_parse_calls(opcnt);
5505 // - handle ebp/esp frame, remove ops related to it
5506 scan_prologue_epilogue(opcnt);
5509 // - remove dead labels
5510 // - set regs needed at ret
5511 for (i = 0; i < opcnt; i++)
5513 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
5518 if (ops[i].op == OP_RET)
5519 ops[i].regmask_src |= regmask_ret;
5523 // - process trivial calls
5524 for (i = 0; i < opcnt; i++)
5527 if (po->flags & (OPF_RMD|OPF_DONE))
5530 if (po->op == OP_CALL)
5532 pp = process_call_early(i, opcnt, &j);
5534 if (!(po->flags & OPF_ATAIL)) {
5535 // since we know the args, try to collect them
5536 ret = collect_call_args_early(i, pp, ®mask, ®mask_ffca);
5544 // commit esp adjust
5545 if (ops[j].op != OP_POP)
5546 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5548 for (l = 0; l < pp->argc_stack; l++)
5549 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
5553 if (strstr(pp->ret_type.name, "int64"))
5556 po->flags |= OPF_DONE;
5562 // - process calls, stage 2
5563 // - handle some push/pop pairs
5564 // - scan for STD/CLD, propagate DF
5565 // - try to resolve needed x87 status word bits
5566 for (i = 0; i < opcnt; i++)
5571 if (po->flags & OPF_RMD)
5574 if (po->op == OP_CALL)
5576 if (!(po->flags & OPF_DONE)) {
5577 pp = process_call(i, opcnt);
5579 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
5580 // since we know the args, collect them
5581 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
5583 // for unresolved, collect after other passes
5587 ferr_assert(po, pp != NULL);
5589 po->regmask_src |= get_pp_arg_regmask_src(pp);
5590 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
5592 if (po->regmask_dst & mxST0)
5593 po->flags |= OPF_FPUSH;
5595 if (strstr(pp->ret_type.name, "int64"))
5601 if (po->flags & OPF_DONE)
5606 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
5607 && po->operand[0].type == OPT_CONST)
5609 scan_for_pop_const(i, opcnt, i + opcnt * 12);
5614 scan_pushes_for_pop(i, opcnt, ®mask_pp);
5618 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
5619 scan_propagate_df(i + 1, opcnt);
5624 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
5625 ferr(po, "TODO: fnstsw to mem\n");
5626 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
5628 ferr(po, "fnstsw resolve failed\n");
5629 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
5630 (void *)(long)(mask | (z_check << 16)));
5632 ferr(po, "failed to find fcom: %d\n", ret);
5641 // - find POPs for PUSHes, rm both
5642 // - scan for all used registers
5643 memset(cbits, 0, sizeof(cbits));
5644 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
5645 0, ®mask_save, ®mask_init, regmask_arg);
5647 need_float_stack = !!(regmask & mxST7_2);
5650 // - find flag set ops for their users
5651 // - do unresolved calls
5652 // - declare indirect functions
5653 // - other op specific processing
5654 for (i = 0; i < opcnt; i++)
5657 if (po->flags & (OPF_RMD|OPF_DONE))
5660 if (po->flags & OPF_CC)
5662 int setters[16], cnt = 0, branched = 0;
5664 ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
5665 &branched, setters, &cnt);
5666 if (ret < 0 || cnt <= 0)
5667 ferr(po, "unable to trace flag setter(s)\n");
5668 if (cnt > ARRAY_SIZE(setters))
5669 ferr(po, "too many flag setters\n");
5671 for (j = 0; j < cnt; j++)
5673 tmp_op = &ops[setters[j]]; // flag setter
5676 // to get nicer code, we try to delay test and cmp;
5677 // if we can't because of operand modification, or if we
5678 // have arith op, or branch, make it calculate flags explicitly
5679 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
5681 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
5682 pfomask = 1 << po->pfo;
5684 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
5685 pfomask = 1 << po->pfo;
5688 // see if we'll be able to handle based on op result
5689 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
5690 && po->pfo != PFO_Z && po->pfo != PFO_S
5691 && po->pfo != PFO_P)
5693 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
5695 pfomask = 1 << po->pfo;
5698 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
5699 propagate_lmod(tmp_op, &tmp_op->operand[0],
5700 &tmp_op->operand[1]);
5701 if (tmp_op->operand[0].lmod == OPLM_DWORD)
5706 tmp_op->pfomask |= pfomask;
5707 cond_vars |= pfomask;
5709 // note: may overwrite, currently not a problem
5713 if (po->op == OP_RCL || po->op == OP_RCR
5714 || po->op == OP_ADC || po->op == OP_SBB)
5715 cond_vars |= 1 << PFO_C;
5721 cond_vars |= 1 << PFO_Z;
5725 if (po->operand[0].lmod == OPLM_DWORD)
5730 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
5735 // note: resolved non-reg calls are OPF_DONE already
5737 ferr_assert(po, pp != NULL);
5739 if (pp->is_unresolved) {
5740 int regmask_stack = 0;
5741 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
5743 // this is pretty rough guess:
5744 // see ecx and edx were pushed (and not their saved versions)
5745 for (arg = 0; arg < pp->argc; arg++) {
5746 if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
5749 tmp_op = pp->arg[arg].datap;
5751 ferr(po, "parsed_op missing for arg%d\n", arg);
5752 if (tmp_op->operand[0].type == OPT_REG)
5753 regmask_stack |= 1 << tmp_op->operand[0].reg;
5756 if (!((regmask_stack & (1 << xCX))
5757 && (regmask_stack & (1 << xDX))))
5759 if (pp->argc_stack != 0
5760 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
5762 pp_insert_reg_arg(pp, "ecx");
5763 pp->is_fastcall = 1;
5764 regmask_init |= 1 << xCX;
5765 regmask |= 1 << xCX;
5767 if (pp->argc_stack != 0
5768 || ((regmask | regmask_arg) & (1 << xDX)))
5770 pp_insert_reg_arg(pp, "edx");
5771 regmask_init |= 1 << xDX;
5772 regmask |= 1 << xDX;
5776 // note: __cdecl doesn't fall into is_unresolved category
5777 if (pp->argc_stack > 0)
5783 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
5785 // <var> = offset <something>
5786 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
5787 && !IS_START(po->operand[1].name, "off_"))
5789 if (!po->operand[0].pp->is_fptr)
5790 ferr(po, "%s not declared as fptr when it should be\n",
5791 po->operand[0].name);
5792 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
5793 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
5794 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
5795 fnote(po, "var: %s\n", buf1);
5796 fnote(po, "func: %s\n", buf2);
5797 ferr(po, "^ mismatch\n");
5805 if (po->operand[0].lmod == OPLM_DWORD) {
5806 // 32bit division is common, look for it
5807 if (po->op == OP_DIV)
5808 ret = scan_for_reg_clear(i, xDX);
5810 ret = scan_for_cdq_edx(i);
5812 po->flags |= OPF_32BIT;
5821 po->flags |= OPF_RMD | OPF_DONE;
5831 if (po->operand[0].lmod == OPLM_QWORD)
5841 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
5843 find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
5845 po->flags |= OPF_32BIT;
5853 // this might need it's own pass...
5854 if (po->op != OP_FST && po->p_argnum > 0)
5855 save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
5857 // correct for "full stack" mode late enable
5858 if ((po->flags & (OPF_PPUSH|OPF_FPOP)) && need_float_stack)
5859 po->flags |= OPF_FSHIFT;
5862 float_type = need_double ? "double" : "float";
5863 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
5864 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
5866 // output starts here
5868 // define userstack size
5869 if (g_func_pp->is_userstack) {
5870 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
5871 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
5872 fprintf(fout, "#endif\n");
5875 // the function itself
5876 ferr_assert(ops, !g_func_pp->is_fptr);
5877 output_pp(fout, g_func_pp,
5878 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
5879 fprintf(fout, "\n{\n");
5881 // declare indirect functions
5882 for (i = 0; i < opcnt; i++) {
5884 if (po->flags & OPF_RMD)
5887 if (po->op == OP_CALL) {
5890 ferr(po, "NULL pp\n");
5892 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
5893 if (pp->name[0] != 0) {
5894 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
5895 memcpy(pp->name, "i_", 2);
5897 // might be declared already
5899 for (j = 0; j < i; j++) {
5900 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
5901 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
5911 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
5914 output_pp(fout, pp, OPP_SIMPLE_ARGS);
5915 fprintf(fout, ";\n");
5920 // output LUTs/jumptables
5921 for (i = 0; i < g_func_pd_cnt; i++) {
5923 fprintf(fout, " static const ");
5924 if (pd->type == OPT_OFFSET) {
5925 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
5927 for (j = 0; j < pd->count; j++) {
5929 fprintf(fout, ", ");
5930 fprintf(fout, "&&%s", pd->d[j].u.label);
5934 fprintf(fout, "%s %s[] =\n { ",
5935 lmod_type_u(ops, pd->lmod), pd->label);
5937 for (j = 0; j < pd->count; j++) {
5939 fprintf(fout, ", ");
5940 fprintf(fout, "%u", pd->d[j].u.val);
5943 fprintf(fout, " };\n");
5947 // declare stack frame, va_arg
5949 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
5950 if (g_func_lmods & (1 << OPLM_WORD))
5951 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
5952 if (g_func_lmods & (1 << OPLM_BYTE))
5953 fprintf(fout, " u8 b[%d];", g_stack_fsz);
5954 if (g_func_lmods & (1 << OPLM_QWORD))
5955 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
5956 fprintf(fout, " } sf;\n");
5960 if (g_func_pp->is_userstack) {
5961 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
5962 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
5966 if (g_func_pp->is_vararg) {
5967 fprintf(fout, " va_list ap;\n");
5971 // declare arg-registers
5972 for (i = 0; i < g_func_pp->argc; i++) {
5973 if (g_func_pp->arg[i].reg != NULL) {
5974 reg = char_array_i(regs_r32,
5975 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
5976 if (regmask & (1 << reg)) {
5977 if (g_func_pp->arg[i].type.is_retreg)
5978 fprintf(fout, " u32 %s = *r_%s;\n",
5979 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
5981 fprintf(fout, " u32 %s = (u32)a%d;\n",
5982 g_func_pp->arg[i].reg, i + 1);
5985 if (g_func_pp->arg[i].type.is_retreg)
5986 ferr(ops, "retreg '%s' is unused?\n",
5987 g_func_pp->arg[i].reg);
5988 fprintf(fout, " // %s = a%d; // unused\n",
5989 g_func_pp->arg[i].reg, i + 1);
5995 // declare normal registers
5996 regmask_now = regmask & ~regmask_arg;
5997 regmask_now &= ~(1 << xSP);
5998 if (regmask_now & 0x00ff) {
5999 for (reg = 0; reg < 8; reg++) {
6000 if (regmask_now & (1 << reg)) {
6001 fprintf(fout, " u32 %s", regs_r32[reg]);
6002 if (regmask_init & (1 << reg))
6003 fprintf(fout, " = 0");
6004 fprintf(fout, ";\n");
6010 if (regmask_now & 0xff00) {
6011 for (reg = 8; reg < 16; reg++) {
6012 if (regmask_now & (1 << reg)) {
6013 fprintf(fout, " mmxr %s", regs_r32[reg]);
6014 if (regmask_init & (1 << reg))
6015 fprintf(fout, " = { 0, }");
6016 fprintf(fout, ";\n");
6022 if (need_float_stack) {
6023 fprintf(fout, " %s f_st[8];\n", float_type);
6024 fprintf(fout, " int f_stp = 0;\n");
6028 if (regmask_now & 0xff0000) {
6029 for (reg = 16; reg < 24; reg++) {
6030 if (regmask_now & (1 << reg)) {
6031 fprintf(fout, " %s f_st%d", float_type, reg - 16);
6032 if (regmask_init & (1 << reg))
6033 fprintf(fout, " = 0");
6034 fprintf(fout, ";\n");
6041 if (need_float_sw) {
6042 fprintf(fout, " u16 f_sw;\n");
6047 for (reg = 0; reg < 8; reg++) {
6048 if (regmask_save & (1 << reg)) {
6049 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
6055 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6056 if (save_arg_vars[i] == 0)
6058 for (reg = 0; reg < 32; reg++) {
6059 if (save_arg_vars[i] & (1 << reg)) {
6060 fprintf(fout, " u32 %s;\n",
6061 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
6068 for (reg = 0; reg < 32; reg++) {
6069 if (regmask_ffca & (1 << reg)) {
6070 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
6076 // declare push-pop temporaries
6078 for (reg = 0; reg < 8; reg++) {
6079 if (regmask_pp & (1 << reg)) {
6080 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
6087 for (i = 0; i < 8; i++) {
6088 if (cond_vars & (1 << i)) {
6089 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
6096 fprintf(fout, " u32 tmp;\n");
6101 fprintf(fout, " u64 tmp64;\n");
6106 fprintf(fout, "\n");
6108 // do stack clear, if needed
6109 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6111 if (g_stack_clear_len != 0) {
6112 if (g_stack_clear_len <= 4) {
6113 for (i = 0; i < g_stack_clear_len; i++)
6114 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6115 fprintf(fout, "0;\n");
6118 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6119 g_stack_clear_start, g_stack_clear_len * 4);
6123 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6126 if (g_func_pp->is_vararg) {
6127 if (g_func_pp->argc_stack == 0)
6128 ferr(ops, "vararg func without stack args?\n");
6129 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
6133 for (i = 0; i < opcnt; i++)
6135 if (g_labels[i] != NULL) {
6136 fprintf(fout, "\n%s:\n", g_labels[i]);
6139 delayed_flag_op = NULL;
6140 last_arith_dst = NULL;
6144 if (po->flags & OPF_RMD)
6149 #define assert_operand_cnt(n_) \
6150 if (po->operand_cnt != n_) \
6151 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6153 // conditional/flag using op?
6154 if (po->flags & OPF_CC)
6160 // we go through all this trouble to avoid using parsed_flag_op,
6161 // which makes generated code much nicer
6162 if (delayed_flag_op != NULL)
6164 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6165 po->pfo, po->pfo_inv);
6168 else if (last_arith_dst != NULL
6169 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6170 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6173 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6174 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6175 last_arith_dst->lmod, buf3);
6178 else if (tmp_op != NULL) {
6179 // use preprocessed flag calc results
6180 if (!(tmp_op->pfomask & (1 << po->pfo)))
6181 ferr(po, "not prepared for pfo %d\n", po->pfo);
6183 // note: pfo_inv was not yet applied
6184 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6185 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6188 ferr(po, "all methods of finding comparison failed\n");
6191 if (po->flags & OPF_JMP) {
6192 fprintf(fout, " if %s", buf1);
6194 else if (po->op == OP_RCL || po->op == OP_RCR
6195 || po->op == OP_ADC || po->op == OP_SBB)
6198 fprintf(fout, " cond_%s = %s;\n",
6199 parsed_flag_op_names[po->pfo], buf1);
6201 else if (po->flags & OPF_DATA) { // SETcc
6202 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6203 fprintf(fout, " %s = %s;", buf2, buf1);
6206 ferr(po, "unhandled conditional op\n");
6210 pfomask = po->pfomask;
6215 assert_operand_cnt(2);
6216 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6217 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6218 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
6219 fprintf(fout, " %s = %s;", buf1,
6220 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6225 assert_operand_cnt(2);
6226 po->operand[1].lmod = OPLM_DWORD; // always
6227 fprintf(fout, " %s = %s;",
6228 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6229 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6234 assert_operand_cnt(2);
6235 fprintf(fout, " %s = %s;",
6236 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6237 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6241 assert_operand_cnt(2);
6242 switch (po->operand[1].lmod) {
6244 strcpy(buf3, "(s8)");
6247 strcpy(buf3, "(s16)");
6250 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6252 fprintf(fout, " %s = %s;",
6253 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6254 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6259 assert_operand_cnt(2);
6260 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6261 fprintf(fout, " tmp = %s;",
6262 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6263 fprintf(fout, " %s = %s;",
6264 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6265 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6266 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6267 fprintf(fout, " %s = %stmp;",
6268 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6269 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
6270 snprintf(g_comment, sizeof(g_comment), "xchg");
6274 assert_operand_cnt(1);
6275 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6276 fprintf(fout, " %s = ~%s;", buf1, buf1);
6280 assert_operand_cnt(2);
6281 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6282 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6283 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6284 strcpy(g_comment, "xlat");
6288 assert_operand_cnt(2);
6289 fprintf(fout, " %s = (s32)%s >> 31;",
6290 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6291 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6292 strcpy(g_comment, "cdq");
6296 assert_operand_cnt(1);
6297 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6298 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
6302 if (po->flags & OPF_REP) {
6303 assert_operand_cnt(3);
6308 assert_operand_cnt(2);
6309 fprintf(fout, " %s = %sesi; esi %c= %d;",
6310 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6311 lmod_cast_u_ptr(po, po->operand[1].lmod),
6312 (po->flags & OPF_DF) ? '-' : '+',
6313 lmod_bytes(po, po->operand[1].lmod));
6314 strcpy(g_comment, "lods");
6319 if (po->flags & OPF_REP) {
6320 assert_operand_cnt(3);
6321 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
6322 (po->flags & OPF_DF) ? '-' : '+',
6323 lmod_bytes(po, po->operand[1].lmod));
6324 fprintf(fout, " %sedi = eax;",
6325 lmod_cast_u_ptr(po, po->operand[1].lmod));
6326 strcpy(g_comment, "rep stos");
6329 assert_operand_cnt(2);
6330 fprintf(fout, " %sedi = eax; edi %c= %d;",
6331 lmod_cast_u_ptr(po, po->operand[1].lmod),
6332 (po->flags & OPF_DF) ? '-' : '+',
6333 lmod_bytes(po, po->operand[1].lmod));
6334 strcpy(g_comment, "stos");
6339 j = lmod_bytes(po, po->operand[0].lmod);
6340 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6341 l = (po->flags & OPF_DF) ? '-' : '+';
6342 if (po->flags & OPF_REP) {
6343 assert_operand_cnt(3);
6345 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
6348 " %sedi = %sesi;", buf1, buf1);
6349 strcpy(g_comment, "rep movs");
6352 assert_operand_cnt(2);
6353 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
6354 buf1, buf1, l, j, l, j);
6355 strcpy(g_comment, "movs");
6360 // repe ~ repeat while ZF=1
6361 j = lmod_bytes(po, po->operand[0].lmod);
6362 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6363 l = (po->flags & OPF_DF) ? '-' : '+';
6364 if (po->flags & OPF_REP) {
6365 assert_operand_cnt(3);
6367 " while (ecx != 0) {\n");
6368 if (pfomask & (1 << PFO_C)) {
6371 " cond_c = %sesi < %sedi;\n", buf1, buf1);
6372 pfomask &= ~(1 << PFO_C);
6375 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
6376 buf1, buf1, l, j, l, j);
6379 " if (cond_z %s 0) break;\n",
6380 (po->flags & OPF_REPZ) ? "==" : "!=");
6383 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
6384 (po->flags & OPF_REPZ) ? "e" : "ne");
6387 assert_operand_cnt(2);
6389 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
6390 buf1, buf1, l, j, l, j);
6391 strcpy(g_comment, "cmps");
6393 pfomask &= ~(1 << PFO_Z);
6394 last_arith_dst = NULL;
6395 delayed_flag_op = NULL;
6399 // only does ZF (for now)
6400 // repe ~ repeat while ZF=1
6401 j = lmod_bytes(po, po->operand[1].lmod);
6402 l = (po->flags & OPF_DF) ? '-' : '+';
6403 if (po->flags & OPF_REP) {
6404 assert_operand_cnt(3);
6406 " while (ecx != 0) {\n");
6408 " cond_z = (%seax == %sedi); edi %c= %d;\n",
6409 lmod_cast_u(po, po->operand[1].lmod),
6410 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6413 " if (cond_z %s 0) break;\n",
6414 (po->flags & OPF_REPZ) ? "==" : "!=");
6417 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
6418 (po->flags & OPF_REPZ) ? "e" : "ne");
6421 assert_operand_cnt(2);
6422 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
6423 lmod_cast_u(po, po->operand[1].lmod),
6424 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6425 strcpy(g_comment, "scas");
6427 pfomask &= ~(1 << PFO_Z);
6428 last_arith_dst = NULL;
6429 delayed_flag_op = NULL;
6432 // arithmetic w/flags
6434 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
6435 goto dualop_arith_const;
6436 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6440 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6441 if (po->operand[1].type == OPT_CONST) {
6442 j = lmod_bytes(po, po->operand[0].lmod);
6443 if (((1ull << j * 8) - 1) == po->operand[1].val)
6444 goto dualop_arith_const;
6449 assert_operand_cnt(2);
6450 fprintf(fout, " %s %s= %s;",
6451 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6453 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6454 output_std_flags(fout, po, &pfomask, buf1);
6455 last_arith_dst = &po->operand[0];
6456 delayed_flag_op = NULL;
6460 // and 0, or ~0 used instead mov
6461 assert_operand_cnt(2);
6462 fprintf(fout, " %s = %s;",
6463 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6464 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6465 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6466 output_std_flags(fout, po, &pfomask, buf1);
6467 last_arith_dst = &po->operand[0];
6468 delayed_flag_op = NULL;
6473 assert_operand_cnt(2);
6474 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6475 if (pfomask & (1 << PFO_C)) {
6476 if (po->operand[1].type == OPT_CONST) {
6477 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6478 j = po->operand[1].val;
6481 if (po->op == OP_SHL)
6485 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
6489 ferr(po, "zero shift?\n");
6493 pfomask &= ~(1 << PFO_C);
6495 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
6496 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6497 if (po->operand[1].type != OPT_CONST)
6498 fprintf(fout, " & 0x1f");
6500 output_std_flags(fout, po, &pfomask, buf1);
6501 last_arith_dst = &po->operand[0];
6502 delayed_flag_op = NULL;
6506 assert_operand_cnt(2);
6507 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6508 fprintf(fout, " %s = %s%s >> %s;", buf1,
6509 lmod_cast_s(po, po->operand[0].lmod), buf1,
6510 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6511 output_std_flags(fout, po, &pfomask, buf1);
6512 last_arith_dst = &po->operand[0];
6513 delayed_flag_op = NULL;
6518 assert_operand_cnt(3);
6519 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6520 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6521 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
6522 if (po->operand[2].type != OPT_CONST) {
6523 // no handling for "undefined" case, hopefully not needed
6524 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
6527 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6528 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6529 if (po->op == OP_SHLD) {
6530 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
6531 buf1, buf3, buf1, buf2, l, buf3);
6532 strcpy(g_comment, "shld");
6535 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
6536 buf1, buf3, buf1, buf2, l, buf3);
6537 strcpy(g_comment, "shrd");
6539 output_std_flags(fout, po, &pfomask, buf1);
6540 last_arith_dst = &po->operand[0];
6541 delayed_flag_op = NULL;
6546 assert_operand_cnt(2);
6547 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6548 if (po->operand[1].type == OPT_CONST) {
6549 j = po->operand[1].val;
6550 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
6551 fprintf(fout, po->op == OP_ROL ?
6552 " %s = (%s << %d) | (%s >> %d);" :
6553 " %s = (%s >> %d) | (%s << %d);",
6554 buf1, buf1, j, buf1,
6555 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
6559 output_std_flags(fout, po, &pfomask, buf1);
6560 last_arith_dst = &po->operand[0];
6561 delayed_flag_op = NULL;
6566 assert_operand_cnt(2);
6567 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6568 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6569 if (po->operand[1].type == OPT_CONST) {
6570 j = po->operand[1].val % l;
6572 ferr(po, "zero rotate\n");
6573 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
6574 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
6575 if (po->op == OP_RCL) {
6577 " %s = (%s << %d) | (cond_c << %d)",
6578 buf1, buf1, j, j - 1);
6580 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
6584 " %s = (%s >> %d) | (cond_c << %d)",
6585 buf1, buf1, j, l - j);
6587 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
6589 fprintf(fout, ";\n");
6590 fprintf(fout, " cond_c = tmp;");
6594 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
6595 output_std_flags(fout, po, &pfomask, buf1);
6596 last_arith_dst = &po->operand[0];
6597 delayed_flag_op = NULL;
6601 assert_operand_cnt(2);
6602 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6603 if (IS(opr_name(po, 0), opr_name(po, 1))) {
6604 // special case for XOR
6605 int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
6606 for (j = 0; j <= PFO_LE; j++) {
6607 if (pfomask & (1 << j)) {
6608 fprintf(fout, " cond_%s = %d;\n",
6609 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
6610 pfomask &= ~(1 << j);
6613 fprintf(fout, " %s = 0;",
6614 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6615 last_arith_dst = &po->operand[0];
6616 delayed_flag_op = NULL;
6622 assert_operand_cnt(2);
6623 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6624 if (pfomask & (1 << PFO_C)) {
6625 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6626 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6627 if (po->operand[0].lmod == OPLM_DWORD) {
6628 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
6629 fprintf(fout, " cond_c = tmp64 >> 32;\n");
6630 fprintf(fout, " %s = (u32)tmp64;",
6631 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6632 strcat(g_comment, " add64");
6635 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
6636 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
6637 fprintf(fout, " %s += %s;",
6638 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6641 pfomask &= ~(1 << PFO_C);
6642 output_std_flags(fout, po, &pfomask, buf1);
6643 last_arith_dst = &po->operand[0];
6644 delayed_flag_op = NULL;
6647 if (pfomask & (1 << PFO_LE)) {
6648 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
6649 fprintf(fout, " cond_%s = %s;\n",
6650 parsed_flag_op_names[PFO_LE], buf1);
6651 pfomask &= ~(1 << PFO_LE);
6656 assert_operand_cnt(2);
6657 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6658 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
6659 for (j = 0; j <= PFO_LE; j++) {
6660 if (!(pfomask & (1 << j)))
6662 if (j == PFO_Z || j == PFO_S)
6665 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6666 fprintf(fout, " cond_%s = %s;\n",
6667 parsed_flag_op_names[j], buf1);
6668 pfomask &= ~(1 << j);
6675 assert_operand_cnt(2);
6676 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6677 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6678 if (po->op == OP_SBB
6679 && IS(po->operand[0].name, po->operand[1].name))
6681 // avoid use of unitialized var
6682 fprintf(fout, " %s = -cond_c;", buf1);
6683 // carry remains what it was
6684 pfomask &= ~(1 << PFO_C);
6687 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
6688 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6690 output_std_flags(fout, po, &pfomask, buf1);
6691 last_arith_dst = &po->operand[0];
6692 delayed_flag_op = NULL;
6696 assert_operand_cnt(2);
6697 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6698 fprintf(fout, " %s = %s ? __builtin_ffs(%s) - 1 : 0;",
6699 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6701 output_std_flags(fout, po, &pfomask, buf1);
6702 last_arith_dst = &po->operand[0];
6703 delayed_flag_op = NULL;
6704 strcat(g_comment, " bsf");
6708 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
6709 for (j = 0; j <= PFO_LE; j++) {
6710 if (!(pfomask & (1 << j)))
6712 if (j == PFO_Z || j == PFO_S || j == PFO_C)
6715 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6716 fprintf(fout, " cond_%s = %s;\n",
6717 parsed_flag_op_names[j], buf1);
6718 pfomask &= ~(1 << j);
6724 if (pfomask & (1 << PFO_C))
6725 // carry is unaffected by inc/dec.. wtf?
6726 ferr(po, "carry propagation needed\n");
6728 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6729 if (po->operand[0].type == OPT_REG) {
6730 strcpy(buf2, po->op == OP_INC ? "++" : "--");
6731 fprintf(fout, " %s%s;", buf1, buf2);
6734 strcpy(buf2, po->op == OP_INC ? "+" : "-");
6735 fprintf(fout, " %s %s= 1;", buf1, buf2);
6737 output_std_flags(fout, po, &pfomask, buf1);
6738 last_arith_dst = &po->operand[0];
6739 delayed_flag_op = NULL;
6743 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6744 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
6745 fprintf(fout, " %s = -%s%s;", buf1,
6746 lmod_cast_s(po, po->operand[0].lmod), buf2);
6747 last_arith_dst = &po->operand[0];
6748 delayed_flag_op = NULL;
6749 if (pfomask & PFOB_C) {
6750 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
6753 output_std_flags(fout, po, &pfomask, buf1);
6757 if (po->operand_cnt == 2) {
6758 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6761 if (po->operand_cnt == 3)
6762 ferr(po, "TODO imul3\n");
6765 assert_operand_cnt(1);
6766 switch (po->operand[0].lmod) {
6768 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
6769 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
6770 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
6771 fprintf(fout, " edx = tmp64 >> 32;\n");
6772 fprintf(fout, " eax = tmp64;");
6775 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
6776 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
6777 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
6781 ferr(po, "TODO: unhandled mul type\n");
6784 last_arith_dst = NULL;
6785 delayed_flag_op = NULL;
6790 assert_operand_cnt(1);
6791 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6792 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
6793 po->op == OP_IDIV));
6794 switch (po->operand[0].lmod) {
6796 if (po->flags & OPF_32BIT)
6797 snprintf(buf2, sizeof(buf2), "%seax", cast);
6799 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
6800 snprintf(buf2, sizeof(buf2), "%stmp64",
6801 (po->op == OP_IDIV) ? "(s64)" : "");
6803 if (po->operand[0].type == OPT_REG
6804 && po->operand[0].reg == xDX)
6806 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
6807 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
6810 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
6811 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
6815 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
6816 snprintf(buf2, sizeof(buf2), "%stmp",
6817 (po->op == OP_IDIV) ? "(s32)" : "");
6818 if (po->operand[0].type == OPT_REG
6819 && po->operand[0].reg == xDX)
6821 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
6823 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
6827 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
6829 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
6832 strcat(g_comment, " div16");
6835 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
6837 last_arith_dst = NULL;
6838 delayed_flag_op = NULL;
6843 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6845 for (j = 0; j < 8; j++) {
6846 if (pfomask & (1 << j)) {
6847 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
6848 fprintf(fout, " cond_%s = %s;",
6849 parsed_flag_op_names[j], buf1);
6856 last_arith_dst = NULL;
6857 delayed_flag_op = po;
6861 // SETcc - should already be handled
6864 // note: we reuse OP_Jcc for SETcc, only flags differ
6866 fprintf(fout, "\n goto %s;", po->operand[0].name);
6870 fprintf(fout, " if (ecx == 0)\n");
6871 fprintf(fout, " goto %s;", po->operand[0].name);
6872 strcat(g_comment, " jecxz");
6876 fprintf(fout, " if (--ecx != 0)\n");
6877 fprintf(fout, " goto %s;", po->operand[0].name);
6878 strcat(g_comment, " loop");
6882 assert_operand_cnt(1);
6883 last_arith_dst = NULL;
6884 delayed_flag_op = NULL;
6886 if (po->operand[0].type == OPT_REGMEM) {
6887 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
6890 ferr(po, "parse failure for jmp '%s'\n",
6891 po->operand[0].name);
6892 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
6895 else if (po->operand[0].type != OPT_LABEL)
6896 ferr(po, "unhandled jmp type\n");
6898 fprintf(fout, " goto %s;", po->operand[0].name);
6902 assert_operand_cnt(1);
6904 my_assert_not(pp, NULL);
6907 if (po->flags & OPF_CC) {
6908 // we treat conditional branch to another func
6909 // (yes such code exists..) as conditional tailcall
6911 fprintf(fout, " {\n");
6914 if (pp->is_fptr && !pp->is_arg) {
6915 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
6916 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6918 if (pp->is_unresolved)
6919 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
6920 buf3, asmfn, po->asmln, pp->name);
6923 fprintf(fout, "%s", buf3);
6924 if (strstr(pp->ret_type.name, "int64")) {
6925 if (po->flags & OPF_TAIL)
6926 ferr(po, "int64 and tail?\n");
6927 fprintf(fout, "tmp64 = ");
6929 else if (!IS(pp->ret_type.name, "void")) {
6930 if (po->flags & OPF_TAIL) {
6931 if (regmask_ret & mxAX) {
6932 fprintf(fout, "return ");
6933 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
6934 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
6936 else if (regmask_ret & mxST0)
6937 ferr(po, "float tailcall\n");
6939 else if (po->regmask_dst & mxAX) {
6940 fprintf(fout, "eax = ");
6941 if (pp->ret_type.is_ptr)
6942 fprintf(fout, "(u32)");
6944 else if (po->regmask_dst & mxST0) {
6945 ferr_assert(po, po->flags & OPF_FPUSH);
6946 if (need_float_stack)
6947 fprintf(fout, "f_st[--f_stp & 7] = ");
6949 fprintf(fout, "f_st0 = ");
6953 if (pp->name[0] == 0)
6954 ferr(po, "missing pp->name\n");
6955 fprintf(fout, "%s%s(", pp->name,
6956 pp->has_structarg ? "_sa" : "");
6958 if (po->flags & OPF_ATAIL) {
6960 g_func_pp->is_stdcall && g_func_pp->argc_stack > 0;
6961 check_compat |= pp->argc_stack > 0;
6963 && (pp->argc_stack != g_func_pp->argc_stack
6964 || pp->is_stdcall != g_func_pp->is_stdcall))
6965 ferr(po, "incompatible arg-reuse tailcall\n");
6966 if (g_func_pp->has_retreg)
6967 ferr(po, "TODO: retreg+tailcall\n");
6969 for (arg = j = 0; arg < pp->argc; arg++) {
6971 fprintf(fout, ", ");
6974 if (pp->arg[arg].type.is_ptr)
6975 snprintf(cast, sizeof(cast), "(%s)",
6976 pp->arg[arg].type.name);
6978 if (pp->arg[arg].reg != NULL) {
6979 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6983 for (; j < g_func_pp->argc; j++)
6984 if (g_func_pp->arg[j].reg == NULL)
6986 fprintf(fout, "%sa%d", cast, j + 1);
6991 for (arg = 0; arg < pp->argc; arg++) {
6993 fprintf(fout, ", ");
6996 if (pp->arg[arg].type.is_ptr)
6997 snprintf(cast, sizeof(cast), "(%s)",
6998 pp->arg[arg].type.name);
7000 if (pp->arg[arg].reg != NULL) {
7001 if (pp->arg[arg].type.is_retreg)
7002 fprintf(fout, "&%s", pp->arg[arg].reg);
7003 else if (IS(pp->arg[arg].reg, "ebp")
7004 && g_bp_frame && !(po->flags & OPF_EBP_S))
7006 // rare special case
7007 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
7008 strcat(g_comment, " bp_ref");
7011 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7016 tmp_op = pp->arg[arg].datap;
7018 ferr(po, "parsed_op missing for arg%d\n", arg);
7020 if (tmp_op->flags & OPF_VAPUSH) {
7021 fprintf(fout, "ap");
7023 else if (tmp_op->op == OP_FST) {
7024 fprintf(fout, "fs_%d", tmp_op->p_argnum);
7025 if (tmp_op->operand[0].lmod == OPLM_QWORD)
7028 else if (tmp_op->p_argpass != 0) {
7029 fprintf(fout, "a%d", tmp_op->p_argpass);
7031 else if (pp->arg[arg].is_saved) {
7032 ferr_assert(po, tmp_op->p_argnum > 0);
7033 fprintf(fout, "%s%s", cast,
7034 saved_arg_name(buf1, sizeof(buf1),
7035 tmp_op->p_arggrp, tmp_op->p_argnum));
7039 out_src_opr(buf1, sizeof(buf1),
7040 tmp_op, &tmp_op->operand[0], cast, 0));
7044 fprintf(fout, ");");
7046 if (strstr(pp->ret_type.name, "int64")) {
7047 fprintf(fout, "\n");
7048 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7049 fprintf(fout, "%seax = tmp64;", buf3);
7052 if (pp->is_unresolved) {
7053 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
7055 strcat(g_comment, buf2);
7058 if (po->flags & OPF_TAIL) {
7060 if (i == opcnt - 1 || pp->is_noreturn)
7062 else if (IS(pp->ret_type.name, "void"))
7064 else if (!(regmask_ret & (1 << xAX)))
7066 // else already handled as 'return f()'
7069 fprintf(fout, "\n%sreturn;", buf3);
7070 strcat(g_comment, " ^ tailcall");
7073 strcat(g_comment, " tailcall");
7075 if ((regmask_ret & (1 << xAX))
7076 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7078 ferr(po, "int func -> void func tailcall?\n");
7081 if (pp->is_noreturn)
7082 strcat(g_comment, " noreturn");
7083 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7084 strcat(g_comment, " argframe");
7085 if (po->flags & OPF_CC)
7086 strcat(g_comment, " cond");
7088 if (po->flags & OPF_CC)
7089 fprintf(fout, "\n }");
7091 delayed_flag_op = NULL;
7092 last_arith_dst = NULL;
7096 if (g_func_pp->is_vararg)
7097 fprintf(fout, " va_end(ap);\n");
7098 if (g_func_pp->has_retreg) {
7099 for (arg = 0; arg < g_func_pp->argc; arg++)
7100 if (g_func_pp->arg[arg].type.is_retreg)
7101 fprintf(fout, " *r_%s = %s;\n",
7102 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7105 if (regmask_ret & mxST0) {
7106 fprintf(fout, " return %s;", float_st0);
7108 else if (!(regmask_ret & mxAX)) {
7109 if (i != opcnt - 1 || label_pending)
7110 fprintf(fout, " return;");
7112 else if (g_func_pp->ret_type.is_ptr) {
7113 fprintf(fout, " return (%s)eax;",
7114 g_func_pp->ret_type.name);
7116 else if (IS(g_func_pp->ret_type.name, "__int64"))
7117 fprintf(fout, " return ((u64)edx << 32) | eax;");
7119 fprintf(fout, " return eax;");
7121 last_arith_dst = NULL;
7122 delayed_flag_op = NULL;
7126 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7127 if (po->p_argnum != 0) {
7128 // special case - saved func arg
7129 fprintf(fout, " %s = %s;",
7130 saved_arg_name(buf2, sizeof(buf2),
7131 po->p_arggrp, po->p_argnum), buf1);
7134 else if (po->flags & OPF_RSAVE) {
7135 fprintf(fout, " s_%s = %s;", buf1, buf1);
7138 else if (po->flags & OPF_PPUSH) {
7140 ferr_assert(po, tmp_op != NULL);
7141 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7142 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7145 else if (g_func_pp->is_userstack) {
7146 fprintf(fout, " *(--esp) = %s;", buf1);
7149 if (!(g_ida_func_attr & IDAFA_NORETURN))
7150 ferr(po, "stray push encountered\n");
7155 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7156 if (po->flags & OPF_RSAVE) {
7157 fprintf(fout, " %s = s_%s;", buf1, buf1);
7160 else if (po->flags & OPF_PPUSH) {
7161 // push/pop graph / non-const
7162 ferr_assert(po, po->datap == NULL);
7163 fprintf(fout, " %s = pp_%s;", buf1, buf1);
7166 else if (po->datap != NULL) {
7169 fprintf(fout, " %s = %s;", buf1,
7170 out_src_opr(buf2, sizeof(buf2),
7171 tmp_op, &tmp_op->operand[0],
7172 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7175 else if (g_func_pp->is_userstack) {
7176 fprintf(fout, " %s = *esp++;", buf1);
7180 ferr(po, "stray pop encountered\n");
7190 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7191 fprintf(fout, " tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
7192 po->op == OPP_ALLSHL ? "<<" : ">>");
7193 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
7194 strcat(g_comment, po->op == OPP_ALLSHL
7195 ? " allshl" : " allshr");
7200 if (need_float_stack) {
7201 out_src_opr_float(buf1, sizeof(buf1),
7202 po, &po->operand[0], 1);
7203 if (po->regmask_src & mxSTa) {
7204 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7208 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
7211 if (po->flags & OPF_FSHIFT)
7212 fprintf(fout, " f_st1 = f_st0;");
7213 if (po->operand[0].type == OPT_REG
7214 && po->operand[0].reg == xST0)
7216 strcat(g_comment, " fld st");
7219 fprintf(fout, " f_st0 = %s;",
7220 out_src_opr_float(buf1, sizeof(buf1),
7221 po, &po->operand[0], 0));
7223 strcat(g_comment, " fld");
7227 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7228 lmod_cast(po, po->operand[0].lmod, 1), 0);
7229 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7230 if (need_float_stack) {
7231 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
7234 if (po->flags & OPF_FSHIFT)
7235 fprintf(fout, " f_st1 = f_st0;");
7236 fprintf(fout, " f_st0 = %s;", buf2);
7238 strcat(g_comment, " fild");
7242 if (need_float_stack)
7243 fprintf(fout, " f_st[--f_stp & 7] = ");
7245 if (po->flags & OPF_FSHIFT)
7246 fprintf(fout, " f_st1 = f_st0;");
7247 fprintf(fout, " f_st0 = ");
7249 switch (po->operand[0].val) {
7250 case X87_CONST_1: fprintf(fout, "1.0;"); break;
7251 case X87_CONST_LN2: fprintf(fout, "0.693147180559945;"); break;
7252 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
7253 default: ferr(po, "TODO\n"); break;
7258 if (po->flags & OPF_FARG) {
7259 // store to stack as func arg
7260 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7264 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7266 dead_dst = po->operand[0].type == OPT_REG
7267 && po->operand[0].reg == xST0;
7270 fprintf(fout, " %s = %s;", buf1, float_st0);
7271 if (po->flags & OPF_FSHIFT) {
7272 if (need_float_stack)
7273 fprintf(fout, " f_stp++;");
7275 fprintf(fout, " f_st0 = f_st1;");
7277 if (dead_dst && !(po->flags & OPF_FSHIFT))
7280 strcat(g_comment, " fst");
7284 fprintf(fout, " %s = %s%s;",
7285 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7286 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7287 if (po->flags & OPF_FSHIFT) {
7288 if (need_float_stack)
7289 fprintf(fout, " f_stp++;");
7291 fprintf(fout, " f_st0 = f_st1;");
7293 strcat(g_comment, " fist");
7300 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7302 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7304 dead_dst = (po->flags & OPF_FPOP)
7305 && po->operand[0].type == OPT_REG
7306 && po->operand[0].reg == xST0;
7308 case OP_FADD: j = '+'; break;
7309 case OP_FDIV: j = '/'; break;
7310 case OP_FMUL: j = '*'; break;
7311 case OP_FSUB: j = '-'; break;
7312 default: j = 'x'; break;
7314 if (need_float_stack) {
7316 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7317 if (po->flags & OPF_FSHIFT)
7318 fprintf(fout, " f_stp++;");
7321 if (po->flags & OPF_FSHIFT) {
7322 // note: assumes only 2 regs handled
7324 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
7326 fprintf(fout, " f_st0 = f_st1;");
7329 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7331 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7336 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7338 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7340 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
7342 dead_dst = (po->flags & OPF_FPOP)
7343 && po->operand[0].type == OPT_REG
7344 && po->operand[0].reg == xST0;
7345 j = po->op == OP_FDIVR ? '/' : '-';
7346 if (need_float_stack) {
7348 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7349 if (po->flags & OPF_FSHIFT)
7350 fprintf(fout, " f_stp++;");
7353 if (po->flags & OPF_FSHIFT) {
7355 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
7357 fprintf(fout, " f_st0 = f_st1;");
7360 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7362 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7370 case OP_FIADD: j = '+'; break;
7371 case OP_FIDIV: j = '/'; break;
7372 case OP_FIMUL: j = '*'; break;
7373 case OP_FISUB: j = '-'; break;
7374 default: j = 'x'; break;
7376 fprintf(fout, " %s %c= (%s)%s;", float_st0,
7378 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7379 lmod_cast(po, po->operand[0].lmod, 1), 0));
7384 fprintf(fout, " %s = %s %c %s;", float_st0,
7385 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7387 po->op == OP_FIDIVR ? '/' : '-', float_st0);
7392 ferr_assert(po, po->datap != NULL);
7393 mask = (long)po->datap & 0xffff;
7394 z_check = ((long)po->datap >> 16) & 1;
7395 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7397 if (mask == 0x0100) { // C0 -> <
7398 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
7401 else if (mask == 0x4000) { // C3 -> =
7402 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
7405 else if (mask == 0x4100) { // C3, C0
7407 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
7409 strcat(g_comment, " z_chk_det");
7412 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
7413 "(%s < %s ? 0x0100 : 0);",
7414 float_st0, buf1, float_st0, buf1);
7418 ferr(po, "unhandled sw mask: %x\n", mask);
7419 if (po->flags & OPF_FSHIFT) {
7420 if (need_float_stack)
7421 fprintf(fout, " f_stp++;");
7423 fprintf(fout, " f_st0 = f_st1;");
7429 fprintf(fout, " %s = f_sw;",
7430 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7434 fprintf(fout, " %s = -%s;", float_st0, float_st0);
7438 fprintf(fout, " %s = cos%s(%s);", float_st0,
7439 need_double ? "" : "f", float_st0);
7443 if (need_float_stack) {
7444 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
7445 need_double ? "" : "f", float_st1, float_st0);
7446 fprintf(fout, " f_stp++;");
7449 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
7450 need_double ? "" : "f");
7455 if (need_float_stack) {
7456 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
7457 float_st1, need_double ? "" : "f", float_st0);
7458 fprintf(fout, " f_stp++;");
7461 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
7462 need_double ? "" : "f");
7464 strcat(g_comment, " fyl2x");
7468 fprintf(fout, " %s = sin%s(%s);", float_st0,
7469 need_double ? "" : "f", float_st0);
7473 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
7474 need_double ? "" : "f", float_st0);
7478 dead_dst = po->operand[0].type == OPT_REG
7479 && po->operand[0].reg == xST0;
7481 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7483 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
7484 float_st0, float_st0, buf1, buf1);
7485 strcat(g_comment, " fxch");
7492 ferr_assert(po, po->flags & OPF_32BIT);
7493 fprintf(fout, " eax = (s32)%s;", float_st0);
7494 if (po->flags & OPF_FSHIFT) {
7495 if (need_float_stack)
7496 fprintf(fout, " f_stp++;");
7498 fprintf(fout, " f_st0 = f_st1;");
7500 strcat(g_comment, " ftol");
7504 if (need_float_stack) {
7505 fprintf(fout, " %s = pow%s(%s, %s);", float_st1,
7506 need_double ? "" : "f", float_st1, float_st0);
7507 fprintf(fout, " f_stp++;");
7510 fprintf(fout, " f_st0 = pow%s(f_st1, f_st0);",
7511 need_double ? "" : "f");
7513 strcat(g_comment, " CIpow");
7517 fprintf(fout, " do_skip_code_abort();");
7522 fprintf(fout, " do_emms();");
7527 ferr(po, "unhandled op type %d, flags %x\n",
7532 if (g_comment[0] != 0) {
7533 char *p = g_comment;
7534 while (my_isblank(*p))
7536 fprintf(fout, " // %s", p);
7541 fprintf(fout, "\n");
7543 // some sanity checking
7544 if (po->flags & OPF_REP) {
7545 if (po->op != OP_STOS && po->op != OP_MOVS
7546 && po->op != OP_CMPS && po->op != OP_SCAS)
7547 ferr(po, "unexpected rep\n");
7548 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
7549 && (po->op == OP_CMPS || po->op == OP_SCAS))
7550 ferr(po, "cmps/scas with plain rep\n");
7552 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
7553 && po->op != OP_CMPS && po->op != OP_SCAS)
7554 ferr(po, "unexpected repz/repnz\n");
7557 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
7559 // see is delayed flag stuff is still valid
7560 if (delayed_flag_op != NULL && delayed_flag_op != po) {
7561 if (is_any_opr_modified(delayed_flag_op, po, 0))
7562 delayed_flag_op = NULL;
7565 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
7566 if (is_opr_modified(last_arith_dst, po))
7567 last_arith_dst = NULL;
7573 if (g_stack_fsz && !g_stack_frame_used)
7574 fprintf(fout, " (void)sf;\n");
7576 fprintf(fout, "}\n\n");
7578 gen_x_cleanup(opcnt);
7581 static void gen_x_cleanup(int opcnt)
7585 for (i = 0; i < opcnt; i++) {
7586 struct label_ref *lr, *lr_del;
7588 lr = g_label_refs[i].next;
7589 while (lr != NULL) {
7594 g_label_refs[i].i = -1;
7595 g_label_refs[i].next = NULL;
7597 if (ops[i].op == OP_CALL) {
7599 proto_release(ops[i].pp);
7605 struct func_proto_dep;
7607 struct func_prototype {
7612 int has_ret:3; // -1, 0, 1: unresolved, no, yes
7613 unsigned int dep_resolved:1;
7614 unsigned int is_stdcall:1;
7615 struct func_proto_dep *dep_func;
7617 const struct parsed_proto *pp; // seed pp, if any
7620 struct func_proto_dep {
7622 struct func_prototype *proto;
7623 int regmask_live; // .. at the time of call
7624 unsigned int ret_dep:1; // return from this is caller's return
7627 static struct func_prototype *hg_fp;
7628 static int hg_fp_cnt;
7630 static struct scanned_var {
7632 enum opr_lenmod lmod;
7633 unsigned int is_seeded:1;
7634 unsigned int is_c_str:1;
7635 const struct parsed_proto *pp; // seed pp, if any
7637 static int hg_var_cnt;
7639 static char **hg_refs;
7640 static int hg_ref_cnt;
7642 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7645 static struct func_prototype *hg_fp_add(const char *funcn)
7647 struct func_prototype *fp;
7649 if ((hg_fp_cnt & 0xff) == 0) {
7650 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
7651 my_assert_not(hg_fp, NULL);
7652 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
7655 fp = &hg_fp[hg_fp_cnt];
7656 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
7658 fp->argc_stack = -1;
7664 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
7669 for (i = 0; i < fp->dep_func_cnt; i++)
7670 if (IS(fp->dep_func[i].name, name))
7671 return &fp->dep_func[i];
7676 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
7679 if (hg_fp_find_dep(fp, name))
7682 if ((fp->dep_func_cnt & 0xff) == 0) {
7683 fp->dep_func = realloc(fp->dep_func,
7684 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
7685 my_assert_not(fp->dep_func, NULL);
7686 memset(&fp->dep_func[fp->dep_func_cnt], 0,
7687 sizeof(fp->dep_func[0]) * 0x100);
7689 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
7693 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
7695 const struct func_prototype *p1 = p1_, *p2 = p2_;
7696 return strcmp(p1->name, p2->name);
7700 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
7702 const struct func_prototype *p1 = p1_, *p2 = p2_;
7703 return p1->id - p2->id;
7707 static void hg_ref_add(const char *name)
7709 if ((hg_ref_cnt & 0xff) == 0) {
7710 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
7711 my_assert_not(hg_refs, NULL);
7712 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
7715 hg_refs[hg_ref_cnt] = strdup(name);
7716 my_assert_not(hg_refs[hg_ref_cnt], NULL);
7720 // recursive register dep pass
7721 // - track saved regs (part 2)
7722 // - try to figure out arg-regs
7723 // - calculate reg deps
7724 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
7725 struct func_prototype *fp, int regmask_save, int regmask_dst,
7726 int *regmask_dep, int *has_ret)
7728 struct func_proto_dep *dep;
7729 struct parsed_op *po;
7730 int from_caller = 0;
7735 for (; i < opcnt; i++)
7737 if (cbits[i >> 3] & (1 << (i & 7)))
7739 cbits[i >> 3] |= (1 << (i & 7));
7743 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
7744 if (po->flags & OPF_RMD)
7747 if (po->btj != NULL) {
7749 for (j = 0; j < po->btj->count; j++) {
7750 check_i(po, po->btj->d[j].bt_i);
7751 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
7752 regmask_save, regmask_dst, regmask_dep, has_ret);
7757 check_i(po, po->bt_i);
7758 if (po->flags & OPF_CJMP) {
7759 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
7760 regmask_save, regmask_dst, regmask_dep, has_ret);
7768 if (po->flags & OPF_FARG)
7769 /* (just calculate register deps) */;
7770 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
7772 reg = po->operand[0].reg;
7773 ferr_assert(po, reg >= 0);
7775 if (po->flags & OPF_RSAVE) {
7776 regmask_save |= 1 << reg;
7779 if (po->flags & OPF_DONE)
7782 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0, 0);
7784 regmask_save |= 1 << reg;
7785 po->flags |= OPF_RMD;
7786 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, OPF_RMD);
7790 else if (po->flags & OPF_RMD)
7792 else if (po->op == OP_CALL) {
7793 po->regmask_dst |= 1 << xAX;
7795 dep = hg_fp_find_dep(fp, po->operand[0].name);
7797 dep->regmask_live = regmask_save | regmask_dst;
7798 if (g_bp_frame && !(po->flags & OPF_EBP_S))
7799 dep->regmask_live |= 1 << xBP;
7802 else if (po->op == OP_RET) {
7803 if (po->operand_cnt > 0) {
7805 if (fp->argc_stack >= 0
7806 && fp->argc_stack != po->operand[0].val / 4)
7807 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
7808 fp->argc_stack = po->operand[0].val / 4;
7812 // if has_ret is 0, there is uninitialized eax path,
7813 // which means it's most likely void func
7814 if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
7815 if (po->op == OP_CALL) {
7820 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
7823 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
7826 if (ret != 1 && from_caller) {
7827 // unresolved eax - probably void func
7831 if (j >= 0 && ops[j].op == OP_CALL) {
7832 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
7843 l = regmask_save | regmask_dst;
7844 if (g_bp_frame && !(po->flags & OPF_EBP_S))
7847 l = po->regmask_src & ~l;
7850 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
7851 l, regmask_dst, regmask_save, po->flags);
7854 regmask_dst |= po->regmask_dst;
7856 if (po->flags & OPF_TAIL)
7861 static void gen_hdr(const char *funcn, int opcnt)
7863 unsigned char cbits[MAX_OPS / 8];
7864 const struct parsed_proto *pp_c;
7865 struct parsed_proto *pp;
7866 struct func_prototype *fp;
7867 struct parsed_op *po;
7868 int regmask_dummy = 0;
7870 int max_bp_offset = 0;
7875 pp_c = proto_parse(g_fhdr, funcn, 1);
7877 // already in seed, will add to hg_fp later
7880 fp = hg_fp_add(funcn);
7882 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
7883 g_stack_frame_used = 0;
7886 // - resolve all branches
7887 // - parse calls with labels
7888 resolve_branches_parse_calls(opcnt);
7891 // - handle ebp/esp frame, remove ops related to it
7892 scan_prologue_epilogue(opcnt);
7895 // - remove dead labels
7897 for (i = 0; i < opcnt; i++)
7899 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7905 if (po->flags & (OPF_RMD|OPF_DONE))
7908 if (po->op == OP_CALL) {
7909 if (po->operand[0].type == OPT_LABEL)
7910 hg_fp_add_dep(fp, opr_name(po, 0));
7911 else if (po->pp != NULL)
7912 hg_fp_add_dep(fp, po->pp->name);
7917 // - remove dead labels
7918 // - handle push <const>/pop pairs
7919 for (i = 0; i < opcnt; i++)
7921 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7927 if (po->flags & (OPF_RMD|OPF_DONE))
7930 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
7931 scan_for_pop_const(i, opcnt, i + opcnt * 13);
7935 // - process trivial calls
7936 for (i = 0; i < opcnt; i++)
7939 if (po->flags & (OPF_RMD|OPF_DONE))
7942 if (po->op == OP_CALL)
7944 pp = process_call_early(i, opcnt, &j);
7946 if (!(po->flags & OPF_ATAIL))
7947 // since we know the args, try to collect them
7948 if (collect_call_args_early(i, pp, NULL, NULL) != 0)
7954 // commit esp adjust
7955 if (ops[j].op != OP_POP)
7956 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
7958 for (l = 0; l < pp->argc_stack; l++)
7959 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
7963 po->flags |= OPF_DONE;
7969 // - track saved regs (simple)
7971 for (i = 0; i < opcnt; i++)
7974 if (po->flags & (OPF_RMD|OPF_DONE))
7977 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
7978 && po->operand[0].reg != xCX)
7980 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
7982 // regmask_save |= 1 << po->operand[0].reg; // do it later
7983 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
7984 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
7987 else if (po->op == OP_CALL)
7989 pp = process_call(i, opcnt);
7991 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
7992 // since we know the args, collect them
7993 ret = collect_call_args(po, i, pp, ®mask_dummy,
8000 memset(cbits, 0, sizeof(cbits));
8004 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, ®mask_dep, &has_ret);
8006 // find unreachable code - must be fixed in IDA
8007 for (i = 0; i < opcnt; i++)
8009 if (cbits[i >> 3] & (1 << (i & 7)))
8012 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
8013 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
8015 // the compiler sometimes still generates code after
8016 // noreturn OS functions
8019 if (ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
8020 ferr(&ops[i], "unreachable code\n");
8023 for (i = 0; i < g_eqcnt; i++) {
8024 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
8025 max_bp_offset = g_eqs[i].offset;
8028 if (fp->argc_stack < 0) {
8029 max_bp_offset = (max_bp_offset + 3) & ~3;
8030 fp->argc_stack = max_bp_offset / 4;
8031 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
8035 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
8036 fp->has_ret = has_ret;
8038 printf("// has_ret %d, regmask_dep %x\n",
8039 fp->has_ret, fp->regmask_dep);
8040 output_hdr_fp(stdout, fp, 1);
8041 if (IS(funcn, "sub_10007F72")) exit(1);
8044 gen_x_cleanup(opcnt);
8047 static void hg_fp_resolve_deps(struct func_prototype *fp)
8049 struct func_prototype fp_s;
8053 // this thing is recursive, so mark first..
8054 fp->dep_resolved = 1;
8056 for (i = 0; i < fp->dep_func_cnt; i++) {
8057 strcpy(fp_s.name, fp->dep_func[i].name);
8058 fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8059 sizeof(hg_fp[0]), hg_fp_cmp_name);
8060 if (fp->dep_func[i].proto != NULL) {
8061 if (!fp->dep_func[i].proto->dep_resolved)
8062 hg_fp_resolve_deps(fp->dep_func[i].proto);
8064 dep = ~fp->dep_func[i].regmask_live
8065 & fp->dep_func[i].proto->regmask_dep;
8066 fp->regmask_dep |= dep;
8067 // printf("dep %s %s |= %x\n", fp->name,
8068 // fp->dep_func[i].name, dep);
8070 if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
8071 fp->has_ret = fp->dep_func[i].proto->has_ret;
8076 // make all thiscall/edx arg functions referenced from .data fastcall
8077 static void do_func_refs_from_data(void)
8079 struct func_prototype *fp, fp_s;
8082 for (i = 0; i < hg_ref_cnt; i++) {
8083 strcpy(fp_s.name, hg_refs[i]);
8084 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8085 sizeof(hg_fp[0]), hg_fp_cmp_name);
8089 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
8090 fp->regmask_dep |= mxCX | mxDX;
8094 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8097 const struct parsed_proto *pp;
8098 char *p, namebuf[NAMELEN];
8104 for (; count > 0; count--, fp++) {
8105 if (fp->has_ret == -1)
8106 fprintf(fout, "// ret unresolved\n");
8108 fprintf(fout, "// dep:");
8109 for (j = 0; j < fp->dep_func_cnt; j++) {
8110 fprintf(fout, " %s/", fp->dep_func[j].name);
8111 if (fp->dep_func[j].proto != NULL)
8112 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8113 fp->dep_func[j].proto->has_ret);
8115 fprintf(fout, "\n");
8118 p = strchr(fp->name, '@');
8120 memcpy(namebuf, fp->name, p - fp->name);
8121 namebuf[p - fp->name] = 0;
8129 pp = proto_parse(g_fhdr, name, 1);
8130 if (pp != NULL && pp->is_include)
8133 if (fp->pp != NULL) {
8134 // part of seed, output later
8138 regmask_dep = fp->regmask_dep;
8139 argc_normal = fp->argc_stack;
8141 fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
8142 (fp->has_ret ? "int" : "void"));
8143 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
8144 && (regmask_dep & ~mxCX) == 0)
8146 fprintf(fout, "/*__thiscall*/ ");
8150 else if (regmask_dep && (fp->is_stdcall || fp->argc_stack == 0)
8151 && (regmask_dep & ~(mxCX | mxDX)) == 0)
8153 fprintf(fout, " __fastcall ");
8154 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8160 else if (regmask_dep && !fp->is_stdcall) {
8161 fprintf(fout, "/*__usercall*/ ");
8163 else if (regmask_dep) {
8164 fprintf(fout, "/*__userpurge*/ ");
8166 else if (fp->is_stdcall)
8167 fprintf(fout, " __stdcall ");
8169 fprintf(fout, " __cdecl ");
8171 fprintf(fout, "%s(", name);
8174 for (j = 0; j < xSP; j++) {
8175 if (regmask_dep & (1 << j)) {
8178 fprintf(fout, ", ");
8180 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8182 fprintf(fout, "int");
8183 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
8187 for (j = 0; j < argc_normal; j++) {
8190 fprintf(fout, ", ");
8191 if (fp->pp != NULL) {
8192 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8193 if (!fp->pp->arg[arg - 1].type.is_ptr)
8197 fprintf(fout, "int ");
8198 fprintf(fout, "a%d", arg);
8201 fprintf(fout, ");\n");
8205 static void output_hdr(FILE *fout)
8207 static const char *lmod_c_names[] = {
8208 [OPLM_UNSPEC] = "???",
8209 [OPLM_BYTE] = "uint8_t",
8210 [OPLM_WORD] = "uint16_t",
8211 [OPLM_DWORD] = "uint32_t",
8212 [OPLM_QWORD] = "uint64_t",
8214 const struct scanned_var *var;
8215 struct func_prototype *fp;
8216 char line[256] = { 0, };
8220 // add stuff from headers
8221 for (i = 0; i < pp_cache_size; i++) {
8222 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
8223 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
8225 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
8226 fp = hg_fp_add(name);
8227 fp->pp = &pp_cache[i];
8228 fp->argc_stack = fp->pp->argc_stack;
8229 fp->is_stdcall = fp->pp->is_stdcall;
8230 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
8231 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
8235 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
8236 for (i = 0; i < hg_fp_cnt; i++)
8237 hg_fp_resolve_deps(&hg_fp[i]);
8239 // adjust functions referenced from data segment
8240 do_func_refs_from_data();
8242 // note: messes up .proto ptr, don't use
8243 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
8246 for (i = 0; i < hg_var_cnt; i++) {
8249 if (var->pp != NULL)
8252 else if (var->is_c_str)
8253 fprintf(fout, "extern %-8s %s[];", "char", var->name);
8255 fprintf(fout, "extern %-8s %s;",
8256 lmod_c_names[var->lmod], var->name);
8259 fprintf(fout, " // seeded");
8260 fprintf(fout, "\n");
8263 fprintf(fout, "\n");
8265 // output function prototypes
8266 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
8269 fprintf(fout, "\n// - seed -\n");
8272 while (fgets(line, sizeof(line), g_fhdr))
8273 fwrite(line, 1, strlen(line), fout);
8276 // '=' needs special treatment
8278 static char *next_word_s(char *w, size_t wsize, char *s)
8285 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
8287 for (i = 1; i < wsize - 1; i++) {
8289 printf("warning: missing closing quote: \"%s\"\n", s);
8298 for (; i < wsize - 1; i++) {
8299 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
8305 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
8306 printf("warning: '%s' truncated\n", w);
8311 static int cmpstringp(const void *p1, const void *p2)
8313 return strcmp(*(char * const *)p1, *(char * const *)p2);
8316 static int is_xref_needed(char *p, char **rlist, int rlist_len)
8321 if (strstr(p, "..."))
8322 // unable to determine, assume needed
8325 if (*p == '.') // .text, .data, ...
8326 // ref from other data or non-function -> no
8329 p2 = strpbrk(p, "+:\r\n\x18");
8332 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8333 // referenced from removed code
8339 static int ida_xrefs_show_need(FILE *fasm, char *p,
8340 char **rlist, int rlist_len)
8346 p = strrchr(p, ';');
8347 if (p != NULL && *p == ';') {
8348 if (IS_START(p + 2, "sctref"))
8350 if (IS_START(p + 2, "DATA XREF: ")) {
8352 if (is_xref_needed(p, rlist, rlist_len))
8360 if (!my_fgets(line, sizeof(line), fasm))
8362 // non-first line is always indented
8363 if (!my_isblank(line[0]))
8366 // should be no content, just comment
8371 p = strrchr(p, ';');
8374 if (IS_START(p, "sctref")) {
8379 // it's printed once, but no harm to check again
8380 if (IS_START(p, "DATA XREF: "))
8383 if (is_xref_needed(p, rlist, rlist_len)) {
8388 fseek(fasm, pos, SEEK_SET);
8392 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
8394 struct scanned_var *var;
8395 char line[256] = { 0, };
8404 // skip to next data section
8405 while (my_fgets(line, sizeof(line), fasm))
8410 if (*p == 0 || *p == ';')
8413 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
8414 if (*p == 0 || *p == ';')
8417 if (*p != 's' || !IS_START(p, "segment para public"))
8423 if (p == NULL || !IS_START(p, "segment para public"))
8427 if (!IS_START(p, "'DATA'"))
8431 while (my_fgets(line, sizeof(line), fasm))
8436 no_identifier = my_isblank(*p);
8439 if (*p == 0 || *p == ';')
8442 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8443 words[wordc][0] = 0;
8444 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8445 if (*p == 0 || *p == ';') {
8451 if (wordc == 2 && IS(words[1], "ends"))
8456 if (no_identifier) {
8457 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
8458 hg_ref_add(words[2]);
8462 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
8463 // when this starts, we don't need anything from this section
8467 // check refs comment(s)
8468 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
8471 if ((hg_var_cnt & 0xff) == 0) {
8472 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
8473 * (hg_var_cnt + 0x100));
8474 my_assert_not(hg_vars, NULL);
8475 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
8478 var = &hg_vars[hg_var_cnt++];
8479 snprintf(var->name, sizeof(var->name), "%s", words[0]);
8481 // maybe already in seed header?
8482 var->pp = proto_parse(g_fhdr, var->name, 1);
8483 if (var->pp != NULL) {
8484 if (var->pp->is_fptr) {
8485 var->lmod = OPLM_DWORD;
8488 else if (var->pp->is_func)
8490 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
8491 aerr("unhandled C type '%s' for '%s'\n",
8492 var->pp->type.name, var->name);
8498 if (IS(words[1], "dd")) {
8499 var->lmod = OPLM_DWORD;
8500 if (wordc >= 4 && IS(words[2], "offset"))
8501 hg_ref_add(words[3]);
8503 else if (IS(words[1], "dw"))
8504 var->lmod = OPLM_WORD;
8505 else if (IS(words[1], "db")) {
8506 var->lmod = OPLM_BYTE;
8507 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
8508 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
8512 else if (IS(words[1], "dq"))
8513 var->lmod = OPLM_QWORD;
8514 //else if (IS(words[1], "dt"))
8516 aerr("type '%s' not known\n", words[1]);
8524 static void set_label(int i, const char *name)
8530 p = strchr(name, ':');
8534 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
8535 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
8536 g_labels[i] = realloc(g_labels[i], len + 1);
8537 my_assert_not(g_labels[i], NULL);
8538 memcpy(g_labels[i], name, len);
8539 g_labels[i][len] = 0;
8548 static struct chunk_item *func_chunks;
8549 static int func_chunk_cnt;
8550 static int func_chunk_alloc;
8552 static void add_func_chunk(FILE *fasm, const char *name, int line)
8554 if (func_chunk_cnt >= func_chunk_alloc) {
8555 func_chunk_alloc *= 2;
8556 func_chunks = realloc(func_chunks,
8557 func_chunk_alloc * sizeof(func_chunks[0]));
8558 my_assert_not(func_chunks, NULL);
8560 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
8561 func_chunks[func_chunk_cnt].name = strdup(name);
8562 func_chunks[func_chunk_cnt].asmln = line;
8566 static int cmp_chunks(const void *p1, const void *p2)
8568 const struct chunk_item *c1 = p1, *c2 = p2;
8569 return strcmp(c1->name, c2->name);
8572 static void scan_ahead_for_chunks(FILE *fasm)
8582 oldpos = ftell(fasm);
8585 while (my_fgets(line, sizeof(line), fasm))
8596 // get rid of random tabs
8597 for (i = 0; line[i] != 0; i++)
8598 if (line[i] == '\t')
8601 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8604 next_word(words[0], sizeof(words[0]), p);
8605 if (words[0][0] == 0)
8606 aerr("missing name for func chunk?\n");
8608 add_func_chunk(fasm, words[0], asmln);
8610 else if (IS_START(p, "; sctend"))
8616 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8617 words[wordc][0] = 0;
8618 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8619 if (*p == 0 || *p == ';') {
8625 if (wordc == 2 && IS(words[1], "ends"))
8629 fseek(fasm, oldpos, SEEK_SET);
8633 int main(int argc, char *argv[])
8635 FILE *fout, *fasm, *frlist;
8636 struct parsed_data *pd = NULL;
8638 char **rlist = NULL;
8640 int rlist_alloc = 0;
8641 int func_chunks_used = 0;
8642 int func_chunks_sorted = 0;
8643 int func_chunk_i = -1;
8644 long func_chunk_ret = 0;
8645 int func_chunk_ret_ln = 0;
8646 int scanned_ahead = 0;
8648 char words[20][256];
8649 enum opr_lenmod lmod;
8650 char *sctproto = NULL;
8652 int pending_endp = 0;
8654 int skip_code_end = 0;
8655 int skip_warned = 0;
8668 for (arg = 1; arg < argc; arg++) {
8669 if (IS(argv[arg], "-v"))
8671 else if (IS(argv[arg], "-rf"))
8672 g_allow_regfunc = 1;
8673 else if (IS(argv[arg], "-uc"))
8674 g_allow_user_icall = 1;
8675 else if (IS(argv[arg], "-m"))
8677 else if (IS(argv[arg], "-hdr"))
8678 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
8683 if (argc < arg + 3) {
8684 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
8685 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
8687 " -hdr - header generation mode\n"
8688 " -rf - allow unannotated indirect calls\n"
8689 " -uc - allow ind. calls/refs to __usercall\n"
8690 " -m - allow multiple .text sections\n"
8691 "[rlist] is a file with function names to skip,"
8699 asmfn = argv[arg++];
8700 fasm = fopen(asmfn, "r");
8701 my_assert_not(fasm, NULL);
8703 hdrfn = argv[arg++];
8704 g_fhdr = fopen(hdrfn, "r");
8705 my_assert_not(g_fhdr, NULL);
8708 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
8709 my_assert_not(rlist, NULL);
8710 // needs special handling..
8711 rlist[rlist_len++] = "__alloca_probe";
8713 func_chunk_alloc = 32;
8714 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
8715 my_assert_not(func_chunks, NULL);
8717 memset(words, 0, sizeof(words));
8719 for (; arg < argc; arg++) {
8722 frlist = fopen(argv[arg], "r");
8723 my_assert_not(frlist, NULL);
8725 while (my_fgets(line, sizeof(line), frlist)) {
8727 if (*p == 0 || *p == ';')
8730 if (IS_START(p, "#if 0")
8731 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
8735 else if (IS_START(p, "#endif"))
8742 p = next_word(words[0], sizeof(words[0]), p);
8743 if (words[0][0] == 0)
8746 if (rlist_len >= rlist_alloc) {
8747 rlist_alloc = rlist_alloc * 2 + 64;
8748 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
8749 my_assert_not(rlist, NULL);
8751 rlist[rlist_len++] = strdup(words[0]);
8759 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
8761 fout = fopen(argv[arg_out], "w");
8762 my_assert_not(fout, NULL);
8765 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
8766 my_assert_not(g_eqs, NULL);
8768 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
8769 g_label_refs[i].i = -1;
8770 g_label_refs[i].next = NULL;
8774 scan_variables(fasm, rlist, rlist_len);
8776 while (my_fgets(line, sizeof(line), fasm))
8785 // get rid of random tabs
8786 for (i = 0; line[i] != 0; i++)
8787 if (line[i] == '\t')
8792 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
8793 goto do_pending_endp; // eww..
8795 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
8797 static const char *attrs[] = {
8806 // parse IDA's attribute-list comment
8807 g_ida_func_attr = 0;
8810 for (; *p != 0; p = sskip(p)) {
8811 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8812 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8813 g_ida_func_attr |= 1 << i;
8814 p += strlen(attrs[i]);
8818 if (i == ARRAY_SIZE(attrs)) {
8819 anote("unparsed IDA attr: %s\n", p);
8822 if (IS(attrs[i], "fpd=")) {
8823 p = next_word(words[0], sizeof(words[0]), p);
8828 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
8830 static const char *attrs[] = {
8835 // parse manual attribute-list comment
8836 g_sct_func_attr = 0;
8839 for (; *p != 0; p = sskip(p)) {
8840 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8841 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8842 g_sct_func_attr |= 1 << i;
8843 p += strlen(attrs[i]);
8850 // clear_sf=start,len (in dwords)
8851 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
8852 &g_stack_clear_len, &j);
8854 // clear_regmask=<mask>
8855 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
8857 anote("unparsed attr value: %s\n", p);
8862 else if (i == ARRAY_SIZE(attrs)) {
8863 anote("unparsed sct attr: %s\n", p);
8868 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8871 next_word(words[0], sizeof(words[0]), p);
8872 if (words[0][0] == 0)
8873 aerr("missing name for func chunk?\n");
8875 if (!scanned_ahead) {
8876 add_func_chunk(fasm, words[0], asmln);
8877 func_chunks_sorted = 0;
8880 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
8882 if (func_chunk_i >= 0) {
8883 if (func_chunk_i < func_chunk_cnt
8884 && IS(func_chunks[func_chunk_i].name, g_func))
8886 // move on to next chunk
8887 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
8889 aerr("seek failed for '%s' chunk #%d\n",
8890 g_func, func_chunk_i);
8891 asmln = func_chunks[func_chunk_i].asmln;
8895 if (func_chunk_ret == 0)
8896 aerr("no return from chunk?\n");
8897 fseek(fasm, func_chunk_ret, SEEK_SET);
8898 asmln = func_chunk_ret_ln;
8904 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
8905 func_chunks_used = 1;
8907 if (IS_START(g_func, "sub_")) {
8908 unsigned long addr = strtoul(p, NULL, 16);
8909 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
8910 if (addr > f_addr && !scanned_ahead) {
8911 //anote("scan_ahead caused by '%s', addr %lx\n",
8913 scan_ahead_for_chunks(fasm);
8915 func_chunks_sorted = 0;
8923 for (i = wordc; i < ARRAY_SIZE(words); i++)
8925 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8926 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8927 if (*p == 0 || *p == ';') {
8932 if (*p != 0 && *p != ';')
8933 aerr("too many words\n");
8935 if (skip_code_end) {
8940 // allow asm patches in comments
8942 if (IS_START(p, "; sctpatch:")) {
8944 if (*p == 0 || *p == ';')
8946 goto parse_words; // lame
8948 if (IS_START(p, "; sctproto:")) {
8949 sctproto = strdup(p + 11);
8951 else if (IS_START(p, "; sctend")) {
8956 else if (IS_START(p, "; sctskip_start")) {
8957 if (in_func && !g_skip_func) {
8959 ops[pi].op = OPP_ABORT;
8960 ops[pi].asmln = asmln;
8966 else if (IS_START(p, "; sctskip_end")) {
8974 awarn("wordc == 0?\n");
8978 // don't care about this:
8979 if (words[0][0] == '.'
8980 || IS(words[0], "include")
8981 || IS(words[0], "assume") || IS(words[1], "segment")
8982 || IS(words[0], "align"))
8988 // do delayed endp processing to collect switch jumptables
8990 if (in_func && !g_skip_func && !end && wordc >= 2
8991 && ((words[0][0] == 'd' && words[0][2] == 0)
8992 || (words[1][0] == 'd' && words[1][2] == 0)))
8995 if (words[1][0] == 'd' && words[1][2] == 0) {
8997 if (g_func_pd_cnt >= pd_alloc) {
8998 pd_alloc = pd_alloc * 2 + 16;
8999 g_func_pd = realloc(g_func_pd,
9000 sizeof(g_func_pd[0]) * pd_alloc);
9001 my_assert_not(g_func_pd, NULL);
9003 pd = &g_func_pd[g_func_pd_cnt];
9005 memset(pd, 0, sizeof(*pd));
9006 strcpy(pd->label, words[0]);
9007 pd->type = OPT_CONST;
9008 pd->lmod = lmod_from_directive(words[1]);
9014 anote("skipping alignment byte?\n");
9017 lmod = lmod_from_directive(words[0]);
9018 if (lmod != pd->lmod)
9019 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
9022 if (pd->count_alloc < pd->count + wordc) {
9023 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
9024 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
9025 my_assert_not(pd->d, NULL);
9027 for (; i < wordc; i++) {
9028 if (IS(words[i], "offset")) {
9029 pd->type = OPT_OFFSET;
9032 p = strchr(words[i], ',');
9035 if (pd->type == OPT_OFFSET)
9036 pd->d[pd->count].u.label = strdup(words[i]);
9038 pd->d[pd->count].u.val = parse_number(words[i], 0);
9039 pd->d[pd->count].bt_i = -1;
9045 if (in_func && !g_skip_func) {
9047 gen_hdr(g_func, pi);
9049 gen_func(fout, g_fhdr, g_func, pi);
9054 g_ida_func_attr = 0;
9055 g_sct_func_attr = 0;
9056 g_stack_clear_start = 0;
9057 g_stack_clear_len = 0;
9062 func_chunks_used = 0;
9065 memset(&ops, 0, pi * sizeof(ops[0]));
9070 for (i = 0; i < g_func_pd_cnt; i++) {
9072 if (pd->type == OPT_OFFSET) {
9073 for (j = 0; j < pd->count; j++)
9074 free(pd->d[j].u.label);
9089 if (IS(words[1], "proc")) {
9091 aerr("proc '%s' while in_func '%s'?\n",
9094 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9096 strcpy(g_func, words[0]);
9097 set_label(0, words[0]);
9102 if (IS(words[1], "endp"))
9105 aerr("endp '%s' while not in_func?\n", words[0]);
9106 if (!IS(g_func, words[0]))
9107 aerr("endp '%s' while in_func '%s'?\n",
9110 aerr("endp '%s' while skipping code\n", words[0]);
9112 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
9113 && ops[0].op == OP_JMP && ops[0].operand[0].had_ds)
9119 if (!g_skip_func && func_chunks_used) {
9120 // start processing chunks
9121 struct chunk_item *ci, key = { g_func, 0 };
9123 func_chunk_ret = ftell(fasm);
9124 func_chunk_ret_ln = asmln;
9125 if (!func_chunks_sorted) {
9126 qsort(func_chunks, func_chunk_cnt,
9127 sizeof(func_chunks[0]), cmp_chunks);
9128 func_chunks_sorted = 1;
9130 ci = bsearch(&key, func_chunks, func_chunk_cnt,
9131 sizeof(func_chunks[0]), cmp_chunks);
9133 aerr("'%s' needs chunks, but none found\n", g_func);
9134 func_chunk_i = ci - func_chunks;
9135 for (; func_chunk_i > 0; func_chunk_i--)
9136 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
9139 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9141 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
9142 asmln = func_chunks[func_chunk_i].asmln;
9150 if (wordc == 2 && IS(words[1], "ends")) {
9154 goto do_pending_endp;
9158 // scan for next text segment
9159 while (my_fgets(line, sizeof(line), fasm)) {
9162 if (*p == 0 || *p == ';')
9165 if (strstr(p, "segment para public 'CODE' use32"))
9172 p = strchr(words[0], ':');
9174 set_label(pi, words[0]);
9178 if (!in_func || g_skip_func || skip_code) {
9179 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
9181 anote("skipping from '%s'\n", g_labels[pi]);
9185 g_labels[pi] = NULL;
9189 if (wordc > 1 && IS(words[1], "="))
9192 aerr("unhandled equ, wc=%d\n", wordc);
9193 if (g_eqcnt >= eq_alloc) {
9195 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
9196 my_assert_not(g_eqs, NULL);
9199 len = strlen(words[0]);
9200 if (len > sizeof(g_eqs[0].name) - 1)
9201 aerr("equ name too long: %d\n", len);
9202 strcpy(g_eqs[g_eqcnt].name, words[0]);
9204 if (!IS(words[3], "ptr"))
9205 aerr("unhandled equ\n");
9206 if (IS(words[2], "dword"))
9207 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
9208 else if (IS(words[2], "word"))
9209 g_eqs[g_eqcnt].lmod = OPLM_WORD;
9210 else if (IS(words[2], "byte"))
9211 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
9212 else if (IS(words[2], "qword"))
9213 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
9215 aerr("bad lmod: '%s'\n", words[2]);
9217 g_eqs[g_eqcnt].offset = parse_number(words[4], 0);
9222 if (pi >= ARRAY_SIZE(ops))
9223 aerr("too many ops\n");
9225 parse_op(&ops[pi], words, wordc);
9227 ops[pi].datap = sctproto;
9242 // vim:ts=2:shiftwidth=2:expandtab