5 * This work is licensed under the terms of 3-clause BSD license.
6 * See COPYING file in the top-level directory.
8 * recognized asm hint comments:
9 * sctattr - function attributes (see code)
10 * sctend - force end of function/chunk
11 * sctpatch: <p> - replace current asm line with <p>
12 * sctproto: <p> - prototype of ref'd function or struct
13 * sctref - variable is referenced, make global
14 * sctskip_start - start of skipped code chunk (inclusive)
15 * sctskip_end - end of skipped code chunk (inclusive)
25 #include "my_assert.h"
29 #include "protoparse.h"
31 static const char *asmfn;
35 #define anote(fmt, ...) \
36 printf("%s:%d: note: " fmt, asmfn, asmln, ##__VA_ARGS__)
37 #define awarn(fmt, ...) \
38 printf("%s:%d: warning: " fmt, asmfn, asmln, ##__VA_ARGS__)
39 #define aerr(fmt, ...) do { \
40 printf("%s:%d: error: " fmt, asmfn, asmln, ##__VA_ARGS__); \
45 #include "masm_tools.h"
48 OPF_RMD = (1 << 0), /* removed from code generation */
49 OPF_DATA = (1 << 1), /* data processing - writes to dst opr */
50 OPF_FLAGS = (1 << 2), /* sets flags */
51 OPF_JMP = (1 << 3), /* branch, call */
52 OPF_CJMP = (1 << 4), /* cond. branch (cc or jecxz/loop) */
53 OPF_CC = (1 << 5), /* uses flags */
54 OPF_TAIL = (1 << 6), /* ret or tail call */
55 OPF_RSAVE = (1 << 7), /* push/pop is local reg save/load */
56 OPF_REP = (1 << 8), /* prefixed by rep */
57 OPF_REPZ = (1 << 9), /* rep is repe/repz */
58 OPF_REPNZ = (1 << 10), /* rep is repne/repnz */
59 OPF_FARG = (1 << 11), /* push collected as func arg */
60 OPF_FARGNR = (1 << 12), /* push collected as func arg (no reuse) */
61 OPF_EBP_S = (1 << 13), /* ebp used as scratch here, not BP */
62 OPF_DF = (1 << 14), /* DF flag set */
63 OPF_ATAIL = (1 << 15), /* tail call with reused arg frame */
64 OPF_32BIT = (1 << 16), /* enough to do 32bit for this op */
65 OPF_LOCK = (1 << 17), /* op has lock prefix */
66 OPF_VAPUSH = (1 << 18), /* vararg ptr push (as call arg) */
67 OPF_DONE = (1 << 19), /* already fully handled by analysis */
68 OPF_PPUSH = (1 << 20), /* part of complex push-pop graph */
69 OPF_NOREGS = (1 << 21), /* don't track regs of this op */
70 OPF_FPUSH = (1 << 22), /* pushes x87 stack */
71 OPF_FPOP = (1 << 23), /* pops x87 stack */
72 OPF_FPOPP = (1 << 24), /* pops x87 stack twice */
73 OPF_FSHIFT = (1 << 25), /* x87 stack shift is actually needed */
74 OPF_FINT = (1 << 26), /* integer float op arg */
165 // pseudo-ops for lib calls
184 // must be sorted (larger len must be further in enum)
193 #define MAX_EXITS 128
195 #define MAX_OPERANDS 3
198 #define OPR_INIT(type_, lmod_, reg_) \
199 { type_, lmod_, reg_, }
203 enum opr_lenmod lmod;
205 unsigned int is_ptr:1; // pointer in C
206 unsigned int is_array:1; // array in C
207 unsigned int type_from_var:1; // .. in header, sometimes wrong
208 unsigned int size_mismatch:1; // type override differs from C
209 unsigned int size_lt:1; // type override is larger than C
210 unsigned int segment:7; // had segment override (enum segment)
211 const struct parsed_proto *pp; // for OPT_LABEL
218 struct parsed_opr operand[MAX_OPERANDS];
221 unsigned char pfo_inv;
222 unsigned char operand_cnt;
223 unsigned char p_argnum; // arg push: altered before call arg #
224 unsigned char p_arggrp; // arg push: arg group # for above
225 unsigned char p_argpass;// arg push: arg of host func
226 short p_argnext;// arg push: same arg pushed elsewhere or -1
227 int regmask_src; // all referensed regs
229 int pfomask; // flagop: parsed_flag_op that can't be delayed
230 int cc_scratch; // scratch storage during analysis
231 int bt_i; // branch target for branches
232 struct parsed_data *btj;// branch targets for jumptables
233 struct parsed_proto *pp;// parsed_proto for OP_CALL
239 // on start: function/data type hint (sctproto)
241 // (OPF_CC) - points to one of (OPF_FLAGS) that affects cc op
242 // OP_PUSH - points to OP_POP in complex push/pop graph
243 // OP_POP - points to OP_PUSH in simple push/pop pair
244 // OP_FCOM - needed_status_word_bits | (is_z_check << 16)
248 enum opr_lenmod lmod;
255 enum opr_lenmod lmod;
269 struct label_ref *next;
273 IDAFA_BP_FRAME = (1 << 0),
274 IDAFA_LIB_FUNC = (1 << 1),
275 IDAFA_STATIC = (1 << 2),
276 IDAFA_NORETURN = (1 << 3),
277 IDAFA_THUNK = (1 << 4),
278 IDAFA_FPD = (1 << 5),
283 SCTFA_CLEAR_SF = (1 << 0), // clear stack frame
284 SCTFA_CLEAR_REGS = (1 << 1), // clear registers (mask)
285 SCTFA_RM_REGS = (1 << 2), // don't emit regs
286 SCTFA_NOWARN = (1 << 3), // don't try to detect problems
308 // note: limited to 32k due to p_argnext
310 #define MAX_ARG_GRP 2
312 static struct parsed_op ops[MAX_OPS];
313 static struct parsed_equ *g_eqs;
315 static char *g_labels[MAX_OPS];
316 static struct label_ref g_label_refs[MAX_OPS];
317 static const struct parsed_proto *g_func_pp;
318 static struct parsed_data *g_func_pd;
319 static int g_func_pd_cnt;
320 static int g_func_lmods;
321 static char g_func[256];
322 static char g_comment[256];
323 static int g_bp_frame;
324 static int g_sp_frame;
325 static int g_stack_frame_used;
326 static int g_stack_fsz;
327 static int g_seh_found;
328 static int g_seh_size;
329 static int g_ida_func_attr;
330 static int g_sct_func_attr;
331 static int g_stack_clear_start; // in dwords
332 static int g_stack_clear_len;
333 static int g_regmask_init;
334 static int g_regmask_rm;
335 static int g_skip_func;
336 static int g_allow_regfunc;
337 static int g_allow_user_icall;
338 static int g_quiet_pp;
339 static int g_header_mode;
341 #define ferr(op_, fmt, ...) do { \
342 printf("%s:%d: error %u: [%s] '%s': " fmt, asmfn, (op_)->asmln, \
343 __LINE__, g_func, dump_op(op_), ##__VA_ARGS__); \
347 #define fnote(op_, fmt, ...) \
348 printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
349 dump_op(op_), ##__VA_ARGS__)
351 #define ferr_assert(op_, cond) do { \
352 if (!(cond)) ferr(op_, "assertion '%s' failed\n", #cond); \
355 #define IS_OP_INDIRECT_CALL(op_) \
356 ((op_)->op == OP_CALL && (op_)->operand[0].type != OPT_LABEL)
358 const char *regs_r32[] = {
359 "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
360 // not r32, but list here for easy parsing and printing
361 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
362 "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"
364 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
365 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
366 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
372 xMM0, xMM1, xMM2, xMM3, // mmx
373 xMM4, xMM5, xMM6, xMM7,
374 xST0, xST1, xST2, xST3, // x87
375 xST4, xST5, xST6, xST7,
378 #define mxAX (1 << xAX)
379 #define mxCX (1 << xCX)
380 #define mxDX (1 << xDX)
381 #define mxSP (1 << xSP)
382 #define mxST0 (1 << xST0)
383 #define mxST1 (1 << xST1)
384 #define mxST1_0 (mxST1 | mxST0)
385 #define mxST7_2 (0xfc << xST0)
386 #define mxSTa (0xff << xST0)
388 // possible basic comparison types (without inversion)
389 enum parsed_flag_op {
393 PFO_BE, // 6 CF=1||ZF=1
397 PFO_LE, // e ZF=1||SF!=OF
400 #define PFOB_O (1 << PFO_O)
401 #define PFOB_C (1 << PFO_C)
402 #define PFOB_Z (1 << PFO_Z)
403 #define PFOB_S (1 << PFO_S)
405 static const char *parsed_flag_op_names[] = {
406 "o", "c", "z", "be", "s", "p", "l", "le"
409 static int char_array_i(const char *array[], size_t len, const char *s)
413 for (i = 0; i < len; i++)
420 static void printf_number(char *buf, size_t buf_size,
421 unsigned long number)
423 // output in C-friendly form
424 snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
427 static int check_segment_prefix(const char *s)
429 if (s[0] == 0 || s[1] != 's' || s[2] != ':')
433 case 'c': return SEG_CS;
434 case 'd': return SEG_DS;
435 case 's': return SEG_SS;
436 case 'e': return SEG_ES;
437 case 'f': return SEG_FS;
438 case 'g': return SEG_GS;
443 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
447 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
449 *reg_lmod = OPLM_QWORD;
453 *reg_lmod = OPLM_DWORD;
456 reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
458 *reg_lmod = OPLM_WORD;
461 reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
463 *reg_lmod = OPLM_BYTE;
466 reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
468 *reg_lmod = OPLM_BYTE;
475 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
477 enum opr_lenmod lmod;
490 while (my_isblank(*s))
492 for (; my_issep(*s); d++, s++)
494 while (my_isblank(*s))
498 // skip '?s:' prefixes
499 if (check_segment_prefix(s))
502 s = next_idt(w, sizeof(w), s);
507 reg = parse_reg(&lmod, w);
509 *regmask |= 1 << reg;
513 if ('0' <= w[0] && w[0] <= '9') {
514 number = parse_number(w, 0);
515 printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
519 // probably some label/identifier - pass
522 snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
526 strcpy(name, cvtbuf);
531 static int is_reg_in_str(const char *s)
535 if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
538 for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
539 if (!strncmp(s, regs_r32[i], 3))
545 static const char *parse_stack_el(const char *name, char *extra_reg,
546 int *base_val, int early_try)
548 const char *p, *p2, *s;
554 if (g_bp_frame || early_try)
557 if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
559 if (extra_reg != NULL) {
560 strncpy(extra_reg, name, 3);
565 if (IS_START(p, "ebp+")) {
569 if (p2 != NULL && is_reg_in_str(p)) {
570 if (extra_reg != NULL) {
571 strncpy(extra_reg, p, p2 - p);
572 extra_reg[p2 - p] = 0;
577 if (!('0' <= *p && *p <= '9'))
584 if (!IS_START(name, "esp+"))
590 if (is_reg_in_str(s)) {
591 if (extra_reg != NULL) {
592 strncpy(extra_reg, s, p - s);
593 extra_reg[p - s] = 0;
598 aerr("%s IDA stackvar not set?\n", __func__);
600 if (!('0' <= *s && *s <= '9')) {
601 aerr("%s IDA stackvar offset not set?\n", __func__);
604 if (s[0] == '0' && s[1] == 'x')
607 if (len < sizeof(buf) - 1) {
608 strncpy(buf, s, len);
611 val = strtol(buf, &endp, 16);
612 if (val == 0 || *endp != 0 || errno != 0) {
613 aerr("%s num parse fail for '%s'\n", __func__, buf);
622 if ('0' <= *p && *p <= '9')
625 if (base_val != NULL)
630 static int guess_lmod_from_name(struct parsed_opr *opr)
632 if (IS_START(opr->name, "dword_") || IS_START(opr->name, "off_")) {
633 opr->lmod = OPLM_DWORD;
636 if (IS_START(opr->name, "word_")) {
637 opr->lmod = OPLM_WORD;
640 if (IS_START(opr->name, "byte_")) {
641 opr->lmod = OPLM_BYTE;
644 if (IS_START(opr->name, "qword_")) {
645 opr->lmod = OPLM_QWORD;
651 static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
652 const struct parsed_type *c_type)
654 static const char *qword_types[] = {
655 "uint64_t", "int64_t", "__int64",
657 static const char *dword_types[] = {
658 "uint32_t", "int", "_DWORD", "UINT_PTR", "DWORD",
659 "WPARAM", "LPARAM", "UINT", "__int32",
660 "LONG", "HIMC", "BOOL", "size_t",
663 static const char *word_types[] = {
664 "uint16_t", "int16_t", "_WORD", "WORD",
665 "unsigned __int16", "__int16",
667 static const char *byte_types[] = {
668 "uint8_t", "int8_t", "char",
669 "unsigned __int8", "__int8", "BYTE", "_BYTE",
671 // structures.. deal the same as with _UNKNOWN for now
677 if (c_type->is_ptr) {
682 n = skip_type_mod(c_type->name);
684 for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
685 if (IS(n, dword_types[i])) {
691 for (i = 0; i < ARRAY_SIZE(word_types); i++) {
692 if (IS(n, word_types[i])) {
698 for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
699 if (IS(n, byte_types[i])) {
705 for (i = 0; i < ARRAY_SIZE(qword_types); i++) {
706 if (IS(n, qword_types[i])) {
715 static char *default_cast_to(char *buf, size_t buf_size,
716 struct parsed_opr *opr)
720 if (!opr->is_ptr || strchr(opr->name, '['))
722 if (opr->pp == NULL || opr->pp->type.name == NULL
725 snprintf(buf, buf_size, "%s", "(void *)");
729 snprintf(buf, buf_size, "(%s)", opr->pp->type.name);
733 static enum opr_type lmod_from_directive(const char *d)
737 else if (IS(d, "dw"))
739 else if (IS(d, "db"))
742 aerr("unhandled directive: '%s'\n", d);
746 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
752 *regmask |= 1 << reg;
755 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
758 static int parse_operand(struct parsed_opr *opr,
759 int *regmask, int *regmask_indirect,
760 char words[16][256], int wordc, int w, unsigned int op_flags)
762 const struct parsed_proto *pp = NULL;
763 enum opr_lenmod tmplmod;
764 unsigned long number;
772 aerr("parse_operand w %d, wordc %d\n", w, wordc);
776 for (i = w; i < wordc; i++) {
777 len = strlen(words[i]);
778 if (words[i][len - 1] == ',') {
779 words[i][len - 1] = 0;
785 wordc_in = wordc - w;
787 if ((op_flags & OPF_JMP) && wordc_in > 0
788 && !('0' <= words[w][0] && words[w][0] <= '9'))
790 const char *label = NULL;
792 if (wordc_in == 3 && !strncmp(words[w], "near", 4)
793 && IS(words[w + 1], "ptr"))
794 label = words[w + 2];
795 else if (wordc_in == 2 && IS(words[w], "short"))
796 label = words[w + 1];
797 else if (wordc_in == 1
798 && strchr(words[w], '[') == NULL
799 && parse_reg(&tmplmod, words[w]) < 0)
803 opr->type = OPT_LABEL;
804 ret = check_segment_prefix(label);
809 strcpy(opr->name, label);
815 if (IS(words[w + 1], "ptr")) {
816 if (IS(words[w], "dword"))
817 opr->lmod = OPLM_DWORD;
818 else if (IS(words[w], "word"))
819 opr->lmod = OPLM_WORD;
820 else if (IS(words[w], "byte"))
821 opr->lmod = OPLM_BYTE;
822 else if (IS(words[w], "qword"))
823 opr->lmod = OPLM_QWORD;
825 aerr("type parsing failed\n");
827 wordc_in = wordc - w;
832 if (IS(words[w], "offset")) {
833 opr->type = OPT_OFFSET;
834 opr->lmod = OPLM_DWORD;
835 strcpy(opr->name, words[w + 1]);
836 pp = proto_parse(g_fhdr, opr->name, 1);
839 if (IS(words[w], "(offset")) {
840 p = strchr(words[w + 1], ')');
842 aerr("parse of bracketed offset failed\n");
844 opr->type = OPT_OFFSET;
845 strcpy(opr->name, words[w + 1]);
851 aerr("parse_operand 1 word expected\n");
853 ret = check_segment_prefix(words[w]);
856 memmove(words[w], words[w] + 3, strlen(words[w]) - 2);
857 if (ret == SEG_FS && IS(words[w], "0"))
860 strcpy(opr->name, words[w]);
862 if (words[w][0] == '[') {
863 opr->type = OPT_REGMEM;
864 ret = sscanf(words[w], "[%[^]]]", opr->name);
866 aerr("[] parse failure\n");
868 parse_indmode(opr->name, regmask_indirect, 1);
869 if (opr->lmod == OPLM_UNSPEC
870 && parse_stack_el(opr->name, NULL, NULL, 1))
873 struct parsed_equ *eq =
874 equ_find(NULL, parse_stack_el(opr->name, NULL, NULL, 1), &i);
876 opr->lmod = eq->lmod;
878 // might be unaligned access
879 g_func_lmods |= 1 << OPLM_BYTE;
883 else if (strchr(words[w], '[')) {
885 p = strchr(words[w], '[');
886 opr->type = OPT_REGMEM;
887 parse_indmode(p, regmask_indirect, 0);
888 strncpy(buf, words[w], p - words[w]);
889 buf[p - words[w]] = 0;
890 pp = proto_parse(g_fhdr, buf, 1);
893 else if (('0' <= words[w][0] && words[w][0] <= '9')
894 || words[w][0] == '-')
896 number = parse_number(words[w], 0);
897 opr->type = OPT_CONST;
899 printf_number(opr->name, sizeof(opr->name), number);
903 ret = parse_reg(&tmplmod, opr->name);
905 setup_reg_opr(opr, ret, tmplmod, regmask);
909 // most likely var in data segment
910 opr->type = OPT_LABEL;
911 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
915 if (pp->is_fptr || pp->is_func) {
916 opr->lmod = OPLM_DWORD;
920 tmplmod = OPLM_UNSPEC;
921 if (!guess_lmod_from_c_type(&tmplmod, &pp->type))
922 anote("unhandled C type '%s' for '%s'\n",
923 pp->type.name, opr->name);
925 if (opr->lmod == OPLM_UNSPEC) {
927 opr->type_from_var = 1;
929 else if (opr->lmod != tmplmod) {
930 opr->size_mismatch = 1;
931 if (tmplmod < opr->lmod)
934 opr->is_ptr = pp->type.is_ptr;
936 opr->is_array = pp->type.is_array;
940 if (opr->lmod == OPLM_UNSPEC)
941 guess_lmod_from_name(opr);
945 static const struct {
950 { "repe", OPF_REP|OPF_REPZ },
951 { "repz", OPF_REP|OPF_REPZ },
952 { "repne", OPF_REP|OPF_REPNZ },
953 { "repnz", OPF_REP|OPF_REPNZ },
954 { "lock", OPF_LOCK }, // ignored for now..
957 #define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
959 static const struct {
962 unsigned short minopr;
963 unsigned short maxopr;
966 unsigned char pfo_inv;
968 { "nop", OP_NOP, 0, 0, 0 },
969 { "push", OP_PUSH, 1, 1, 0 },
970 { "pop", OP_POP, 1, 1, OPF_DATA },
971 { "pusha",OP_PUSHA, 0, 0, 0 },
972 { "popa", OP_POPA, 0, 0, OPF_DATA },
973 { "leave",OP_LEAVE, 0, 0, OPF_DATA },
974 { "mov" , OP_MOV, 2, 2, OPF_DATA },
975 { "lea", OP_LEA, 2, 2, OPF_DATA },
976 { "movzx",OP_MOVZX, 2, 2, OPF_DATA },
977 { "movsx",OP_MOVSX, 2, 2, OPF_DATA },
978 { "xchg", OP_XCHG, 2, 2, OPF_DATA },
979 { "not", OP_NOT, 1, 1, OPF_DATA },
980 { "xlat", OP_XLAT, 0, 0, OPF_DATA },
981 { "cdq", OP_CDQ, 0, 0, OPF_DATA },
982 { "bswap",OP_BSWAP, 1, 1, OPF_DATA },
983 { "lodsb",OP_LODS, 0, 0, OPF_DATA },
984 { "lodsw",OP_LODS, 0, 0, OPF_DATA },
985 { "lodsd",OP_LODS, 0, 0, OPF_DATA },
986 { "stosb",OP_STOS, 0, 0, OPF_DATA },
987 { "stosw",OP_STOS, 0, 0, OPF_DATA },
988 { "stosd",OP_STOS, 0, 0, OPF_DATA },
989 { "movsb",OP_MOVS, 0, 0, OPF_DATA },
990 { "movsw",OP_MOVS, 0, 0, OPF_DATA },
991 { "movsd",OP_MOVS, 0, 0, OPF_DATA },
992 { "cmpsb",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
993 { "cmpsw",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
994 { "cmpsd",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
995 { "scasb",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
996 { "scasw",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
997 { "scasd",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
998 { "std", OP_STD, 0, 0, OPF_DATA }, // special flag
999 { "cld", OP_CLD, 0, 0, OPF_DATA },
1000 { "add", OP_ADD, 2, 2, OPF_DATA|OPF_FLAGS },
1001 { "sub", OP_SUB, 2, 2, OPF_DATA|OPF_FLAGS },
1002 { "and", OP_AND, 2, 2, OPF_DATA|OPF_FLAGS },
1003 { "or", OP_OR, 2, 2, OPF_DATA|OPF_FLAGS },
1004 { "xor", OP_XOR, 2, 2, OPF_DATA|OPF_FLAGS },
1005 { "shl", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
1006 { "shr", OP_SHR, 2, 2, OPF_DATA|OPF_FLAGS },
1007 { "sal", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
1008 { "sar", OP_SAR, 2, 2, OPF_DATA|OPF_FLAGS },
1009 { "shld", OP_SHLD, 3, 3, OPF_DATA|OPF_FLAGS },
1010 { "shrd", OP_SHRD, 3, 3, OPF_DATA|OPF_FLAGS },
1011 { "rol", OP_ROL, 2, 2, OPF_DATA|OPF_FLAGS },
1012 { "ror", OP_ROR, 2, 2, OPF_DATA|OPF_FLAGS },
1013 { "rcl", OP_RCL, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1014 { "rcr", OP_RCR, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1015 { "adc", OP_ADC, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1016 { "sbb", OP_SBB, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1017 { "bsf", OP_BSF, 2, 2, OPF_DATA|OPF_FLAGS },
1018 { "bsr", OP_BSR, 2, 2, OPF_DATA|OPF_FLAGS },
1019 { "inc", OP_INC, 1, 1, OPF_DATA|OPF_FLAGS },
1020 { "dec", OP_DEC, 1, 1, OPF_DATA|OPF_FLAGS },
1021 { "neg", OP_NEG, 1, 1, OPF_DATA|OPF_FLAGS },
1022 { "mul", OP_MUL, 1, 1, OPF_DATA|OPF_FLAGS },
1023 { "imul", OP_IMUL, 1, 3, OPF_DATA|OPF_FLAGS },
1024 { "div", OP_DIV, 1, 1, OPF_DATA|OPF_FLAGS },
1025 { "idiv", OP_IDIV, 1, 1, OPF_DATA|OPF_FLAGS },
1026 { "test", OP_TEST, 2, 2, OPF_FLAGS },
1027 { "cmp", OP_CMP, 2, 2, OPF_FLAGS },
1028 { "retn", OP_RET, 0, 1, OPF_TAIL },
1029 { "call", OP_CALL, 1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
1030 { "jmp", OP_JMP, 1, 1, OPF_JMP },
1031 { "jecxz",OP_JECXZ, 1, 1, OPF_JMP|OPF_CJMP },
1032 { "loop", OP_LOOP, 1, 1, OPF_JMP|OPF_CJMP|OPF_DATA },
1033 { "jo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 0 }, // 70 OF=1
1034 { "jno", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 1 }, // 71 OF=0
1035 { "jc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72 CF=1
1036 { "jb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72
1037 { "jnc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73 CF=0
1038 { "jnb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1039 { "jae", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1040 { "jz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74 ZF=1
1041 { "je", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74
1042 { "jnz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75 ZF=0
1043 { "jne", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75
1044 { "jbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76 CF=1||ZF=1
1045 { "jna", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76
1046 { "ja", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77 CF=0&&ZF=0
1047 { "jnbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77
1048 { "js", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 0 }, // 78 SF=1
1049 { "jns", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 1 }, // 79 SF=0
1050 { "jp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a PF=1
1051 { "jpe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a
1052 { "jnp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b PF=0
1053 { "jpo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b
1054 { "jl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c SF!=OF
1055 { "jnge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c
1056 { "jge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d SF=OF
1057 { "jnl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d
1058 { "jle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e ZF=1||SF!=OF
1059 { "jng", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e
1060 { "jg", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f ZF=0&&SF=OF
1061 { "jnle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f
1062 { "seto", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 0 },
1063 { "setno", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 1 },
1064 { "setc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1065 { "setb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1066 { "setnc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1067 { "setae", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1068 { "setnb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1069 { "setz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1070 { "sete", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1071 { "setnz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1072 { "setne", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1073 { "setbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1074 { "setna", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1075 { "seta", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1076 { "setnbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1077 { "sets", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 0 },
1078 { "setns", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 1 },
1079 { "setp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1080 { "setpe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1081 { "setnp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1082 { "setpo", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1083 { "setl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1084 { "setnge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1085 { "setge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1086 { "setnl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1087 { "setle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1088 { "setng", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1089 { "setg", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1090 { "setnle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1092 { "fld", OP_FLD, 1, 1, OPF_FPUSH },
1093 { "fild", OP_FILD, 1, 1, OPF_FPUSH|OPF_FINT },
1094 { "fld1", OP_FLDc, 0, 0, OPF_FPUSH },
1095 { "fldl2t", OP_FLDc, 0, 0, OPF_FPUSH },
1096 { "fldl2e", OP_FLDc, 0, 0, OPF_FPUSH },
1097 { "fldpi", OP_FLDc, 0, 0, OPF_FPUSH },
1098 { "fldlg2", OP_FLDc, 0, 0, OPF_FPUSH },
1099 { "fldln2", OP_FLDc, 0, 0, OPF_FPUSH },
1100 { "fldz", OP_FLDc, 0, 0, OPF_FPUSH },
1101 { "fst", OP_FST, 1, 1, 0 },
1102 { "fstp", OP_FST, 1, 1, OPF_FPOP },
1103 { "fist", OP_FIST, 1, 1, OPF_FINT },
1104 { "fistp", OP_FIST, 1, 1, OPF_FPOP|OPF_FINT },
1105 { "fadd", OP_FADD, 0, 2, 0 },
1106 { "faddp", OP_FADD, 0, 2, OPF_FPOP },
1107 { "fdiv", OP_FDIV, 0, 2, 0 },
1108 { "fdivp", OP_FDIV, 0, 2, OPF_FPOP },
1109 { "fmul", OP_FMUL, 0, 2, 0 },
1110 { "fmulp", OP_FMUL, 0, 2, OPF_FPOP },
1111 { "fsub", OP_FSUB, 0, 2, 0 },
1112 { "fsubp", OP_FSUB, 0, 2, OPF_FPOP },
1113 { "fdivr", OP_FDIVR, 0, 2, 0 },
1114 { "fdivrp", OP_FDIVR, 0, 2, OPF_FPOP },
1115 { "fsubr", OP_FSUBR, 0, 2, 0 },
1116 { "fsubrp", OP_FSUBR, 0, 2, OPF_FPOP },
1117 { "fiadd", OP_FIADD, 1, 1, OPF_FINT },
1118 { "fidiv", OP_FIDIV, 1, 1, OPF_FINT },
1119 { "fimul", OP_FIMUL, 1, 1, OPF_FINT },
1120 { "fisub", OP_FISUB, 1, 1, OPF_FINT },
1121 { "fidivr", OP_FIDIVR, 1, 1, OPF_FINT },
1122 { "fisubr", OP_FISUBR, 1, 1, OPF_FINT },
1123 { "fcom", OP_FCOM, 0, 1, 0 },
1124 { "fcomp", OP_FCOM, 0, 1, OPF_FPOP },
1125 { "fcompp", OP_FCOM, 0, 0, OPF_FPOPP },
1126 { "fucom", OP_FCOM, 0, 1, 0 },
1127 { "fucomp", OP_FCOM, 0, 1, OPF_FPOP },
1128 { "fucompp",OP_FCOM, 0, 0, OPF_FPOPP },
1129 { "fnstsw", OP_FNSTSW, 1, 1, OPF_DATA },
1130 { "fchs", OP_FCHS, 0, 0, 0 },
1131 { "fcos", OP_FCOS, 0, 0, 0 },
1132 { "fpatan", OP_FPATAN, 0, 0, OPF_FPOP },
1133 { "fptan", OP_FPTAN, 0, 0, OPF_FPUSH },
1134 { "fsin", OP_FSIN, 0, 0, 0 },
1135 { "fsqrt", OP_FSQRT, 0, 0, 0 },
1136 { "fxch", OP_FXCH, 1, 1, 0 },
1137 { "fyl2x", OP_FYL2X, 0, 0, OPF_FPOP },
1139 { "emms", OP_EMMS, 0, 0, OPF_DATA },
1140 { "movq", OP_MOV, 2, 2, OPF_DATA },
1141 // pseudo-ops for lib calls
1142 { "_allshl",OPP_ALLSHL },
1143 { "_allshr",OPP_ALLSHR },
1144 { "_ftol", OPP_FTOL },
1145 { "_CIpow", OPP_CIPOW },
1146 { "abort", OPP_ABORT },
1151 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
1153 enum opr_lenmod lmod = OPLM_UNSPEC;
1154 int prefix_flags = 0;
1162 for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
1163 if (IS(words[w], pref_table[i].name)) {
1164 prefix_flags = pref_table[i].flags;
1171 aerr("lone prefix: '%s'\n", words[0]);
1176 for (i = 0; i < ARRAY_SIZE(op_table); i++) {
1177 if (IS(words[w], op_table[i].name))
1181 if (i == ARRAY_SIZE(op_table)) {
1183 aerr("unhandled op: '%s'\n", words[0]);
1188 op->op = op_table[i].op;
1189 op->flags = op_table[i].flags | prefix_flags;
1190 op->pfo = op_table[i].pfo;
1191 op->pfo_inv = op_table[i].pfo_inv;
1192 op->regmask_src = op->regmask_dst = 0;
1195 if (op->op == OP_UD2)
1198 for (opr = 0; opr < op_table[i].maxopr; opr++) {
1199 if (opr >= op_table[i].minopr && w >= wordc)
1202 regmask = regmask_ind = 0;
1203 w = parse_operand(&op->operand[opr], ®mask, ®mask_ind,
1204 words, wordc, w, op->flags);
1206 if (opr == 0 && (op->flags & OPF_DATA))
1207 op->regmask_dst = regmask;
1209 op->regmask_src |= regmask;
1210 op->regmask_src |= regmask_ind;
1212 if (op->operand[opr].lmod != OPLM_UNSPEC)
1213 g_func_lmods |= 1 << op->operand[opr].lmod;
1217 aerr("parse_op %s incomplete: %d/%d\n",
1218 words[0], w, wordc);
1221 op->operand_cnt = opr;
1222 if (!strncmp(op_table[i].name, "set", 3))
1223 op->operand[0].lmod = OPLM_BYTE;
1226 // first operand is not dst
1229 op->regmask_src |= op->regmask_dst;
1230 op->regmask_dst = 0;
1233 // first operand is src too
1246 op->regmask_src |= op->regmask_dst;
1251 op->regmask_src |= op->regmask_dst;
1252 op->regmask_dst |= op->regmask_src;
1258 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1259 && op->operand[0].lmod == op->operand[1].lmod
1260 && op->operand[0].reg == op->operand[1].reg
1261 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1263 op->regmask_src = 0;
1266 op->regmask_src |= op->regmask_dst;
1269 // ops with implicit argumets
1271 op->operand_cnt = 2;
1272 setup_reg_opr(&op->operand[0], xAX, OPLM_BYTE, &op->regmask_src);
1273 op->regmask_dst = op->regmask_src;
1274 setup_reg_opr(&op->operand[1], xBX, OPLM_DWORD, &op->regmask_src);
1278 op->operand_cnt = 2;
1279 setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
1280 setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
1286 if (words[op_w][4] == 'b')
1288 else if (words[op_w][4] == 'w')
1290 else if (words[op_w][4] == 'd')
1293 op->regmask_src = 0;
1294 setup_reg_opr(&op->operand[j++], op->op == OP_LODS ? xSI : xDI,
1295 OPLM_DWORD, &op->regmask_src);
1296 op->regmask_dst = op->regmask_src;
1297 setup_reg_opr(&op->operand[j++], xAX, lmod,
1298 op->op == OP_LODS ? &op->regmask_dst : &op->regmask_src);
1299 if (op->flags & OPF_REP) {
1300 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1301 op->regmask_dst |= 1 << xCX;
1303 op->operand_cnt = j;
1308 if (words[op_w][4] == 'b')
1310 else if (words[op_w][4] == 'w')
1312 else if (words[op_w][4] == 'd')
1315 op->regmask_src = 0;
1316 // note: lmod is not correct, don't have where to place it
1317 setup_reg_opr(&op->operand[j++], xDI, lmod, &op->regmask_src);
1318 setup_reg_opr(&op->operand[j++], xSI, OPLM_DWORD, &op->regmask_src);
1319 if (op->flags & OPF_REP)
1320 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1321 op->operand_cnt = j;
1322 op->regmask_dst = op->regmask_src;
1326 op->regmask_dst = 1 << xCX;
1329 op->operand_cnt = 2;
1330 op->regmask_src = 1 << xCX;
1331 op->operand[1].type = OPT_REG;
1332 op->operand[1].reg = xCX;
1333 op->operand[1].lmod = OPLM_DWORD;
1337 if (op->operand_cnt == 2) {
1338 if (op->operand[0].type != OPT_REG)
1339 aerr("reg expected\n");
1340 op->regmask_src |= 1 << op->operand[0].reg;
1342 if (op->operand_cnt != 1)
1347 if (op->operand[0].lmod == OPLM_UNSPEC)
1348 op->operand[0].lmod = OPLM_DWORD;
1349 op->regmask_src = mxAX | op->regmask_dst;
1350 op->regmask_dst = mxAX;
1351 if (op->operand[0].lmod != OPLM_BYTE)
1352 op->regmask_dst |= mxDX;
1357 // we could set up operands for edx:eax, but there is no real need to
1358 // (see is_opr_modified())
1359 if (op->operand[0].lmod == OPLM_UNSPEC)
1360 op->operand[0].lmod = OPLM_DWORD;
1361 op->regmask_src = mxAX | op->regmask_dst;
1362 op->regmask_dst = mxAX;
1363 if (op->operand[0].lmod != OPLM_BYTE) {
1364 op->regmask_src |= mxDX;
1365 op->regmask_dst |= mxDX;
1374 op->regmask_src |= op->regmask_dst;
1375 if (op->operand[1].lmod == OPLM_UNSPEC)
1376 op->operand[1].lmod = OPLM_BYTE;
1381 op->regmask_src |= op->regmask_dst;
1382 if (op->operand[2].lmod == OPLM_UNSPEC)
1383 op->operand[2].lmod = OPLM_BYTE;
1387 op->regmask_src |= op->regmask_dst;
1388 op->regmask_dst = 0;
1389 if (op->operand[0].lmod == OPLM_UNSPEC
1390 && (op->operand[0].type == OPT_CONST
1391 || op->operand[0].type == OPT_OFFSET
1392 || op->operand[0].type == OPT_LABEL))
1393 op->operand[0].lmod = OPLM_DWORD;
1399 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1400 && op->operand[0].lmod == op->operand[1].lmod
1401 && op->operand[0].reg == op->operand[1].reg
1402 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1404 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1405 op->regmask_src = op->regmask_dst = 0;
1410 if (op->operand[0].type == OPT_REG
1411 && op->operand[1].type == OPT_REGMEM)
1414 snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1415 if (IS(buf, op->operand[1].name))
1416 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1421 // needed because of OPF_DATA
1422 op->regmask_src = op->regmask_dst;
1423 // trashed regs must be explicitly detected later
1424 op->regmask_dst = 0;
1428 op->regmask_dst = (1 << xBP) | (1 << xSP);
1429 op->regmask_src = 1 << xBP;
1434 op->regmask_dst |= mxST0;
1438 op->regmask_dst |= mxST0;
1439 if (IS(words[op_w] + 3, "1"))
1440 op->operand[0].val = X87_CONST_1;
1441 else if (IS(words[op_w] + 3, "l2t"))
1442 op->operand[0].val = X87_CONST_L2T;
1443 else if (IS(words[op_w] + 3, "l2e"))
1444 op->operand[0].val = X87_CONST_L2E;
1445 else if (IS(words[op_w] + 3, "pi"))
1446 op->operand[0].val = X87_CONST_PI;
1447 else if (IS(words[op_w] + 3, "lg2"))
1448 op->operand[0].val = X87_CONST_LG2;
1449 else if (IS(words[op_w] + 3, "ln2"))
1450 op->operand[0].val = X87_CONST_LN2;
1451 else if (IS(words[op_w] + 3, "z"))
1452 op->operand[0].val = X87_CONST_Z;
1454 aerr("fld what?\n");
1459 op->regmask_src |= mxST0;
1468 op->regmask_src |= mxST0;
1469 if (op->operand_cnt == 2)
1470 op->regmask_src |= op->regmask_dst;
1471 else if (op->operand_cnt == 1) {
1472 memcpy(&op->operand[1], &op->operand[0], sizeof(op->operand[1]));
1473 op->operand[0].type = OPT_REG;
1474 op->operand[0].lmod = OPLM_QWORD;
1475 op->operand[0].reg = xST0;
1476 op->regmask_dst |= mxST0;
1479 // IDA doesn't use this
1480 aerr("no operands?\n");
1494 op->regmask_src |= mxST0;
1495 op->regmask_dst |= mxST0;
1500 op->regmask_src |= mxST0 | mxST1;
1501 op->regmask_dst |= mxST0;
1509 op->regmask_src |= mxST0;
1510 if (op->operand_cnt == 0) {
1511 op->operand_cnt = 1;
1512 op->operand[0].type = OPT_REG;
1513 op->operand[0].lmod = OPLM_QWORD;
1514 op->operand[0].reg = xST1;
1515 op->regmask_src |= mxST1;
1523 if (op->operand[0].type == OPT_REG
1524 && op->operand[1].type == OPT_CONST)
1526 struct parsed_opr *op1 = &op->operand[1];
1527 if ((op->op == OP_AND && op1->val == 0)
1530 || (op->operand[0].lmod == OPLM_WORD && op1->val == 0xffff)
1531 || (op->operand[0].lmod == OPLM_BYTE && op1->val == 0xff))))
1533 op->regmask_src = 0;
1538 static const char *op_name(struct parsed_op *po)
1540 static char buf[16];
1544 if (po->op == OP_JCC || po->op == OP_SCC) {
1546 *p++ = (po->op == OP_JCC) ? 'j' : 's';
1549 strcpy(p, parsed_flag_op_names[po->pfo]);
1553 for (i = 0; i < ARRAY_SIZE(op_table); i++)
1554 if (op_table[i].op == po->op)
1555 return op_table[i].name;
1561 static const char *dump_op(struct parsed_op *po)
1563 static char out[128];
1570 snprintf(out, sizeof(out), "%s", op_name(po));
1571 for (i = 0; i < po->operand_cnt; i++) {
1575 snprintf(p, sizeof(out) - (p - out),
1576 po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1577 po->operand[i].name);
1583 static const char *lmod_type_u(struct parsed_op *po,
1584 enum opr_lenmod lmod)
1596 ferr(po, "invalid lmod: %d\n", lmod);
1597 return "(_invalid_)";
1601 static const char *lmod_cast_u(struct parsed_op *po,
1602 enum opr_lenmod lmod)
1614 ferr(po, "invalid lmod: %d\n", lmod);
1615 return "(_invalid_)";
1619 static const char *lmod_cast_u_ptr(struct parsed_op *po,
1620 enum opr_lenmod lmod)
1632 ferr(po, "invalid lmod: %d\n", lmod);
1633 return "(_invalid_)";
1637 static const char *lmod_cast_s(struct parsed_op *po,
1638 enum opr_lenmod lmod)
1650 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1651 return "(_invalid_)";
1655 static const char *lmod_cast(struct parsed_op *po,
1656 enum opr_lenmod lmod, int is_signed)
1659 lmod_cast_s(po, lmod) :
1660 lmod_cast_u(po, lmod);
1663 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1675 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1680 static const char *opr_name(struct parsed_op *po, int opr_num)
1682 if (opr_num >= po->operand_cnt)
1683 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1684 return po->operand[opr_num].name;
1687 static unsigned int opr_const(struct parsed_op *po, int opr_num)
1689 if (opr_num >= po->operand_cnt)
1690 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1691 if (po->operand[opr_num].type != OPT_CONST)
1692 ferr(po, "opr %d: const expected\n", opr_num);
1693 return po->operand[opr_num].val;
1696 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1698 if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
1699 ferr(po, "invalid reg: %d\n", popr->reg);
1700 return regs_r32[popr->reg];
1703 static int check_simple_cast(const char *cast, int *bits, int *is_signed)
1705 if (IS_START(cast, "(s8)") || IS_START(cast, "(u8)"))
1707 else if (IS_START(cast, "(s16)") || IS_START(cast, "(u16)"))
1709 else if (IS_START(cast, "(s32)") || IS_START(cast, "(u32)"))
1711 else if (IS_START(cast, "(s64)") || IS_START(cast, "(u64)"))
1716 *is_signed = cast[1] == 's' ? 1 : 0;
1720 static int check_deref_cast(const char *cast, int *bits)
1722 if (IS_START(cast, "*(u8 *)"))
1724 else if (IS_START(cast, "*(u16 *)"))
1726 else if (IS_START(cast, "*(u32 *)"))
1728 else if (IS_START(cast, "*(u64 *)"))
1736 // cast1 is the "final" cast
1737 static const char *simplify_cast(const char *cast1, const char *cast2)
1739 static char buf[256];
1747 if (IS(cast1, cast2))
1750 if (check_simple_cast(cast1, &bits1, &s1) == 0
1751 && check_simple_cast(cast2, &bits2, &s2) == 0)
1756 if (check_simple_cast(cast1, &bits1, &s1) == 0
1757 && check_deref_cast(cast2, &bits2) == 0)
1759 if (bits1 == bits2) {
1760 snprintf(buf, sizeof(buf), "*(%c%d *)", s1 ? 's' : 'u', bits1);
1765 if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1768 snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1772 static const char *simplify_cast_num(const char *cast, unsigned int val)
1774 if (IS(cast, "(u8)") && val < 0x100)
1776 if (IS(cast, "(s8)") && val < 0x80)
1778 if (IS(cast, "(u16)") && val < 0x10000)
1780 if (IS(cast, "(s16)") && val < 0x8000)
1782 if (IS(cast, "(s32)") && val < 0x80000000)
1788 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1797 namelen = strlen(name);
1799 p = strpbrk(name, "+-");
1803 ferr(po, "equ parse failed for '%s'\n", name);
1806 *extra_offs = strtol(p, &endp, 16);
1807 if (*endp != 0 || errno != 0)
1808 ferr(po, "equ parse failed for '%s'\n", name);
1811 for (i = 0; i < g_eqcnt; i++)
1812 if (strncmp(g_eqs[i].name, name, namelen) == 0
1813 && g_eqs[i].name[namelen] == 0)
1817 ferr(po, "unresolved equ name: '%s'\n", name);
1824 static int is_stack_access(struct parsed_op *po,
1825 const struct parsed_opr *popr)
1827 return (parse_stack_el(popr->name, NULL, NULL, 0)
1828 || (g_bp_frame && !(po->flags & OPF_EBP_S)
1829 && IS_START(popr->name, "ebp")));
1832 static void parse_stack_access(struct parsed_op *po,
1833 const char *name, char *ofs_reg, int *offset_out,
1834 int *stack_ra_out, const char **bp_arg_out, int is_lea)
1836 const char *bp_arg = "";
1837 const char *p = NULL;
1838 struct parsed_equ *eq;
1845 if (IS_START(name, "ebp-")
1846 || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1849 if (IS_START(p, "0x"))
1852 offset = strtoul(p, &endp, 16);
1855 if (*endp != 0 || errno != 0)
1856 ferr(po, "ebp- parse of '%s' failed\n", name);
1859 bp_arg = parse_stack_el(name, ofs_reg, NULL, 0);
1860 eq = equ_find(po, bp_arg, &offset);
1862 ferr(po, "detected but missing eq\n");
1863 offset += eq->offset;
1866 if (!strncmp(name, "ebp", 3))
1869 // yes it sometimes LEAs ra for compares..
1870 if (!is_lea && ofs_reg[0] == 0
1871 && stack_ra <= offset && offset < stack_ra + 4)
1873 ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1876 *offset_out = offset;
1878 *stack_ra_out = stack_ra;
1880 *bp_arg_out = bp_arg;
1883 static int parse_stack_esp_offset(struct parsed_op *po,
1884 const char *name, int *offset_out)
1886 char ofs_reg[16] = { 0, };
1887 struct parsed_equ *eq;
1893 if (strstr(name, "esp") == NULL)
1895 bp_arg = parse_stack_el(name, ofs_reg, &base_val, 0);
1896 if (bp_arg == NULL) {
1897 // just plain offset?
1898 if (!IS_START(name, "esp+"))
1901 offset = strtol(name + 4, &endp, 0);
1902 if (endp == NULL || *endp != 0 || errno != 0)
1904 *offset_out = offset;
1908 if (ofs_reg[0] != 0)
1910 eq = equ_find(po, bp_arg, &offset);
1912 ferr(po, "detected but missing eq\n");
1913 offset += eq->offset;
1914 *offset_out = base_val + offset;
1918 static int stack_frame_access(struct parsed_op *po,
1919 struct parsed_opr *popr, char *buf, size_t buf_size,
1920 const char *name, const char *cast, int is_src, int is_lea)
1922 enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1923 const char *prefix = "";
1924 const char *bp_arg = NULL;
1925 char ofs_reg[16] = { 0, };
1926 int i, arg_i, arg_s;
1933 if (g_bp_frame && (po->flags & OPF_EBP_S)
1934 && !(po->regmask_src & mxSP))
1935 ferr(po, "stack_frame_access while ebp is scratch\n");
1937 parse_stack_access(po, name, ofs_reg, &offset,
1938 &stack_ra, &bp_arg, is_lea);
1940 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1942 if (offset > stack_ra)
1944 arg_i = (offset - stack_ra - 4) / 4;
1945 if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1947 if (g_func_pp->is_vararg
1948 && arg_i == g_func_pp->argc_stack && is_lea)
1950 // should be va_list
1953 snprintf(buf, buf_size, "%sap", cast);
1956 ferr(po, "offset %d (%s,%d) doesn't map to any arg\n",
1957 offset, bp_arg, arg_i);
1959 if (ofs_reg[0] != 0)
1960 ferr(po, "offset reg on arg access?\n");
1962 for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1963 if (g_func_pp->arg[i].reg != NULL)
1969 if (i == g_func_pp->argc)
1970 ferr(po, "arg %d not in prototype?\n", arg_i);
1972 popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
1979 ferr(po, "lea/byte to arg?\n");
1980 if (is_src && (offset & 3) == 0)
1981 snprintf(buf, buf_size, "%sa%d",
1982 simplify_cast(cast, "(u8)"), i + 1);
1984 snprintf(buf, buf_size, "%sBYTE%d(a%d)",
1985 cast, offset & 3, i + 1);
1990 ferr(po, "lea/word to arg?\n");
1995 ferr(po, "problematic arg store\n");
1996 snprintf(buf, buf_size, "%s((char *)&a%d + 1)",
1997 simplify_cast(cast, "*(u16 *)"), i + 1);
2000 ferr(po, "unaligned arg word load\n");
2002 else if (is_src && (offset & 2) == 0)
2003 snprintf(buf, buf_size, "%sa%d",
2004 simplify_cast(cast, "(u16)"), i + 1);
2006 snprintf(buf, buf_size, "%s%sWORD(a%d)",
2007 cast, (offset & 2) ? "HI" : "LO", i + 1);
2019 snprintf(buf, buf_size, "(u32)&a%d + %d",
2022 ferr(po, "unaligned arg store\n");
2024 // mov edx, [ebp+arg_4+2]; movsx ecx, dx
2025 snprintf(buf, buf_size, "%s(a%d >> %d)",
2026 prefix, i + 1, (offset & 3) * 8);
2030 snprintf(buf, buf_size, "%s%sa%d",
2031 prefix, is_lea ? "&" : "", i + 1);
2036 ferr_assert(po, !(offset & 7));
2039 snprintf(buf, buf_size, "%s%sa%d",
2040 prefix, is_lea ? "&" : "", i + 1);
2044 ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
2048 strcat(g_comment, " unaligned");
2051 guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
2052 if (tmp_lmod != OPLM_DWORD
2053 && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
2054 < lmod_bytes(po, popr->lmod) + (offset & 3))))
2056 ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
2057 i + 1, offset, g_func_pp->arg[i].type.name);
2059 // can't check this because msvc likes to reuse
2060 // arg space for scratch..
2061 //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
2062 // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
2066 if (g_stack_fsz == 0)
2067 ferr(po, "stack var access without stackframe\n");
2068 g_stack_frame_used = 1;
2070 sf_ofs = g_stack_fsz + offset;
2071 if (ofs_reg[0] == 0 && (offset > 0 || sf_ofs < 0))
2072 ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
2082 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2083 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2087 if ((sf_ofs & 1) || ofs_reg[0] != 0) {
2088 // known unaligned or possibly unaligned
2089 strcat(g_comment, " unaligned");
2091 prefix = "*(u16 *)&";
2092 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2093 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2096 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
2100 if ((sf_ofs & 3) || ofs_reg[0] != 0) {
2101 // known unaligned or possibly unaligned
2102 strcat(g_comment, " unaligned");
2104 prefix = "*(u32 *)&";
2105 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2106 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2109 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
2113 ferr_assert(po, !(sf_ofs & 7));
2114 ferr_assert(po, ofs_reg[0] == 0);
2115 // only used for x87 int64/float, float sets is_lea
2116 if (!is_lea && (po->flags & OPF_FINT))
2117 prefix = "*(s64 *)&";
2118 snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
2122 ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
2129 static void check_func_pp(struct parsed_op *po,
2130 const struct parsed_proto *pp, const char *pfx)
2132 enum opr_lenmod tmp_lmod;
2136 if (pp->argc_reg != 0) {
2137 if (!g_allow_user_icall && !pp->is_fastcall) {
2138 pp_print(buf, sizeof(buf), pp);
2139 ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
2141 if (pp->argc_stack > 0 && pp->argc_reg != 2)
2142 ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
2143 pfx, pp->argc_reg, pp->argc_stack);
2146 // fptrs must use 32bit args, callsite might have no information and
2147 // lack a cast to smaller types, which results in incorrectly masked
2148 // args passed (callee may assume masked args, it does on ARM)
2149 if (!pp->is_osinc) {
2150 for (i = 0; i < pp->argc; i++) {
2151 ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
2152 if (ret && tmp_lmod != OPLM_DWORD)
2153 ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
2154 i + 1, pp->arg[i].type.name);
2159 static const char *check_label_read_ref(struct parsed_op *po,
2160 const char *name, int *is_import)
2162 const struct parsed_proto *pp;
2164 pp = proto_parse(g_fhdr, name, 0);
2166 ferr(po, "proto_parse failed for ref '%s'\n", name);
2169 check_func_pp(po, pp, "ref");
2171 if (is_import != NULL)
2172 *is_import = pp->is_import;
2177 static void check_opr(struct parsed_op *po, struct parsed_opr *popr)
2179 if (popr->segment == SEG_FS)
2180 ferr(po, "fs: used\n");
2181 if (popr->segment == SEG_GS)
2182 ferr(po, "gs: used\n");
2185 static char *out_src_opr(char *buf, size_t buf_size,
2186 struct parsed_op *po, struct parsed_opr *popr, const char *cast,
2189 char tmp1[256], tmp2[256];
2196 check_opr(po, popr);
2201 switch (popr->type) {
2204 ferr(po, "lea from reg?\n");
2206 switch (popr->lmod) {
2208 snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2211 snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2214 snprintf(buf, buf_size, "%s%s",
2215 simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2218 if (popr->name[1] == 'h') // XXX..
2219 snprintf(buf, buf_size, "%s(%s >> 8)",
2220 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2222 snprintf(buf, buf_size, "%s%s",
2223 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2226 ferr(po, "invalid src lmod: %d\n", popr->lmod);
2231 if (is_stack_access(po, popr)) {
2232 stack_frame_access(po, popr, buf, buf_size,
2233 popr->name, cast, 1, is_lea);
2237 strcpy(expr, popr->name);
2238 if (strchr(expr, '[')) {
2239 // special case: '[' can only be left for label[reg] form
2240 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2242 ferr(po, "parse failure for '%s'\n", expr);
2243 if (tmp1[0] == '(') {
2244 // (off_4FFF50+3)[eax]
2245 p = strchr(tmp1 + 1, ')');
2246 if (p == NULL || p[1] != 0)
2247 ferr(po, "parse failure (2) for '%s'\n", expr);
2249 memmove(tmp1, tmp1 + 1, strlen(tmp1));
2251 snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2254 // XXX: do we need more parsing?
2256 snprintf(buf, buf_size, "%s", expr);
2260 snprintf(buf, buf_size, "%s(%s)",
2261 simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2265 name = check_label_read_ref(po, popr->name, &is_import);
2267 // for imported data, asm is loading the offset
2270 if (cast[0] == 0 && popr->is_ptr)
2274 snprintf(buf, buf_size, "(u32)&%s", name);
2275 else if (popr->size_lt)
2276 snprintf(buf, buf_size, "%s%s%s%s", cast,
2277 lmod_cast_u_ptr(po, popr->lmod),
2278 popr->is_array ? "" : "&", name);
2280 snprintf(buf, buf_size, "%s%s%s", cast, name,
2281 popr->is_array ? "[0]" : "");
2286 name = check_label_read_ref(po, popr->name, NULL);
2290 ferr(po, "lea an offset?\n");
2291 snprintf(buf, buf_size, "%s&%s", cast, name);
2296 ferr(po, "lea from const?\n");
2298 printf_number(tmp1, sizeof(tmp1), popr->val);
2299 if (popr->val == 0 && strchr(cast, '*'))
2300 snprintf(buf, buf_size, "NULL");
2302 snprintf(buf, buf_size, "%s%s",
2303 simplify_cast_num(cast, popr->val), tmp1);
2307 ferr(po, "invalid src type: %d\n", popr->type);
2313 // note: may set is_ptr (we find that out late for ebp frame..)
2314 static char *out_dst_opr(char *buf, size_t buf_size,
2315 struct parsed_op *po, struct parsed_opr *popr)
2317 check_opr(po, popr);
2319 switch (popr->type) {
2321 switch (popr->lmod) {
2323 snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2326 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2330 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2334 if (popr->name[1] == 'h') // XXX..
2335 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2337 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2340 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2345 if (is_stack_access(po, popr)) {
2346 stack_frame_access(po, popr, buf, buf_size,
2347 popr->name, "", 0, 0);
2351 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2354 if (popr->size_mismatch)
2355 snprintf(buf, buf_size, "%s%s%s",
2356 lmod_cast_u_ptr(po, popr->lmod),
2357 popr->is_array ? "" : "&", popr->name);
2359 snprintf(buf, buf_size, "%s%s", popr->name,
2360 popr->is_array ? "[0]" : "");
2364 ferr(po, "invalid dst type: %d\n", popr->type);
2370 static char *out_src_opr_u32(char *buf, size_t buf_size,
2371 struct parsed_op *po, struct parsed_opr *popr)
2373 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2376 static char *out_opr_float(char *buf, size_t buf_size,
2377 struct parsed_op *po, struct parsed_opr *popr, int is_src,
2378 int need_float_stack)
2380 const char *cast = NULL;
2387 switch (popr->type) {
2389 if (popr->reg < xST0 || popr->reg > xST7) {
2391 ferr_assert(po, po->op == OP_PUSH);
2392 ferr_assert(po, popr->lmod == OPLM_DWORD);
2393 snprintf(buf, buf_size, "*(float *)&%s", opr_reg_p(po, popr));
2397 if (need_float_stack) {
2398 if (popr->reg == xST0)
2399 snprintf(buf, buf_size, "f_st[f_stp & 7]");
2401 snprintf(buf, buf_size, "f_st[(f_stp + %d) & 7]",
2405 snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2409 if (popr->lmod == OPLM_QWORD && is_stack_access(po, popr)) {
2410 stack_frame_access(po, popr, buf, buf_size,
2411 popr->name, "", is_src, 0);
2417 switch (popr->lmod) {
2425 ferr(po, "unhandled lmod: %d\n", popr->lmod);
2428 out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2429 snprintf(buf, buf_size, "*(%s *)(%s)", cast, tmp);
2433 // only for func float args pushes
2434 ferr_assert(po, po->op == OP_PUSH);
2435 u.i = po->operand[0].val;
2436 if (ceilf(u.f) == u.f)
2437 snprintf(buf, buf_size, "%.1ff", u.f);
2439 snprintf(buf, buf_size, "%.8ff", u.f);
2443 ferr(po, "invalid float type: %d\n", popr->type);
2449 static char *out_src_opr_float(char *buf, size_t buf_size,
2450 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2452 return out_opr_float(buf, buf_size, po, popr, 1, need_float_stack);
2455 static char *out_dst_opr_float(char *buf, size_t buf_size,
2456 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2458 return out_opr_float(buf, buf_size, po, popr, 0, need_float_stack);
2461 static void out_test_for_cc(char *buf, size_t buf_size,
2462 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2463 enum opr_lenmod lmod, const char *expr)
2465 const char *cast, *scast;
2467 cast = lmod_cast_u(po, lmod);
2468 scast = lmod_cast_s(po, lmod);
2472 case PFO_BE: // CF==1||ZF==1; CF=0
2473 snprintf(buf, buf_size, "(%s%s %s 0)",
2474 cast, expr, is_inv ? "!=" : "==");
2478 case PFO_L: // SF!=OF; OF=0
2479 snprintf(buf, buf_size, "(%s%s %s 0)",
2480 scast, expr, is_inv ? ">=" : "<");
2483 case PFO_LE: // ZF==1||SF!=OF; OF=0
2484 snprintf(buf, buf_size, "(%s%s %s 0)",
2485 scast, expr, is_inv ? ">" : "<=");
2490 snprintf(buf, buf_size, "(%d)", !!is_inv);
2493 case PFO_P: // PF==1
2494 snprintf(buf, buf_size, "(%sdo_parity(%s))",
2495 is_inv ? "!" : "", expr);
2499 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2503 static void out_cmp_for_cc(char *buf, size_t buf_size,
2504 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2507 const char *cast, *scast, *cast_use;
2508 char buf1[256], buf2[256];
2509 enum opr_lenmod lmod;
2511 if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2512 ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2513 po->operand[0].lmod, po->operand[1].lmod);
2514 lmod = po->operand[0].lmod;
2516 cast = lmod_cast_u(po, lmod);
2517 scast = lmod_cast_s(po, lmod);
2533 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2536 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2537 if (po->op == OP_DEC)
2538 snprintf(buf2, sizeof(buf2), "1");
2541 snprintf(cast_op2, sizeof(cast_op2) - 1, "%s", cast_use);
2543 strcat(cast_op2, "-");
2544 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_op2, 0);
2549 // note: must be unsigned compare
2550 snprintf(buf, buf_size, "(%s %s %s)",
2551 buf1, is_inv ? ">=" : "<", buf2);
2555 snprintf(buf, buf_size, "(%s %s %s)",
2556 buf1, is_inv ? "!=" : "==", buf2);
2560 // note: must be unsigned compare
2561 snprintf(buf, buf_size, "(%s %s %s)",
2562 buf1, is_inv ? ">" : "<=", buf2);
2565 if (is_inv && lmod == OPLM_BYTE
2566 && po->operand[1].type == OPT_CONST
2567 && po->operand[1].val == 0xff)
2569 snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2570 snprintf(buf, buf_size, "(0)");
2574 // note: must be signed compare
2576 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2577 scast, buf1, buf2, is_inv ? ">=" : "<");
2581 snprintf(buf, buf_size, "(%s %s %s)",
2582 buf1, is_inv ? ">=" : "<", buf2);
2586 snprintf(buf, buf_size, "(%s %s %s)",
2587 buf1, is_inv ? ">" : "<=", buf2);
2595 static void out_cmp_test(char *buf, size_t buf_size,
2596 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2598 char buf1[256], buf2[256], buf3[256];
2600 if (po->op == OP_TEST) {
2601 if (IS(opr_name(po, 0), opr_name(po, 1))) {
2602 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2605 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2606 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2607 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2609 out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2610 po->operand[0].lmod, buf3);
2612 else if (po->op == OP_CMP) {
2613 out_cmp_for_cc(buf, buf_size, po, pfo, is_inv, 0);
2616 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2619 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2620 struct parsed_opr *popr2)
2622 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2623 ferr(po, "missing lmod for both operands\n");
2625 if (popr1->lmod == OPLM_UNSPEC)
2626 popr1->lmod = popr2->lmod;
2627 else if (popr2->lmod == OPLM_UNSPEC)
2628 popr2->lmod = popr1->lmod;
2629 else if (popr1->lmod != popr2->lmod) {
2630 if (popr1->type_from_var) {
2631 popr1->size_mismatch = 1;
2632 if (popr1->lmod < popr2->lmod)
2634 popr1->lmod = popr2->lmod;
2636 else if (popr2->type_from_var) {
2637 popr2->size_mismatch = 1;
2638 if (popr2->lmod < popr1->lmod)
2640 popr2->lmod = popr1->lmod;
2643 ferr(po, "conflicting lmods: %d vs %d\n",
2644 popr1->lmod, popr2->lmod);
2648 static const char *op_to_c(struct parsed_op *po)
2672 ferr(po, "op_to_c was supplied with %d\n", po->op);
2676 // last op in stream - unconditional branch or ret
2677 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2678 || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2679 && ops[_i].op != OP_CALL))
2681 #define check_i(po, i) \
2683 ferr(po, "bad " #i ": %d\n", i)
2685 // note: this skips over calls and rm'd stuff assuming they're handled
2686 // so it's intended to use at one of final passes
2687 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2688 int depth, int seen_noreturn, int flags_set)
2690 struct parsed_op *po;
2695 for (; i < opcnt; i++) {
2697 if (po->cc_scratch == magic)
2698 return ret; // already checked
2699 po->cc_scratch = magic;
2701 if (po->flags & OPF_TAIL) {
2702 if (po->op == OP_CALL) {
2703 if (po->pp != NULL && po->pp->is_noreturn)
2712 if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
2715 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2716 if (po->btj != NULL) {
2718 for (j = 0; j < po->btj->count; j++) {
2719 check_i(po, po->btj->d[j].bt_i);
2720 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2721 depth, seen_noreturn, flags_set);
2723 return ret; // dead end
2728 check_i(po, po->bt_i);
2729 if (po->flags & OPF_CJMP) {
2730 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2731 depth, seen_noreturn, flags_set);
2733 return ret; // dead end
2742 if ((po->op == OP_POP || po->op == OP_PUSH)
2743 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2748 if (po->op == OP_PUSH) {
2751 else if (po->op == OP_POP) {
2752 if (relevant && depth == 0) {
2753 po->flags |= flags_set;
2761 // for noreturn, assume msvc skipped stack cleanup
2762 return seen_noreturn ? 1 : -1;
2765 // scan for 'reg' pop backwards starting from i
2766 // intended to use for register restore search, so other reg
2767 // references are considered an error
2768 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2770 struct parsed_op *po;
2771 struct label_ref *lr;
2774 ops[i].cc_scratch = magic;
2778 if (g_labels[i] != NULL) {
2779 lr = &g_label_refs[i];
2780 for (; lr != NULL; lr = lr->next) {
2781 check_i(&ops[i], lr->i);
2782 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2786 if (i > 0 && LAST_OP(i - 1))
2794 if (ops[i].cc_scratch == magic)
2796 ops[i].cc_scratch = magic;
2799 if (po->op == OP_POP && po->operand[0].reg == reg) {
2800 if (po->flags & (OPF_RMD|OPF_DONE))
2803 po->flags |= set_flags;
2807 // this also covers the case where we reach corresponding push
2808 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2812 // nothing interesting on this path,
2813 // still return ret for something recursive calls could find
2817 static void find_reachable_exits(int i, int opcnt, int magic,
2818 int *exits, int *exit_count)
2820 struct parsed_op *po;
2823 for (; i < opcnt; i++)
2826 if (po->cc_scratch == magic)
2828 po->cc_scratch = magic;
2830 if (po->flags & OPF_TAIL) {
2831 ferr_assert(po, *exit_count < MAX_EXITS);
2832 exits[*exit_count] = i;
2837 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2838 if (po->flags & OPF_RMD)
2841 if (po->btj != NULL) {
2842 for (j = 0; j < po->btj->count; j++) {
2843 check_i(po, po->btj->d[j].bt_i);
2844 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2850 check_i(po, po->bt_i);
2851 if (po->flags & OPF_CJMP)
2852 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2860 // scan for 'reg' pop backwards starting from exits (all paths)
2861 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2863 static int exits[MAX_EXITS];
2864 static int exit_count;
2870 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2872 ferr_assert(&ops[i], exit_count > 0);
2875 for (j = 0; j < exit_count; j++) {
2877 ret = scan_for_rsave_pop_reg(e, i + opcnt * 16 + set_flags,
2883 if (ops[e].op == OP_CALL && ops[e].pp != NULL
2884 && ops[e].pp->is_noreturn)
2886 // assume stack cleanup was skipped
2895 // scan for one or more pop of push <const>
2896 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2897 int push_i, int is_probe)
2899 struct parsed_op *po;
2900 struct label_ref *lr;
2904 for (; i < opcnt; i++)
2907 if (po->cc_scratch == magic)
2908 return ret; // already checked
2909 po->cc_scratch = magic;
2911 if (po->flags & OPF_JMP) {
2912 if (po->flags & OPF_RMD)
2914 if (po->op == OP_CALL)
2917 if (po->btj != NULL) {
2918 for (j = 0; j < po->btj->count; j++) {
2919 check_i(po, po->btj->d[j].bt_i);
2920 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2928 check_i(po, po->bt_i);
2929 if (po->flags & OPF_CJMP) {
2930 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2941 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2944 if (g_labels[i] != NULL) {
2945 // all refs must be visited
2946 lr = &g_label_refs[i];
2947 for (; lr != NULL; lr = lr->next) {
2949 if (ops[lr->i].cc_scratch != magic)
2952 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2956 if (po->op == OP_POP)
2958 if (po->flags & (OPF_RMD|OPF_DONE))
2962 po->flags |= OPF_DONE;
2963 po->datap = &ops[push_i];
2972 static void scan_for_pop_const(int i, int opcnt, int magic)
2976 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
2978 ops[i].flags |= OPF_RMD | OPF_DONE;
2979 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
2983 // check if all branch targets within a marked path are also marked
2984 // note: the path checked must not be empty or end with a branch
2985 static int check_path_branches(int opcnt, int magic)
2987 struct parsed_op *po;
2990 for (i = 0; i < opcnt; i++) {
2992 if (po->cc_scratch != magic)
2995 if (po->flags & OPF_JMP) {
2996 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
2999 if (po->btj != NULL) {
3000 for (j = 0; j < po->btj->count; j++) {
3001 check_i(po, po->btj->d[j].bt_i);
3002 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
3007 check_i(po, po->bt_i);
3008 if (ops[po->bt_i].cc_scratch != magic)
3010 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
3018 // scan for multiple pushes for given pop
3019 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
3022 int reg = ops[pop_i].operand[0].reg;
3023 struct parsed_op *po;
3024 struct label_ref *lr;
3027 ops[i].cc_scratch = magic;
3031 if (g_labels[i] != NULL) {
3032 lr = &g_label_refs[i];
3033 for (; lr != NULL; lr = lr->next) {
3034 check_i(&ops[i], lr->i);
3035 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
3039 if (i > 0 && LAST_OP(i - 1))
3047 if (ops[i].cc_scratch == magic)
3049 ops[i].cc_scratch = magic;
3052 if (po->op == OP_CALL)
3054 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
3057 if (po->op == OP_PUSH)
3059 if (po->datap != NULL)
3061 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
3062 // leave this case for reg save/restore handlers
3066 po->flags |= OPF_PPUSH | OPF_DONE;
3067 po->datap = &ops[pop_i];
3076 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
3078 int magic = i + opcnt * 14;
3081 ret = scan_pushes_for_pop_r(i, magic, i, 1);
3083 ret = check_path_branches(opcnt, magic);
3085 ops[i].flags |= OPF_PPUSH | OPF_DONE;
3086 *regmask_pp |= 1 << ops[i].operand[0].reg;
3087 scan_pushes_for_pop_r(i, magic + 1, i, 0);
3092 static void scan_propagate_df(int i, int opcnt)
3094 struct parsed_op *po = &ops[i];
3097 for (; i < opcnt; i++) {
3099 if (po->flags & OPF_DF)
3100 return; // already resolved
3101 po->flags |= OPF_DF;
3103 if (po->op == OP_CALL)
3104 ferr(po, "call with DF set?\n");
3106 if (po->flags & OPF_JMP) {
3107 if (po->btj != NULL) {
3109 for (j = 0; j < po->btj->count; j++) {
3110 check_i(po, po->btj->d[j].bt_i);
3111 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
3116 if (po->flags & OPF_RMD)
3118 check_i(po, po->bt_i);
3119 if (po->flags & OPF_CJMP)
3120 scan_propagate_df(po->bt_i, opcnt);
3126 if (po->flags & OPF_TAIL)
3129 if (po->op == OP_CLD) {
3130 po->flags |= OPF_RMD | OPF_DONE;
3135 ferr(po, "missing DF clear?\n");
3138 // is operand 'opr' referenced by parsed_op 'po'?
3139 static int is_opr_referenced(const struct parsed_opr *opr,
3140 const struct parsed_op *po)
3144 if (opr->type == OPT_REG) {
3145 mask = po->regmask_dst | po->regmask_src;
3146 if (po->op == OP_CALL)
3147 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
3148 if ((1 << opr->reg) & mask)
3154 for (i = 0; i < po->operand_cnt; i++)
3155 if (IS(po->operand[0].name, opr->name))
3161 // is operand 'opr' read by parsed_op 'po'?
3162 static int is_opr_read(const struct parsed_opr *opr,
3163 const struct parsed_op *po)
3165 if (opr->type == OPT_REG) {
3166 if (po->regmask_src & (1 << opr->reg))
3176 // is operand 'opr' modified by parsed_op 'po'?
3177 static int is_opr_modified(const struct parsed_opr *opr,
3178 const struct parsed_op *po)
3182 if (opr->type == OPT_REG) {
3183 if (po->op == OP_CALL) {
3184 mask = po->regmask_dst;
3185 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
3186 if (mask & (1 << opr->reg))
3192 if (po->regmask_dst & (1 << opr->reg))
3198 return IS(po->operand[0].name, opr->name);
3201 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
3202 static int is_any_opr_modified(const struct parsed_op *po_test,
3203 const struct parsed_op *po, int c_mode)
3208 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
3211 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3214 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
3217 // in reality, it can wreck any register, but in decompiled C
3218 // version it can only overwrite eax or edx:eax
3219 mask = (1 << xAX) | (1 << xDX);
3223 if (po->op == OP_CALL
3224 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
3227 for (i = 0; i < po_test->operand_cnt; i++)
3228 if (IS(po_test->operand[i].name, po->operand[0].name))
3234 // scan for any po_test operand modification in range given
3235 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
3238 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3241 for (; i < opcnt; i++) {
3242 if (is_any_opr_modified(po_test, &ops[i], c_mode))
3249 // scan for po_test operand[0] modification in range given
3250 static int scan_for_mod_opr0(struct parsed_op *po_test,
3253 for (; i < opcnt; i++) {
3254 if (is_opr_modified(&po_test->operand[0], &ops[i]))
3261 static int try_resolve_const(int i, const struct parsed_opr *opr,
3262 int magic, unsigned int *val);
3264 static int scan_for_flag_set(int i, int opcnt, int magic,
3265 int *branched, int *setters, int *setter_cnt)
3267 struct label_ref *lr;
3271 if (ops[i].cc_scratch == magic) {
3272 // is this a problem?
3273 //ferr(&ops[i], "%s looped\n", __func__);
3276 ops[i].cc_scratch = magic;
3278 if (g_labels[i] != NULL) {
3281 lr = &g_label_refs[i];
3282 for (; lr->next; lr = lr->next) {
3283 check_i(&ops[i], lr->i);
3284 ret = scan_for_flag_set(lr->i, opcnt, magic,
3285 branched, setters, setter_cnt);
3290 check_i(&ops[i], lr->i);
3291 if (i > 0 && LAST_OP(i - 1)) {
3295 ret = scan_for_flag_set(lr->i, opcnt, magic,
3296 branched, setters, setter_cnt);
3302 if (ops[i].flags & OPF_FLAGS) {
3303 setters[*setter_cnt] = i;
3306 if (ops[i].flags & OPF_REP) {
3307 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
3310 ret = try_resolve_const(i, &opr, i + opcnt * 7, &uval);
3311 if (ret != 1 || uval == 0) {
3312 // can't treat it as full setter because of ecx=0 case,
3313 // also disallow delayed compare
3322 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3329 // scan back for cdq, if anything modifies edx, fail
3330 static int scan_for_cdq_edx(int i)
3333 if (g_labels[i] != NULL) {
3334 if (g_label_refs[i].next != NULL)
3336 if (i > 0 && LAST_OP(i - 1)) {
3337 i = g_label_refs[i].i;
3344 if (ops[i].op == OP_CDQ)
3347 if (ops[i].regmask_dst & (1 << xDX))
3354 static int scan_for_reg_clear(int i, int reg)
3357 if (g_labels[i] != NULL) {
3358 if (g_label_refs[i].next != NULL)
3360 if (i > 0 && LAST_OP(i - 1)) {
3361 i = g_label_refs[i].i;
3368 if (ops[i].op == OP_XOR
3369 && ops[i].operand[0].lmod == OPLM_DWORD
3370 && ops[i].operand[0].reg == ops[i].operand[1].reg
3371 && ops[i].operand[0].reg == reg)
3374 if (ops[i].regmask_dst & (1 << reg))
3381 static void patch_esp_adjust(struct parsed_op *po, int adj)
3383 ferr_assert(po, po->op == OP_ADD);
3384 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3385 ferr_assert(po, po->operand[1].type == OPT_CONST);
3387 // this is a bit of a hack, but deals with use of
3388 // single adj for multiple calls
3389 po->operand[1].val -= adj;
3390 po->flags |= OPF_RMD;
3391 if (po->operand[1].val == 0)
3392 po->flags |= OPF_DONE;
3393 ferr_assert(po, (int)po->operand[1].val >= 0);
3396 // scan for positive, constant esp adjust
3397 // multipath case is preliminary
3398 static int scan_for_esp_adjust(int i, int opcnt,
3399 int adj_expect, int *adj, int *is_multipath, int do_update)
3401 int adj_expect_unknown = 0;
3402 struct parsed_op *po;
3406 *adj = *is_multipath = 0;
3407 if (adj_expect < 0) {
3408 adj_expect_unknown = 1;
3409 adj_expect = 32 * 4; // enough?
3412 for (; i < opcnt && *adj < adj_expect; i++) {
3413 if (g_labels[i] != NULL)
3417 if (po->flags & OPF_DONE)
3420 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3421 if (po->operand[1].type != OPT_CONST)
3422 ferr(&ops[i], "non-const esp adjust?\n");
3423 *adj += po->operand[1].val;
3425 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3428 patch_esp_adjust(po, adj_expect);
3430 po->flags |= OPF_RMD;
3434 else if (po->op == OP_PUSH) {
3435 //if (first_pop == -1)
3436 // first_pop = -2; // none
3437 *adj -= lmod_bytes(po, po->operand[0].lmod);
3439 else if (po->op == OP_POP) {
3440 if (!(po->flags & OPF_DONE)) {
3441 // seems like msvc only uses 'pop ecx' for stack realignment..
3442 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3444 if (first_pop == -1 && *adj >= 0)
3447 if (do_update && *adj >= 0) {
3448 po->flags |= OPF_RMD;
3450 po->flags |= OPF_DONE | OPF_NOREGS;
3453 *adj += lmod_bytes(po, po->operand[0].lmod);
3454 if (*adj > adj_best)
3457 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3458 if (po->op == OP_JMP && po->btj == NULL) {
3464 if (po->op != OP_CALL)
3466 if (po->operand[0].type != OPT_LABEL)
3468 if (po->pp != NULL && po->pp->is_stdcall)
3470 if (adj_expect_unknown && first_pop >= 0)
3472 // assume it's another cdecl call
3476 if (first_pop >= 0) {
3477 // probably only 'pop ecx' was used
3485 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3487 struct parsed_op *po;
3491 ferr(ops, "%s: followed bad branch?\n", __func__);
3493 for (; i < opcnt; i++) {
3495 if (po->cc_scratch == magic)
3497 po->cc_scratch = magic;
3500 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3501 if (po->btj != NULL) {
3503 for (j = 0; j < po->btj->count; j++)
3504 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3508 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3509 if (!(po->flags & OPF_CJMP))
3512 if (po->flags & OPF_TAIL)
3517 static const struct parsed_proto *try_recover_pp(
3518 struct parsed_op *po, const struct parsed_opr *opr,
3519 int is_call, int *search_instead)
3521 const struct parsed_proto *pp = NULL;
3525 // maybe an arg of g_func?
3526 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3528 char ofs_reg[16] = { 0, };
3529 int arg, arg_s, arg_i;
3536 parse_stack_access(po, opr->name, ofs_reg,
3537 &offset, &stack_ra, NULL, 0);
3538 if (ofs_reg[0] != 0)
3539 ferr(po, "offset reg on arg access?\n");
3540 if (offset <= stack_ra) {
3541 // search who set the stack var instead
3542 if (search_instead != NULL)
3543 *search_instead = 1;
3547 arg_i = (offset - stack_ra - 4) / 4;
3548 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3549 if (g_func_pp->arg[arg].reg != NULL)
3555 if (arg == g_func_pp->argc)
3556 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3558 pp = g_func_pp->arg[arg].pp;
3561 ferr(po, "icall arg: arg%d has no pp\n", arg + 1);
3562 check_func_pp(po, pp, "icall arg");
3565 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3567 p = strchr(opr->name + 1, '[');
3568 memcpy(buf, opr->name, p - opr->name);
3569 buf[p - opr->name] = 0;
3570 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3572 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3573 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3576 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3579 check_func_pp(po, pp, "reg-fptr ref");
3585 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3586 int magic, const struct parsed_proto **pp_found, int *pp_i,
3589 const struct parsed_proto *pp = NULL;
3590 struct parsed_op *po;
3591 struct label_ref *lr;
3593 ops[i].cc_scratch = magic;
3596 if (g_labels[i] != NULL) {
3597 lr = &g_label_refs[i];
3598 for (; lr != NULL; lr = lr->next) {
3599 check_i(&ops[i], lr->i);
3600 scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3602 if (i > 0 && LAST_OP(i - 1))
3610 if (ops[i].cc_scratch == magic)
3612 ops[i].cc_scratch = magic;
3614 if (!(ops[i].flags & OPF_DATA))
3616 if (!is_opr_modified(opr, &ops[i]))
3618 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3619 // most probably trashed by some processing
3624 opr = &ops[i].operand[1];
3625 if (opr->type != OPT_REG)
3629 po = (i >= 0) ? &ops[i] : ops;
3632 // reached the top - can only be an arg-reg
3633 if (opr->type != OPT_REG || g_func_pp == NULL)
3636 for (i = 0; i < g_func_pp->argc; i++) {
3637 if (g_func_pp->arg[i].reg == NULL)
3639 if (IS(opr->name, g_func_pp->arg[i].reg))
3642 if (i == g_func_pp->argc)
3644 pp = g_func_pp->arg[i].pp;
3646 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3647 i + 1, g_func_pp->arg[i].reg);
3648 check_func_pp(po, pp, "icall reg-arg");
3651 pp = try_recover_pp(po, opr, 1, NULL);
3653 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3654 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3655 || (*pp_found)->is_stdcall != pp->is_stdcall
3656 //|| (*pp_found)->is_fptr != pp->is_fptr
3657 || (*pp_found)->argc != pp->argc
3658 || (*pp_found)->argc_reg != pp->argc_reg
3659 || (*pp_found)->argc_stack != pp->argc_stack)
3661 ferr(po, "icall: parsed_proto mismatch\n");
3671 static void add_label_ref(struct label_ref *lr, int op_i)
3673 struct label_ref *lr_new;
3680 lr_new = calloc(1, sizeof(*lr_new));
3682 lr_new->next = lr->next;
3686 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3688 struct parsed_op *po = &ops[i];
3689 struct parsed_data *pd;
3690 char label[NAMELEN], *p;
3693 p = strchr(po->operand[0].name, '[');
3697 len = p - po->operand[0].name;
3698 strncpy(label, po->operand[0].name, len);
3701 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3702 if (IS(g_func_pd[j].label, label)) {
3708 //ferr(po, "label '%s' not parsed?\n", label);
3711 if (pd->type != OPT_OFFSET)
3712 ferr(po, "label '%s' with non-offset data?\n", label);
3714 // find all labels, link
3715 for (j = 0; j < pd->count; j++) {
3716 for (l = 0; l < opcnt; l++) {
3717 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3718 add_label_ref(&g_label_refs[l], i);
3728 static void clear_labels(int count)
3732 for (i = 0; i < count; i++) {
3733 if (g_labels[i] != NULL) {
3740 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3745 for (i = 0; i < pp->argc; i++) {
3746 if (pp->arg[i].reg != NULL) {
3747 reg = char_array_i(regs_r32,
3748 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3750 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3751 pp->arg[i].reg, pp->name);
3752 regmask |= 1 << reg;
3759 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3764 if (pp->has_retreg) {
3765 for (i = 0; i < pp->argc; i++) {
3766 if (pp->arg[i].type.is_retreg) {
3767 reg = char_array_i(regs_r32,
3768 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3769 ferr_assert(ops, reg >= 0);
3770 regmask |= 1 << reg;
3775 if (strstr(pp->ret_type.name, "int64"))
3776 return regmask | (1 << xAX) | (1 << xDX);
3777 if (IS(pp->ret_type.name, "float")
3778 || IS(pp->ret_type.name, "double"))
3780 return regmask | mxST0;
3782 if (strcasecmp(pp->ret_type.name, "void") == 0)
3785 return regmask | mxAX;
3788 static int are_ops_same(struct parsed_op *po1, struct parsed_op *po2)
3790 return po1->op == po2->op && po1->operand_cnt == po2->operand_cnt
3791 && memcmp(po1->operand, po2->operand,
3792 sizeof(po1->operand[0]) * po1->operand_cnt) == 0;
3795 static void resolve_branches_parse_calls(int opcnt)
3797 static const struct {
3801 unsigned int regmask_src;
3802 unsigned int regmask_dst;
3804 { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3805 { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3806 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3807 // more precise? Wine gets away with just __ftol handler
3808 { "__ftol2", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3809 { "__CIpow", OPP_CIPOW, OPF_FPOP, mxST0|mxST1, mxST0 },
3811 const struct parsed_proto *pp_c;
3812 struct parsed_proto *pp;
3813 struct parsed_data *pd;
3814 struct parsed_op *po;
3815 const char *tmpname;
3820 for (i = 0; i < opcnt; i++)
3826 if (po->datap != NULL) {
3827 pp = calloc(1, sizeof(*pp));
3828 my_assert_not(pp, NULL);
3830 ret = parse_protostr(po->datap, pp);
3832 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3838 if (po->op == OP_CALL) {
3843 else if (po->operand[0].type == OPT_LABEL)
3845 tmpname = opr_name(po, 0);
3846 if (IS_START(tmpname, "loc_")) {
3848 ferr(po, "call to loc_*\n");
3849 // eliminate_seh() must take care of it
3852 if (IS(tmpname, "__alloca_probe"))
3854 if (IS(tmpname, "__SEH_prolog")) {
3855 ferr_assert(po, g_seh_found == 0);
3859 if (IS(tmpname, "__SEH_epilog"))
3862 // convert some calls to pseudo-ops
3863 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3864 if (!IS(tmpname, pseudo_ops[l].name))
3867 po->op = pseudo_ops[l].op;
3868 po->operand_cnt = 0;
3869 po->regmask_src = pseudo_ops[l].regmask_src;
3870 po->regmask_dst = pseudo_ops[l].regmask_dst;
3871 po->flags = pseudo_ops[l].flags;
3872 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3875 if (l < ARRAY_SIZE(pseudo_ops))
3878 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3879 if (!g_header_mode && pp_c == NULL)
3880 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3883 pp = proto_clone(pp_c);
3884 my_assert_not(pp, NULL);
3890 check_func_pp(po, pp, "fptr var call");
3891 if (pp->is_noreturn) {
3892 po->flags |= OPF_TAIL;
3893 po->flags &= ~OPF_ATAIL; // most likely...
3900 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3903 if (po->operand[0].type == OPT_REGMEM) {
3904 pd = try_resolve_jumptab(i, opcnt);
3912 for (l = 0; l < opcnt; l++) {
3913 if (g_labels[l] != NULL
3914 && IS(po->operand[0].name, g_labels[l]))
3916 if (l == i + 1 && po->op == OP_JMP) {
3917 // yet another alignment type..
3918 po->flags |= OPF_RMD|OPF_DONE;
3921 add_label_ref(&g_label_refs[l], i);
3927 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3930 if (po->operand[0].type == OPT_LABEL)
3934 ferr(po, "unhandled branch\n");
3938 po->flags |= OPF_TAIL;
3939 prev_op = i > 0 ? ops[i - 1].op : OP_UD2;
3940 if (prev_op == OP_POP)
3941 po->flags |= OPF_ATAIL;
3942 if (g_stack_fsz + g_bp_frame == 0 && prev_op != OP_PUSH
3943 && (g_func_pp == NULL || g_func_pp->argc_stack > 0))
3945 po->flags |= OPF_ATAIL;
3951 static int resolve_origin(int i, const struct parsed_opr *opr,
3952 int magic, int *op_i, int *is_caller);
3953 static void set_label(int i, const char *name);
3955 static void eliminate_seh_writes(int opcnt)
3957 const struct parsed_opr *opr;
3962 // assume all sf writes above g_seh_size to be seh related
3963 // (probably unsafe but oh well)
3964 for (i = 0; i < opcnt; i++) {
3965 if (ops[i].op != OP_MOV)
3967 opr = &ops[i].operand[0];
3968 if (opr->type != OPT_REGMEM)
3970 if (!is_stack_access(&ops[i], opr))
3974 parse_stack_access(&ops[i], opr->name, ofs_reg, &offset,
3976 if (offset < 0 && offset >= -g_seh_size)
3977 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3981 static void eliminate_seh_finally(int opcnt)
3983 const char *target_name = NULL;
3984 const char *return_name = NULL;
3985 int exits[MAX_EXITS];
3993 for (i = 0; i < opcnt; i++) {
3994 if (ops[i].op != OP_CALL)
3996 if (!IS_START(opr_name(&ops[i], 0), "loc_"))
3998 if (target_name != NULL)
3999 ferr(&ops[i], "multiple finally calls? (last was %s)\n",
4001 target_name = opr_name(&ops[i], 0);
4004 if (g_labels[i + 1] == NULL)
4005 set_label(i + 1, "seh_fin_done");
4006 return_name = g_labels[i + 1];
4014 // find finally code (bt_i is not set because it's call)
4015 for (i = 0; i < opcnt; i++) {
4016 if (g_labels[i] == NULL)
4018 if (!IS(g_labels[i], target_name))
4021 ferr_assert(&ops[i], target_i == -1);
4024 ferr_assert(&ops[0], target_i != -1);
4026 find_reachable_exits(target_i, opcnt, target_i + opcnt * 24,
4027 exits, &exit_count);
4028 ferr_assert(&ops[target_i], exit_count == 1);
4029 ferr_assert(&ops[target_i], ops[exits[0]].op == OP_RET);
4032 // convert to jumps, link
4033 ops[call_i].op = OP_JMP;
4034 ops[call_i].bt_i = target_i;
4035 add_label_ref(&g_label_refs[target_i], call_i);
4037 ops[tgend_i].op = OP_JMP;
4038 ops[tgend_i].flags &= ~OPF_TAIL;
4039 ops[tgend_i].flags |= OPF_JMP;
4040 ops[tgend_i].bt_i = return_i;
4041 ops[tgend_i].operand_cnt = 1;
4042 ops[tgend_i].operand[0].type = OPT_LABEL;
4043 snprintf(ops[tgend_i].operand[0].name, NAMELEN, "%s", return_name);
4044 add_label_ref(&g_label_refs[return_i], tgend_i);
4046 // rm seh finally entry code
4047 for (i = target_i - 1; i >= 0; i--) {
4048 if (g_labels[i] != NULL && g_label_refs[i].i != -1)
4050 if (ops[i].flags & OPF_CJMP)
4052 if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4055 for (i = target_i - 1; i >= 0; i--) {
4056 if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4058 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4062 static void eliminate_seh(int opcnt)
4066 for (i = 0; i < opcnt; i++) {
4067 if (ops[i].op != OP_MOV)
4069 if (ops[i].operand[0].segment != SEG_FS)
4071 if (!IS(opr_name(&ops[i], 0), "0"))
4074 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4075 if (ops[i].operand[1].reg == xSP) {
4076 for (j = i - 1; j >= 0; j--) {
4077 if (ops[j].op != OP_PUSH)
4079 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4081 if (ops[j].operand[0].val == ~0)
4083 if (ops[j].operand[0].type == OPT_REG) {
4085 ret = resolve_origin(j, &ops[j].operand[0],
4086 j + opcnt * 22, &k, NULL);
4088 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4092 ferr(ops, "missing seh terminator\n");
4096 ret = resolve_origin(i, &ops[i].operand[1],
4097 i + opcnt * 23, &k, NULL);
4099 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4103 eliminate_seh_writes(opcnt);
4104 eliminate_seh_finally(opcnt);
4107 static void eliminate_seh_calls(int opcnt)
4109 int epilog_found = 0;
4116 ferr_assert(&ops[i], ops[i].op == OP_PUSH
4117 && ops[i].operand[0].type == OPT_CONST);
4118 g_stack_fsz = g_seh_size + ops[i].operand[0].val;
4119 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4122 ferr_assert(&ops[i], ops[i].op == OP_PUSH
4123 && ops[i].operand[0].type == OPT_OFFSET);
4124 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4127 ferr_assert(&ops[i], ops[i].op == OP_CALL
4128 && IS(opr_name(&ops[i], 0), "__SEH_prolog"));
4129 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4131 for (i++; i < opcnt; i++) {
4132 if (ops[i].op != OP_CALL)
4134 if (!IS(opr_name(&ops[i], 0), "__SEH_epilog"))
4137 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4140 ferr_assert(ops, epilog_found);
4142 eliminate_seh_writes(opcnt);
4143 eliminate_seh_finally(opcnt);
4146 static int scan_prologue(int i, int opcnt, int *ecx_push, int *esp_sub)
4150 for (; i < opcnt; i++)
4151 if (!(ops[i].flags & OPF_DONE))
4154 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4155 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4161 for (; i < opcnt; i++) {
4162 if (i > 0 && g_labels[i] != NULL)
4164 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
4166 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
4167 && ops[i].operand[1].type == OPT_CONST)
4169 g_stack_fsz += opr_const(&ops[i], 1);
4170 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4175 if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
4176 && ops[i].operand[1].type == OPT_CONST)
4178 for (j = i + 1; j < opcnt; j++)
4179 if (!(ops[j].flags & OPF_DONE))
4181 if (ops[j].op == OP_CALL
4182 && IS(opr_name(&ops[j], 0), "__alloca_probe"))
4184 g_stack_fsz += opr_const(&ops[i], 1);
4185 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4186 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4197 static void scan_prologue_epilogue(int opcnt, int *stack_align)
4199 int ecx_push = 0, esp_sub = 0, pusha = 0;
4200 int sandard_epilogue;
4204 if (g_seh_found == 2) {
4205 eliminate_seh_calls(opcnt);
4209 eliminate_seh(opcnt);
4210 // ida treats seh as part of sf
4211 g_stack_fsz = g_seh_size;
4215 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
4216 && ops[1].op == OP_MOV
4217 && IS(opr_name(&ops[1], 0), "ebp")
4218 && IS(opr_name(&ops[1], 1), "esp"))
4221 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4222 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4224 for (i = 2; i < opcnt; i++)
4225 if (!(ops[i].flags & OPF_DONE))
4228 if (ops[i].op == OP_PUSHA) {
4229 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4234 if (ops[i].op == OP_AND && ops[i].operand[0].reg == xSP
4235 && ops[i].operand[1].type == OPT_CONST)
4237 l = ops[i].operand[1].val;
4239 if (j == -1 || (l >> j) != -1)
4240 ferr(&ops[i], "unhandled esp align: %x\n", l);
4241 if (stack_align != NULL)
4242 *stack_align = 1 << j;
4243 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4247 i = scan_prologue(i, opcnt, &ecx_push, &esp_sub);
4251 for (; i < opcnt; i++)
4252 if (ops[i].flags & OPF_TAIL)
4255 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4256 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4262 sandard_epilogue = 0;
4263 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
4265 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4266 // the standard epilogue is sometimes even used without a sf
4267 if (ops[j - 1].op == OP_MOV
4268 && IS(opr_name(&ops[j - 1], 0), "esp")
4269 && IS(opr_name(&ops[j - 1], 1), "ebp"))
4270 sandard_epilogue = 1;
4272 else if (ops[j].op == OP_LEAVE)
4274 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4275 sandard_epilogue = 1;
4277 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
4278 && ops[i].pp->is_noreturn)
4280 // on noreturn, msvc sometimes cleans stack, sometimes not
4285 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4286 ferr(&ops[j], "'pop ebp' expected\n");
4288 if (g_stack_fsz != 0 || sandard_epilogue) {
4289 if (ops[j].op == OP_LEAVE)
4291 else if (sandard_epilogue) // mov esp, ebp
4293 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4296 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4298 ferr(&ops[j], "esp restore expected\n");
4301 if (ecx_push && j >= 0 && ops[j].op == OP_POP
4302 && IS(opr_name(&ops[j], 0), "ecx"))
4304 ferr(&ops[j], "unexpected ecx pop\n");
4309 if (ops[j].op == OP_POPA)
4310 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4312 ferr(&ops[j], "popa expected\n");
4317 } while (i < opcnt);
4320 ferr(ops, "missing ebp epilogue\n");
4325 i = scan_prologue(0, opcnt, &ecx_push, &esp_sub);
4327 if (ecx_push && !esp_sub) {
4328 // could actually be args for a call..
4329 for (; i < opcnt; i++)
4330 if (ops[i].op != OP_PUSH)
4333 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
4334 const struct parsed_proto *pp;
4335 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
4336 j = pp ? pp->argc_stack : 0;
4337 while (i > 0 && j > 0) {
4339 if (ops[i].op == OP_PUSH) {
4340 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
4345 ferr(&ops[i], "unhandled prologue\n");
4349 g_stack_fsz = g_seh_size;
4350 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4351 if (!(ops[i].flags & OPF_RMD))
4361 if (ecx_push || esp_sub)
4366 for (; i < opcnt; i++)
4367 if (ops[i].flags & OPF_TAIL)
4371 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4372 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4377 else if (i < opcnt && (ops[i].flags & OPF_ATAIL)) {
4378 // skip arg updates for arg-reuse tailcall
4379 for (; j >= 0; j--) {
4380 if (ops[j].op != OP_MOV)
4382 if (ops[j].operand[0].type != OPT_REGMEM)
4384 if (strstr(ops[j].operand[0].name, "arg_") == NULL)
4389 if (ecx_push > 0 && !esp_sub) {
4390 for (l = 0; l < ecx_push && j >= 0; l++) {
4391 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
4393 else if (ops[j].op == OP_ADD
4394 && IS(opr_name(&ops[j], 0), "esp")
4395 && ops[j].operand[1].type == OPT_CONST)
4398 l += ops[j].operand[1].val / 4 - 1;
4403 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4406 if (l != ecx_push) {
4407 if (i < opcnt && ops[i].op == OP_CALL
4408 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4410 // noreturn tailcall with no epilogue
4415 ferr(&ops[j], "epilogue scan failed\n");
4422 if (ops[j].op != OP_ADD
4423 || !IS(opr_name(&ops[j], 0), "esp")
4424 || ops[j].operand[1].type != OPT_CONST)
4426 if (i < opcnt && ops[i].op == OP_CALL
4427 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4429 // noreturn tailcall with no epilogue
4434 ferr(&ops[j], "'add esp' expected\n");
4437 if (ops[j].operand[1].val < g_stack_fsz)
4438 ferr(&ops[j], "esp adj is too low (need %d)\n", g_stack_fsz);
4440 ops[j].operand[1].val -= g_stack_fsz; // for stack arg scanner
4441 if (ops[j].operand[1].val == 0)
4442 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4447 } while (i < opcnt);
4450 ferr(ops, "missing esp epilogue\n");
4454 // find an instruction that changed opr before i op
4455 // *op_i must be set to -1 by the caller
4456 // *is_caller is set to 1 if one source is determined to be g_func arg
4457 // returns 1 if found, *op_i is then set to origin
4458 // returns -1 if multiple origins are found
4459 static int resolve_origin(int i, const struct parsed_opr *opr,
4460 int magic, int *op_i, int *is_caller)
4462 struct label_ref *lr;
4466 if (g_labels[i] != NULL) {
4467 lr = &g_label_refs[i];
4468 for (; lr != NULL; lr = lr->next) {
4469 check_i(&ops[i], lr->i);
4470 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4472 if (i > 0 && LAST_OP(i - 1))
4478 if (is_caller != NULL)
4483 if (ops[i].cc_scratch == magic)
4485 ops[i].cc_scratch = magic;
4487 if (!(ops[i].flags & OPF_DATA))
4489 if (!is_opr_modified(opr, &ops[i]))
4493 if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4504 // find an instruction that previously referenced opr
4505 // if multiple results are found - fail
4506 // *op_i must be set to -1 by the caller
4507 // returns 1 if found, *op_i is then set to referencer insn
4508 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4509 int magic, int *op_i)
4511 struct label_ref *lr;
4515 if (g_labels[i] != NULL) {
4516 lr = &g_label_refs[i];
4517 for (; lr != NULL; lr = lr->next) {
4518 check_i(&ops[i], lr->i);
4519 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4521 if (i > 0 && LAST_OP(i - 1))
4529 if (ops[i].cc_scratch == magic)
4531 ops[i].cc_scratch = magic;
4533 if (!is_opr_referenced(opr, &ops[i]))
4544 // adjust datap of all reachable 'op' insns when moving back
4545 // returns 1 if at least 1 op was found
4546 // returns -1 if path without an op was found
4547 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4549 struct label_ref *lr;
4552 if (ops[i].cc_scratch == magic)
4554 ops[i].cc_scratch = magic;
4557 if (g_labels[i] != NULL) {
4558 lr = &g_label_refs[i];
4559 for (; lr != NULL; lr = lr->next) {
4560 check_i(&ops[i], lr->i);
4561 ret |= adjust_prev_op(lr->i, op, magic, datap);
4563 if (i > 0 && LAST_OP(i - 1))
4571 if (ops[i].cc_scratch == magic)
4573 ops[i].cc_scratch = magic;
4575 if (ops[i].op != op)
4578 ops[i].datap = datap;
4583 // find next instruction that reads opr
4584 // *op_i must be set to -1 by the caller
4585 // on return, *op_i is set to first referencer insn
4586 // returns 1 if exactly 1 referencer is found
4587 static int find_next_read(int i, int opcnt,
4588 const struct parsed_opr *opr, int magic, int *op_i)
4590 struct parsed_op *po;
4593 for (; i < opcnt; i++)
4595 if (ops[i].cc_scratch == magic)
4597 ops[i].cc_scratch = magic;
4600 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4601 if (po->btj != NULL) {
4603 for (j = 0; j < po->btj->count; j++) {
4604 check_i(po, po->btj->d[j].bt_i);
4605 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4611 if (po->flags & OPF_RMD)
4613 check_i(po, po->bt_i);
4614 if (po->flags & OPF_CJMP) {
4615 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4624 if (!is_opr_read(opr, po)) {
4626 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4627 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4629 full_opr = po->operand[0].lmod >= opr->lmod;
4631 if (is_opr_modified(opr, po) && full_opr) {
4635 if (po->flags & OPF_TAIL)
4650 static int find_next_read_reg(int i, int opcnt, int reg,
4651 enum opr_lenmod lmod, int magic, int *op_i)
4653 struct parsed_opr opr = OPR_INIT(OPT_REG, lmod, reg);
4656 return find_next_read(i, opcnt, &opr, magic, op_i);
4659 // find next instruction that reads opr
4660 // *op_i must be set to -1 by the caller
4661 // on return, *op_i is set to first flag user insn
4662 // returns 1 if exactly 1 flag user is found
4663 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4665 struct parsed_op *po;
4668 for (; i < opcnt; i++)
4670 if (ops[i].cc_scratch == magic)
4672 ops[i].cc_scratch = magic;
4675 if (po->op == OP_CALL)
4677 if (po->flags & OPF_JMP) {
4678 if (po->btj != NULL) {
4680 for (j = 0; j < po->btj->count; j++) {
4681 check_i(po, po->btj->d[j].bt_i);
4682 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4688 if (po->flags & OPF_RMD)
4690 check_i(po, po->bt_i);
4691 if (po->flags & OPF_CJMP)
4698 if (!(po->flags & OPF_CC)) {
4699 if (po->flags & OPF_FLAGS)
4702 if (po->flags & OPF_TAIL)
4718 static int try_resolve_const(int i, const struct parsed_opr *opr,
4719 int magic, unsigned int *val)
4724 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4727 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4730 *val = ops[i].operand[1].val;
4737 static int resolve_used_bits(int i, int opcnt, int reg,
4738 int *mask, int *is_z_check)
4740 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4744 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4748 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4750 fnote(&ops[j], "(first read)\n");
4751 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4754 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4755 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4757 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4758 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4760 *mask = ops[j].operand[1].val;
4761 if (ops[j].operand[0].lmod == OPLM_BYTE
4762 && ops[j].operand[0].name[1] == 'h')
4766 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4769 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4771 *is_z_check = ops[k].pfo == PFO_Z;
4776 static const struct parsed_proto *resolve_deref(int i, int magic,
4777 struct parsed_opr *opr, int level)
4779 struct parsed_opr opr_s = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
4780 const struct parsed_proto *pp = NULL;
4781 int from_caller = 0;
4790 ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4791 if (ret != 2 || len != strlen(opr->name)) {
4792 ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4793 if (ret != 1 || len != strlen(opr->name))
4797 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4802 ret = resolve_origin(i, &opr_s, i + magic, &j, NULL);
4806 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4807 && strlen(ops[j].operand[1].name) == 3
4808 && ops[j].operand[0].lmod == OPLM_DWORD
4809 && ops[j].pp == NULL // no hint
4812 // allow one simple dereference (com/directx)
4813 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4814 ops[j].operand[1].name);
4818 ret = resolve_origin(j, &opr_s, j + magic, &k, NULL);
4823 if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
4826 if (ops[j].pp != NULL) {
4830 else if (ops[j].operand[1].type == OPT_REGMEM) {
4831 pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
4833 // maybe structure ptr in structure
4834 pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
4837 else if (ops[j].operand[1].type == OPT_LABEL)
4838 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4839 else if (ops[j].operand[1].type == OPT_REG) {
4842 ret = resolve_origin(j, &ops[j].operand[1], i + magic,
4844 if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
4845 for (k = 0; k < g_func_pp->argc; k++) {
4846 if (g_func_pp->arg[k].reg == NULL)
4848 if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
4849 pp = g_func_pp->arg[k].pp;
4858 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4860 ferr(&ops[j], "expected struct, got '%s %s'\n",
4861 pp->type.name, pp->name);
4865 return proto_lookup_struct(g_fhdr, pp->type.name, offset);
4868 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4869 int *pp_i, int *multi_src)
4871 const struct parsed_proto *pp = NULL;
4872 int search_advice = 0;
4877 switch (ops[i].operand[0].type) {
4879 // try to resolve struct member calls
4880 pp = resolve_deref(i, i + opcnt * 19, &ops[i].operand[0], 0);
4886 pp = try_recover_pp(&ops[i], &ops[i].operand[0],
4892 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4900 static struct parsed_proto *process_call_early(int i, int opcnt,
4903 struct parsed_op *po = &ops[i];
4904 struct parsed_proto *pp;
4910 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4914 // look for and make use of esp adjust
4916 if (!pp->is_stdcall && pp->argc_stack > 0)
4917 ret = scan_for_esp_adjust(i + 1, opcnt,
4918 pp->argc_stack * 4, &adj, &multipath, 0);
4920 if (pp->argc_stack > adj / 4)
4924 if (ops[ret].op == OP_POP) {
4925 for (j = 1; j < adj / 4; j++) {
4926 if (ops[ret + j].op != OP_POP
4927 || ops[ret + j].operand[0].reg != xCX)
4939 static struct parsed_proto *process_call(int i, int opcnt)
4941 struct parsed_op *po = &ops[i];
4942 const struct parsed_proto *pp_c;
4943 struct parsed_proto *pp;
4944 const char *tmpname;
4945 int call_i = -1, ref_i = -1;
4946 int adj = 0, multipath = 0;
4949 tmpname = opr_name(po, 0);
4954 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4956 if (!pp_c->is_func && !pp_c->is_fptr)
4957 ferr(po, "call to non-func: %s\n", pp_c->name);
4958 pp = proto_clone(pp_c);
4959 my_assert_not(pp, NULL);
4961 // not resolved just to single func
4964 switch (po->operand[0].type) {
4966 // we resolved this call and no longer need the register
4967 po->regmask_src &= ~(1 << po->operand[0].reg);
4969 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4970 && ops[call_i].operand[1].type == OPT_LABEL)
4972 // no other source users?
4973 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4975 if (ret == 1 && call_i == ref_i) {
4976 // and nothing uses it after us?
4978 find_next_read(i + 1, opcnt, &po->operand[0],
4979 i + opcnt * 11, &ref_i);
4981 // then also don't need the source mov
4982 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4994 pp = calloc(1, sizeof(*pp));
4995 my_assert_not(pp, NULL);
4998 ret = scan_for_esp_adjust(i + 1, opcnt,
4999 -1, &adj, &multipath, 0);
5000 if (ret < 0 || adj < 0) {
5001 if (!g_allow_regfunc)
5002 ferr(po, "non-__cdecl indirect call unhandled yet\n");
5003 pp->is_unresolved = 1;
5007 if (adj > ARRAY_SIZE(pp->arg))
5008 ferr(po, "esp adjust too large: %d\n", adj);
5009 pp->ret_type.name = strdup("int");
5010 pp->argc = pp->argc_stack = adj;
5011 for (arg = 0; arg < pp->argc; arg++)
5012 pp->arg[arg].type.name = strdup("int");
5017 // look for and make use of esp adjust
5020 if (!pp->is_stdcall && pp->argc_stack > 0) {
5021 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
5022 ret = scan_for_esp_adjust(i + 1, opcnt,
5023 adj_expect, &adj, &multipath, 0);
5026 if (pp->is_vararg) {
5027 if (adj / 4 < pp->argc_stack) {
5028 fnote(po, "(this call)\n");
5029 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
5030 adj, pp->argc_stack * 4);
5032 // modify pp to make it have varargs as normal args
5034 pp->argc += adj / 4 - pp->argc_stack;
5035 for (; arg < pp->argc; arg++) {
5036 pp->arg[arg].type.name = strdup("int");
5039 if (pp->argc > ARRAY_SIZE(pp->arg))
5040 ferr(po, "too many args for '%s'\n", tmpname);
5042 if (pp->argc_stack > adj / 4) {
5043 if (pp->is_noreturn)
5044 // assume no stack adjust was emited
5046 fnote(po, "(this call)\n");
5047 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
5048 tmpname, pp->argc_stack * 4, adj);
5051 scan_for_esp_adjust(i + 1, opcnt,
5052 pp->argc_stack * 4, &adj, &multipath, 1);
5054 else if (pp->is_vararg)
5055 ferr(po, "missing esp_adjust for vararg func '%s'\n",
5062 static void mark_float_arg(struct parsed_op *po,
5063 struct parsed_proto *pp, int arg, int *regmask_ffca)
5066 po->p_argnum = arg + 1;
5067 ferr_assert(po, pp->arg[arg].datap == NULL);
5068 pp->arg[arg].datap = po;
5069 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
5070 if (regmask_ffca != NULL)
5071 *regmask_ffca |= 1 << arg;
5074 static int check_for_stp(int i, int i_to)
5076 struct parsed_op *po;
5078 for (; i < i_to; i++) {
5080 if (po->op == OP_FST)
5082 if (g_labels[i] != NULL || (po->flags & OPF_JMP))
5084 if (po->op == OP_CALL || po->op == OP_PUSH || po->op == OP_POP)
5086 if (po->op == OP_ADD && po->operand[0].reg == xSP)
5093 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
5096 struct parsed_op *po;
5102 for (base_arg = 0; base_arg < pp->argc; base_arg++)
5103 if (pp->arg[base_arg].reg == NULL)
5106 for (j = i; j > 0; )
5108 ferr_assert(&ops[j], g_labels[j] == NULL);
5112 ferr_assert(po, po->op != OP_PUSH);
5113 if (po->op == OP_FST)
5115 if (po->operand[0].type != OPT_REGMEM)
5117 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
5120 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3)) {
5121 //ferr(po, "offset %d, %d args\n", offset, pp->argc_stack);
5125 arg = base_arg + offset / 4;
5126 mark_float_arg(po, pp, arg, regmask_ffca);
5128 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5129 && po->operand[1].type == OPT_CONST)
5131 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5136 for (arg = base_arg; arg < pp->argc; arg++) {
5137 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
5138 po = pp->arg[arg].datap;
5140 ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
5141 if (po->operand[0].lmod == OPLM_QWORD)
5148 static int collect_call_args_early(int i, struct parsed_proto *pp,
5149 int *regmask, int *regmask_ffca)
5151 struct parsed_op *po;
5156 for (arg = 0; arg < pp->argc; arg++)
5157 if (pp->arg[arg].reg == NULL)
5160 // first see if it can be easily done
5161 for (j = i; j > 0 && arg < pp->argc; )
5163 if (g_labels[j] != NULL)
5168 if (po->op == OP_CALL)
5170 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
5172 else if (po->op == OP_POP)
5174 else if (po->flags & OPF_CJMP)
5176 else if (po->op == OP_PUSH) {
5177 if (po->flags & (OPF_FARG|OPF_FARGNR))
5179 if (!g_header_mode) {
5180 ret = scan_for_mod(po, j + 1, i, 1);
5185 if (pp->arg[arg].type.is_va_list)
5189 for (arg++; arg < pp->argc; arg++)
5190 if (pp->arg[arg].reg == NULL)
5193 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5194 && po->operand[1].type == OPT_CONST)
5196 if (po->flags & (OPF_RMD|OPF_DONE))
5198 if (po->operand[1].val != pp->argc_stack * 4)
5199 ferr(po, "unexpected esp adjust: %d\n",
5200 po->operand[1].val * 4);
5201 ferr_assert(po, pp->argc - arg == pp->argc_stack);
5202 return collect_call_args_no_push(i, pp, regmask_ffca);
5210 for (arg = 0; arg < pp->argc; arg++)
5211 if (pp->arg[arg].reg == NULL)
5214 for (j = i; j > 0 && arg < pp->argc; )
5218 if (ops[j].op == OP_PUSH)
5220 ops[j].p_argnext = -1;
5221 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
5223 k = check_for_stp(j + 1, i);
5225 // push ecx; fstp dword ptr [esp]
5226 ret = parse_stack_esp_offset(&ops[k],
5227 ops[k].operand[0].name, &offset);
5228 if (ret == 0 && offset == 0) {
5229 if (!pp->arg[arg].type.is_float)
5230 ferr(&ops[i], "arg %d should be float\n", arg + 1);
5231 mark_float_arg(&ops[k], pp, arg, regmask_ffca);
5235 if (pp->arg[arg].datap == NULL) {
5236 pp->arg[arg].datap = &ops[j];
5237 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
5238 *regmask |= 1 << ops[j].operand[0].reg;
5241 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5242 ops[j].flags &= ~OPF_RSAVE;
5245 for (arg++; arg < pp->argc; arg++)
5246 if (pp->arg[arg].reg == NULL)
5254 static int sync_argnum(struct parsed_op *po, int argnum)
5256 struct parsed_op *po_tmp;
5258 // see if other branches don't have higher argnum
5259 for (po_tmp = po; po_tmp != NULL; ) {
5260 if (argnum < po_tmp->p_argnum)
5261 argnum = po_tmp->p_argnum;
5262 // note: p_argnext is active on current collect_call_args only
5263 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5266 // make all argnums consistent
5267 for (po_tmp = po; po_tmp != NULL; ) {
5268 if (po_tmp->p_argnum != 0)
5269 po_tmp->p_argnum = argnum;
5270 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5276 static int collect_call_args_r(struct parsed_op *po, int i,
5277 struct parsed_proto *pp, int *regmask, int *arg_grp,
5278 int arg, int argnum, int magic, int need_op_saving, int may_reuse)
5280 struct parsed_proto *pp_tmp;
5281 struct parsed_op *po_tmp;
5282 struct label_ref *lr;
5283 int need_to_save_current;
5284 int arg_grp_current = 0;
5285 int save_args_seen = 0;
5292 ferr(po, "dead label encountered\n");
5296 for (; arg < pp->argc; arg++, argnum++)
5297 if (pp->arg[arg].reg == NULL)
5299 magic = (magic & 0xffffff) | (arg << 24);
5301 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
5303 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
5304 if (ops[j].cc_scratch != magic) {
5305 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
5309 // ok: have already been here
5312 ops[j].cc_scratch = magic;
5314 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
5315 lr = &g_label_refs[j];
5316 if (lr->next != NULL)
5318 for (; lr->next; lr = lr->next) {
5319 check_i(&ops[j], lr->i);
5320 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5322 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5323 arg, argnum, magic, need_op_saving, may_reuse);
5328 check_i(&ops[j], lr->i);
5329 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5331 if (j > 0 && LAST_OP(j - 1)) {
5332 // follow last branch in reverse
5337 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5338 arg, argnum, magic, need_op_saving, may_reuse);
5344 if (ops[j].op == OP_CALL)
5346 if (pp->is_unresolved)
5351 ferr(po, "arg collect %d/%d hit unparsed call '%s'\n",
5352 arg, pp->argc, ops[j].operand[0].name);
5353 if (may_reuse && pp_tmp->argc_stack > 0)
5354 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
5355 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
5357 // esp adjust of 0 means we collected it before
5358 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
5359 && (ops[j].operand[1].type != OPT_CONST
5360 || ops[j].operand[1].val != 0))
5362 if (pp->is_unresolved)
5365 fnote(po, "(this call)\n");
5366 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
5367 arg, pp->argc, ops[j].operand[1].val);
5369 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
5371 if (pp->is_unresolved)
5374 fnote(po, "(this call)\n");
5375 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
5377 else if (ops[j].flags & OPF_CJMP)
5379 if (pp->is_unresolved)
5384 else if (ops[j].op == OP_PUSH
5385 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
5387 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
5390 ops[j].p_argnext = -1;
5391 po_tmp = pp->arg[arg].datap;
5393 ops[j].p_argnext = po_tmp - ops;
5394 pp->arg[arg].datap = &ops[j];
5396 argnum = sync_argnum(&ops[j], argnum);
5398 need_to_save_current = 0;
5400 if (ops[j].operand[0].type == OPT_REG)
5401 reg = ops[j].operand[0].reg;
5403 if (!need_op_saving) {
5404 ret = scan_for_mod(&ops[j], j + 1, i, 1);
5405 need_to_save_current = (ret >= 0);
5407 if (need_op_saving || need_to_save_current) {
5408 // mark this arg as one that needs operand saving
5409 pp->arg[arg].is_saved = 1;
5411 if (save_args_seen & (1 << (argnum - 1))) {
5414 if (arg_grp_current >= MAX_ARG_GRP)
5415 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
5419 else if (ops[j].p_argnum == 0)
5420 ops[j].flags |= OPF_RMD;
5422 // some PUSHes are reused by different calls on other branches,
5423 // but that can't happen if we didn't branch, so they
5424 // can be removed from future searches (handles nested calls)
5426 ops[j].flags |= OPF_FARGNR;
5428 ops[j].flags |= OPF_FARG;
5429 ops[j].flags &= ~OPF_RSAVE;
5431 // check for __VALIST
5432 if (!pp->is_unresolved && g_func_pp != NULL
5433 && pp->arg[arg].type.is_va_list)
5436 ret = resolve_origin(j, &ops[j].operand[0],
5437 magic + 1, &k, NULL);
5438 if (ret == 1 && k >= 0)
5440 if (ops[k].op == OP_LEA) {
5441 if (!g_func_pp->is_vararg)
5442 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
5445 snprintf(buf, sizeof(buf), "arg_%X",
5446 g_func_pp->argc_stack * 4);
5447 if (strstr(ops[k].operand[1].name, buf)
5448 || strstr(ops[k].operand[1].name, "arglist"))
5450 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
5451 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
5452 pp->arg[arg].is_saved = 0;
5456 ferr(&ops[k], "va_list arg detection failed\n");
5458 // check for va_list from g_func_pp arg too
5459 else if (ops[k].op == OP_MOV
5460 && is_stack_access(&ops[k], &ops[k].operand[1]))
5462 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5463 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5465 ops[k].flags |= OPF_RMD | OPF_DONE;
5466 ops[j].flags |= OPF_RMD;
5467 ops[j].p_argpass = ret + 1;
5468 pp->arg[arg].is_saved = 0;
5475 if (pp->arg[arg].is_saved) {
5476 ops[j].flags &= ~OPF_RMD;
5477 ops[j].p_argnum = argnum;
5480 // tracking reg usage
5482 *regmask |= 1 << reg;
5486 if (!pp->is_unresolved) {
5488 for (; arg < pp->argc; arg++, argnum++)
5489 if (pp->arg[arg].reg == NULL)
5492 magic = (magic & 0xffffff) | (arg << 24);
5495 if (ops[j].p_arggrp > arg_grp_current) {
5497 arg_grp_current = ops[j].p_arggrp;
5499 if (ops[j].p_argnum > 0)
5500 save_args_seen |= 1 << (ops[j].p_argnum - 1);
5503 if (arg < pp->argc) {
5504 ferr(po, "arg collect failed for '%s': %d/%d\n",
5505 pp->name, arg, pp->argc);
5509 if (arg_grp_current > *arg_grp)
5510 *arg_grp = arg_grp_current;
5515 static int collect_call_args(struct parsed_op *po, int i,
5516 struct parsed_proto *pp, int *regmask, int magic)
5518 // arg group is for cases when pushes for
5519 // multiple funcs are going on
5520 struct parsed_op *po_tmp;
5525 ret = collect_call_args_r(po, i, pp, regmask, &arg_grp,
5531 // propagate arg_grp
5532 for (a = 0; a < pp->argc; a++) {
5533 if (pp->arg[a].reg != NULL)
5536 po_tmp = pp->arg[a].datap;
5537 while (po_tmp != NULL) {
5538 po_tmp->p_arggrp = arg_grp;
5539 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5544 if (pp->is_unresolved) {
5546 pp->argc_stack += ret;
5547 for (a = 0; a < pp->argc; a++)
5548 if (pp->arg[a].type.name == NULL)
5549 pp->arg[a].type.name = strdup("int");
5555 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5556 int regmask_now, int *regmask,
5557 int regmask_save_now, int *regmask_save,
5558 int *regmask_init, int regmask_arg)
5560 struct parsed_op *po;
5568 for (; i < opcnt; i++)
5571 if (cbits[i >> 3] & (1 << (i & 7)))
5573 cbits[i >> 3] |= (1 << (i & 7));
5575 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5576 if (po->flags & (OPF_RMD|OPF_DONE))
5578 if (po->btj != NULL) {
5579 for (j = 0; j < po->btj->count; j++) {
5580 check_i(po, po->btj->d[j].bt_i);
5581 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5582 regmask_now, regmask, regmask_save_now, regmask_save,
5583 regmask_init, regmask_arg);
5588 check_i(po, po->bt_i);
5589 if (po->flags & OPF_CJMP)
5590 reg_use_pass(po->bt_i, opcnt, cbits,
5591 regmask_now, regmask, regmask_save_now, regmask_save,
5592 regmask_init, regmask_arg);
5598 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5599 && !g_func_pp->is_userstack
5600 && po->operand[0].type == OPT_REG)
5602 reg = po->operand[0].reg;
5603 ferr_assert(po, reg >= 0);
5606 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5607 if (regmask_now & (1 << reg)) {
5608 already_saved = regmask_save_now & (1 << reg);
5609 flags_set = OPF_RSAVE | OPF_DONE;
5612 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, 0);
5614 scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5615 reg, 0, 0, flags_set);
5618 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5620 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5625 ferr_assert(po, !already_saved);
5626 po->flags |= flags_set;
5628 if (regmask_now & (1 << reg)) {
5629 regmask_save_now |= (1 << reg);
5630 *regmask_save |= regmask_save_now;
5635 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5636 reg = po->operand[0].reg;
5637 ferr_assert(po, reg >= 0);
5639 if (regmask_save_now & (1 << reg))
5640 regmask_save_now &= ~(1 << reg);
5642 regmask_now &= ~(1 << reg);
5645 else if (po->op == OP_CALL) {
5646 if ((po->regmask_dst & (1 << xAX))
5647 && !(po->regmask_dst & (1 << xDX)))
5649 if (po->flags & OPF_TAIL)
5650 // don't need eax, will do "return f();" or "f(); return;"
5651 po->regmask_dst &= ~(1 << xAX);
5653 find_next_read_reg(i + 1, opcnt, xAX, OPLM_DWORD,
5654 i + opcnt * 17, &j);
5657 po->regmask_dst &= ~(1 << xAX);
5661 // not "full stack" mode and have something in stack
5662 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5663 ferr(po, "float stack is not empty on func call\n");
5666 if (po->flags & OPF_NOREGS)
5669 // if incomplete register is used, clear it on init to avoid
5670 // later use of uninitialized upper part in some situations
5671 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5672 && po->operand[0].lmod != OPLM_DWORD)
5674 reg = po->operand[0].reg;
5675 ferr_assert(po, reg >= 0);
5677 if (!(regmask_now & (1 << reg)))
5678 *regmask_init |= 1 << reg;
5681 regmask_op = po->regmask_src | po->regmask_dst;
5683 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5684 regmask_new &= ~(1 << xSP);
5685 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5686 regmask_new &= ~(1 << xBP);
5688 if (regmask_new != 0)
5689 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5691 if (regmask_op & (1 << xBP)) {
5692 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5693 if (po->regmask_dst & (1 << xBP))
5694 // compiler decided to drop bp frame and use ebp as scratch
5695 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5697 regmask_op &= ~(1 << xBP);
5701 if (po->flags & OPF_FPUSH) {
5702 if (regmask_now & mxST1)
5703 regmask_now |= mxSTa; // switch to "full stack" mode
5704 if (regmask_now & mxSTa)
5705 po->flags |= OPF_FSHIFT;
5706 if (!(regmask_now & mxST7_2)) {
5708 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5712 regmask_now |= regmask_op;
5713 *regmask |= regmask_now;
5716 if (po->flags & OPF_FPOPP) {
5717 if ((regmask_now & mxSTa) == 0)
5718 ferr(po, "float pop on empty stack?\n");
5719 if (regmask_now & mxST7_2)
5720 po->flags |= OPF_FSHIFT;
5721 if (!(regmask_now & mxST7_2))
5722 regmask_now &= ~mxST1_0;
5724 else if (po->flags & OPF_FPOP) {
5725 if ((regmask_now & mxSTa) == 0)
5726 ferr(po, "float pop on empty stack?\n");
5727 if (regmask_now & (mxST7_2 | mxST1))
5728 po->flags |= OPF_FSHIFT;
5729 if (!(regmask_now & mxST7_2)) {
5731 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5735 if (po->flags & OPF_TAIL) {
5736 if (!(regmask_now & mxST7_2)) {
5737 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5738 if (!(regmask_now & mxST0))
5739 ferr(po, "no st0 on float return, mask: %x\n",
5742 else if (regmask_now & mxST1_0)
5743 ferr(po, "float regs on tail: %x\n", regmask_now);
5746 // there is support for "conditional tailcall", sort of
5747 if (!(po->flags & OPF_CC))
5753 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5757 for (i = 0; i < pp->argc; i++)
5758 if (pp->arg[i].reg == NULL)
5762 memmove(&pp->arg[i + 1], &pp->arg[i],
5763 sizeof(pp->arg[0]) * pp->argc_stack);
5764 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5765 pp->arg[i].reg = strdup(reg);
5766 pp->arg[i].type.name = strdup("int");
5771 static void output_std_flag_z(FILE *fout, struct parsed_op *po,
5772 int *pfomask, const char *dst_opr_text)
5774 if (*pfomask & (1 << PFO_Z)) {
5775 fprintf(fout, "\n cond_z = (%s%s == 0);",
5776 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5777 *pfomask &= ~(1 << PFO_Z);
5781 static void output_std_flag_s(FILE *fout, struct parsed_op *po,
5782 int *pfomask, const char *dst_opr_text)
5784 if (*pfomask & (1 << PFO_S)) {
5785 fprintf(fout, "\n cond_s = (%s%s < 0);",
5786 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5787 *pfomask &= ~(1 << PFO_S);
5791 static void output_std_flags(FILE *fout, struct parsed_op *po,
5792 int *pfomask, const char *dst_opr_text)
5794 output_std_flag_z(fout, po, pfomask, dst_opr_text);
5795 output_std_flag_s(fout, po, pfomask, dst_opr_text);
5799 OPP_FORCE_NORETURN = (1 << 0),
5800 OPP_SIMPLE_ARGS = (1 << 1),
5801 OPP_ALIGN = (1 << 2),
5804 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
5807 const char *cconv = "";
5809 if (pp->is_fastcall)
5810 cconv = "__fastcall ";
5811 else if (pp->is_stdcall && pp->argc_reg == 0)
5812 cconv = "__stdcall ";
5814 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5816 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
5817 fprintf(fout, "noreturn ");
5820 static void output_pp(FILE *fout, const struct parsed_proto *pp,
5825 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5829 output_pp_attrs(fout, pp, flags);
5832 fprintf(fout, "%s", pp->name);
5837 for (i = 0; i < pp->argc; i++) {
5839 fprintf(fout, ", ");
5840 if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
5841 && !(flags & OPP_SIMPLE_ARGS))
5844 output_pp(fout, pp->arg[i].pp, 0);
5846 else if (pp->arg[i].type.is_retreg) {
5847 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
5850 fprintf(fout, "%s", pp->arg[i].type.name);
5852 fprintf(fout, " a%d", i + 1);
5855 if (pp->arg[i].type.is_64bit)
5858 if (pp->is_vararg) {
5860 fprintf(fout, ", ");
5861 fprintf(fout, "...");
5866 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
5872 snprintf(buf1, sizeof(buf1), "%d", grp);
5873 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
5878 static void gen_x_cleanup(int opcnt);
5880 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
5882 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
5883 struct parsed_opr *last_arith_dst = NULL;
5884 char buf1[256], buf2[256], buf3[256], cast[64];
5885 struct parsed_proto *pp, *pp_tmp;
5886 struct parsed_data *pd;
5887 int save_arg_vars[MAX_ARG_GRP] = { 0, };
5888 unsigned char cbits[MAX_OPS / 8];
5889 const char *float_type;
5890 const char *float_st0;
5891 const char *float_st1;
5892 int need_float_stack = 0;
5893 int need_float_sw = 0; // status word
5894 int need_tmp_var = 0;
5898 int label_pending = 0;
5899 int need_double = 0;
5900 int stack_align = 0;
5901 int stack_fsz_adj = 0;
5902 int regmask_save = 0; // used regs saved/restored in this func
5903 int regmask_arg; // regs from this function args (fastcall, etc)
5904 int regmask_ret; // regs needed on ret
5905 int regmask_now; // temp
5906 int regmask_init = 0; // regs that need zero initialization
5907 int regmask_pp = 0; // regs used in complex push-pop graph
5908 int regmask_ffca = 0; // float function call args
5909 int regmask = 0; // used regs
5919 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
5920 g_stack_frame_used = 0;
5922 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
5923 regmask_init = g_regmask_init;
5925 g_func_pp = proto_parse(fhdr, funcn, 0);
5926 if (g_func_pp == NULL)
5927 ferr(ops, "proto_parse failed for '%s'\n", funcn);
5929 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
5930 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
5933 // - resolve all branches
5934 // - parse calls with labels
5935 resolve_branches_parse_calls(opcnt);
5938 // - handle ebp/esp frame, remove ops related to it
5939 scan_prologue_epilogue(opcnt, &stack_align);
5941 // handle a case where sf size is unalignment, but is
5942 // placed in a way that elements are still aligned
5943 if (g_stack_fsz & 4) {
5944 for (i = 0; i < g_eqcnt; i++) {
5945 if (g_eqs[i].lmod != OPLM_QWORD)
5947 if (!(g_eqs[i].offset & 4)) {
5956 // - remove dead labels
5957 // - set regs needed at ret
5958 for (i = 0; i < opcnt; i++)
5960 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
5965 if (ops[i].op == OP_RET)
5966 ops[i].regmask_src |= regmask_ret;
5970 // - process trivial calls
5971 for (i = 0; i < opcnt; i++)
5974 if (po->flags & (OPF_RMD|OPF_DONE))
5977 if (po->op == OP_CALL)
5979 pp = process_call_early(i, opcnt, &j);
5981 if (!(po->flags & OPF_ATAIL)) {
5982 // since we know the args, try to collect them
5983 ret = collect_call_args_early(i, pp, ®mask, ®mask_ffca);
5991 // commit esp adjust
5992 if (ops[j].op != OP_POP)
5993 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5995 for (l = 0; l < pp->argc_stack; l++)
5996 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
6000 if (strstr(pp->ret_type.name, "int64"))
6003 po->flags |= OPF_DONE;
6009 // - process calls, stage 2
6010 // - handle some push/pop pairs
6011 // - scan for STD/CLD, propagate DF
6012 // - try to resolve needed x87 status word bits
6013 for (i = 0; i < opcnt; i++)
6018 if (po->flags & OPF_RMD)
6021 if (po->op == OP_CALL)
6023 if (!(po->flags & OPF_DONE)) {
6024 pp = process_call(i, opcnt);
6026 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
6027 // since we know the args, collect them
6028 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
6030 // for unresolved, collect after other passes
6034 ferr_assert(po, pp != NULL);
6036 po->regmask_src |= get_pp_arg_regmask_src(pp);
6037 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
6039 if (po->regmask_dst & mxST0)
6040 po->flags |= OPF_FPUSH;
6042 if (strstr(pp->ret_type.name, "int64"))
6048 if (po->flags & OPF_DONE)
6053 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
6054 && po->operand[0].type == OPT_CONST)
6056 scan_for_pop_const(i, opcnt, i + opcnt * 12);
6061 scan_pushes_for_pop(i, opcnt, ®mask_pp);
6065 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
6066 scan_propagate_df(i + 1, opcnt);
6071 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
6072 ferr(po, "TODO: fnstsw to mem\n");
6073 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
6075 ferr(po, "fnstsw resolve failed\n");
6076 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
6077 (void *)(long)(mask | (z_check << 16)));
6079 ferr(po, "failed to find fcom: %d\n", ret);
6088 // - find POPs for PUSHes, rm both
6089 // - scan for all used registers
6090 memset(cbits, 0, sizeof(cbits));
6091 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
6092 0, ®mask_save, ®mask_init, regmask_arg);
6094 need_float_stack = !!(regmask & mxST7_2);
6097 // - find flag set ops for their users
6098 // - do unresolved calls
6099 // - declare indirect functions
6100 // - other op specific processing
6101 for (i = 0; i < opcnt; i++)
6104 if (po->flags & (OPF_RMD|OPF_DONE))
6107 if (po->flags & OPF_CC)
6109 int setters[16], cnt = 0, branched = 0;
6111 ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
6112 &branched, setters, &cnt);
6113 if (ret < 0 || cnt <= 0)
6114 ferr(po, "unable to trace flag setter(s)\n");
6115 if (cnt > ARRAY_SIZE(setters))
6116 ferr(po, "too many flag setters\n");
6118 for (j = 0; j < cnt; j++)
6120 tmp_op = &ops[setters[j]]; // flag setter
6123 // to get nicer code, we try to delay test and cmp;
6124 // if we can't because of operand modification, or if we
6125 // have arith op, or branch, make it calculate flags explicitly
6126 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
6128 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
6129 pfomask = 1 << po->pfo;
6131 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
6132 pfomask = 1 << po->pfo;
6135 // see if we'll be able to handle based on op result
6136 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
6137 && po->pfo != PFO_Z && po->pfo != PFO_S
6138 && po->pfo != PFO_P)
6140 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
6142 pfomask = 1 << po->pfo;
6145 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
6146 propagate_lmod(tmp_op, &tmp_op->operand[0],
6147 &tmp_op->operand[1]);
6148 if (tmp_op->operand[0].lmod == OPLM_DWORD)
6153 tmp_op->pfomask |= pfomask;
6154 cond_vars |= pfomask;
6156 // note: may overwrite, currently not a problem
6160 if (po->op == OP_RCL || po->op == OP_RCR
6161 || po->op == OP_ADC || po->op == OP_SBB)
6162 cond_vars |= 1 << PFO_C;
6168 cond_vars |= 1 << PFO_Z;
6172 if (po->operand[0].lmod == OPLM_DWORD)
6177 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
6182 // note: resolved non-reg calls are OPF_DONE already
6184 ferr_assert(po, pp != NULL);
6186 if (pp->is_unresolved) {
6187 int regmask_stack = 0;
6188 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
6190 // this is pretty rough guess:
6191 // see ecx and edx were pushed (and not their saved versions)
6192 for (arg = 0; arg < pp->argc; arg++) {
6193 if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
6196 tmp_op = pp->arg[arg].datap;
6198 ferr(po, "parsed_op missing for arg%d\n", arg);
6199 if (tmp_op->operand[0].type == OPT_REG)
6200 regmask_stack |= 1 << tmp_op->operand[0].reg;
6203 if (!((regmask_stack & (1 << xCX))
6204 && (regmask_stack & (1 << xDX))))
6206 if (pp->argc_stack != 0
6207 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
6209 pp_insert_reg_arg(pp, "ecx");
6210 pp->is_fastcall = 1;
6211 regmask_init |= 1 << xCX;
6212 regmask |= 1 << xCX;
6214 if (pp->argc_stack != 0
6215 || ((regmask | regmask_arg) & (1 << xDX)))
6217 pp_insert_reg_arg(pp, "edx");
6218 regmask_init |= 1 << xDX;
6219 regmask |= 1 << xDX;
6223 // note: __cdecl doesn't fall into is_unresolved category
6224 if (pp->argc_stack > 0)
6227 if (!(po->flags & OPF_TAIL)
6228 && !(g_sct_func_attr & SCTFA_NOWARN))
6230 // treat al write as overwrite to avoid many false positives
6231 if (IS(pp->ret_type.name, "void") || pp->ret_type.is_float) {
6232 find_next_read_reg(i + 1, opcnt, xAX, OPLM_BYTE,
6233 i + opcnt * 25, &j);
6235 fnote(po, "eax used after void/float ret call\n");
6236 fnote(&ops[j], "(used here)\n");
6239 if (!strstr(pp->ret_type.name, "int64")) {
6240 find_next_read_reg(i + 1, opcnt, xDX, OPLM_BYTE,
6241 i + opcnt * 26, &j);
6242 // indirect calls are often guessed, don't warn
6243 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j])) {
6244 fnote(po, "edx used after 32bit ret call\n");
6245 fnote(&ops[j], "(used here)\n");
6249 // msvc often relies on callee not modifying 'this'
6250 for (arg = 0; arg < pp->argc; arg++) {
6251 if (pp->arg[arg].reg && IS(pp->arg[arg].reg, "ecx")) {
6257 find_next_read_reg(i + 1, opcnt, xCX, OPLM_BYTE,
6258 i + opcnt * 27, &j);
6259 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j])) {
6260 fnote(po, "ecx used after call\n");
6261 fnote(&ops[j], "(used here)\n");
6268 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
6270 // <var> = offset <something>
6271 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
6272 && !IS_START(po->operand[1].name, "off_"))
6274 if (!po->operand[0].pp->is_fptr)
6275 ferr(po, "%s not declared as fptr when it should be\n",
6276 po->operand[0].name);
6277 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
6278 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
6279 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
6280 fnote(po, "var: %s\n", buf1);
6281 fnote(po, "func: %s\n", buf2);
6282 ferr(po, "^ mismatch\n");
6290 if (po->operand[0].lmod == OPLM_DWORD) {
6291 // 32bit division is common, look for it
6292 if (po->op == OP_DIV)
6293 ret = scan_for_reg_clear(i, xDX);
6295 ret = scan_for_cdq_edx(i);
6297 po->flags |= OPF_32BIT;
6306 po->flags |= OPF_RMD | OPF_DONE;
6316 if (po->operand[0].lmod == OPLM_QWORD)
6326 find_next_read_reg(i + 1, opcnt, xDX, OPLM_DWORD,
6327 i + opcnt * 18, &j);
6329 po->flags |= OPF_32BIT;
6336 // this might need it's own pass...
6337 if (po->op != OP_FST && po->p_argnum > 0)
6338 save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
6340 // correct for "full stack" mode late enable
6341 if ((po->flags & (OPF_PPUSH|OPF_FPOP|OPF_FPOPP))
6342 && need_float_stack)
6343 po->flags |= OPF_FSHIFT;
6346 float_type = need_double ? "double" : "float";
6347 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
6348 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
6350 // output starts here
6353 fprintf(fout, "// had SEH\n");
6355 // define userstack size
6356 if (g_func_pp->is_userstack) {
6357 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
6358 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
6359 fprintf(fout, "#endif\n");
6362 // the function itself
6363 ferr_assert(ops, !g_func_pp->is_fptr);
6364 output_pp(fout, g_func_pp,
6365 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
6366 fprintf(fout, "\n{\n");
6368 // declare indirect functions
6369 for (i = 0; i < opcnt; i++) {
6371 if (po->flags & OPF_RMD)
6374 if (po->op == OP_CALL) {
6377 ferr(po, "NULL pp\n");
6379 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
6380 if (pp->name[0] != 0) {
6381 if (IS_START(pp->name, "guess"))
6384 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
6385 memcpy(pp->name, "i_", 2);
6387 // might be declared already
6389 for (j = 0; j < i; j++) {
6390 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
6391 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
6401 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
6404 output_pp(fout, pp, OPP_SIMPLE_ARGS);
6405 fprintf(fout, ";\n");
6410 // output LUTs/jumptables
6411 for (i = 0; i < g_func_pd_cnt; i++) {
6413 fprintf(fout, " static const ");
6414 if (pd->type == OPT_OFFSET) {
6415 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
6417 for (j = 0; j < pd->count; j++) {
6419 fprintf(fout, ", ");
6420 fprintf(fout, "&&%s", pd->d[j].u.label);
6424 fprintf(fout, "%s %s[] =\n { ",
6425 lmod_type_u(ops, pd->lmod), pd->label);
6427 for (j = 0; j < pd->count; j++) {
6429 fprintf(fout, ", ");
6430 fprintf(fout, "%u", pd->d[j].u.val);
6433 fprintf(fout, " };\n");
6437 // declare stack frame, va_arg
6440 fprintf(fout, " // stack_fsz_adj %d\n", stack_fsz_adj);
6442 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
6443 if (g_func_lmods & (1 << OPLM_WORD))
6444 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
6445 if (g_func_lmods & (1 << OPLM_BYTE))
6446 fprintf(fout, " u8 b[%d];", g_stack_fsz);
6447 if (g_func_lmods & (1 << OPLM_QWORD))
6448 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
6450 if (stack_align > 8)
6451 ferr(ops, "unhandled stack align of %d\n", stack_align);
6452 else if (stack_align == 8)
6453 fprintf(fout, " u64 align;");
6454 fprintf(fout, " } sf;\n");
6458 if (g_func_pp->is_userstack) {
6459 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
6460 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
6464 if (g_func_pp->is_vararg) {
6465 fprintf(fout, " va_list ap;\n");
6469 // declare arg-registers
6470 for (i = 0; i < g_func_pp->argc; i++) {
6471 if (g_func_pp->arg[i].reg != NULL) {
6472 reg = char_array_i(regs_r32,
6473 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
6474 if (regmask & (1 << reg)) {
6475 if (g_func_pp->arg[i].type.is_retreg)
6476 fprintf(fout, " u32 %s = *r_%s;\n",
6477 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
6479 fprintf(fout, " u32 %s = (u32)a%d;\n",
6480 g_func_pp->arg[i].reg, i + 1);
6483 if (g_func_pp->arg[i].type.is_retreg)
6484 ferr(ops, "retreg '%s' is unused?\n",
6485 g_func_pp->arg[i].reg);
6486 fprintf(fout, " // %s = a%d; // unused\n",
6487 g_func_pp->arg[i].reg, i + 1);
6493 // declare normal registers
6494 regmask_now = regmask & ~regmask_arg & ~g_regmask_rm;
6495 regmask_now &= ~(1 << xSP);
6496 if (regmask_now & 0x00ff) {
6497 for (reg = 0; reg < 8; reg++) {
6498 if (regmask_now & (1 << reg)) {
6499 fprintf(fout, " u32 %s", regs_r32[reg]);
6500 if (regmask_init & (1 << reg))
6501 fprintf(fout, " = 0");
6502 fprintf(fout, ";\n");
6508 if (regmask_now & 0xff00) {
6509 for (reg = 8; reg < 16; reg++) {
6510 if (regmask_now & (1 << reg)) {
6511 fprintf(fout, " mmxr %s", regs_r32[reg]);
6512 if (regmask_init & (1 << reg))
6513 fprintf(fout, " = { 0, }");
6514 fprintf(fout, ";\n");
6520 if (need_float_stack) {
6521 fprintf(fout, " %s f_st[8];\n", float_type);
6522 fprintf(fout, " int f_stp = 0;\n");
6526 if (regmask_now & 0xff0000) {
6527 for (reg = 16; reg < 24; reg++) {
6528 if (regmask_now & (1 << reg)) {
6529 fprintf(fout, " %s f_st%d", float_type, reg - 16);
6530 if (regmask_init & (1 << reg))
6531 fprintf(fout, " = 0");
6532 fprintf(fout, ";\n");
6539 if (need_float_sw) {
6540 fprintf(fout, " u16 f_sw;\n");
6545 for (reg = 0; reg < 8; reg++) {
6546 if (regmask_save & (1 << reg)) {
6547 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
6553 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6554 if (save_arg_vars[i] == 0)
6556 for (reg = 0; reg < 32; reg++) {
6557 if (save_arg_vars[i] & (1 << reg)) {
6558 fprintf(fout, " u32 %s;\n",
6559 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
6566 for (reg = 0; reg < 32; reg++) {
6567 if (regmask_ffca & (1 << reg)) {
6568 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
6574 // declare push-pop temporaries
6576 for (reg = 0; reg < 8; reg++) {
6577 if (regmask_pp & (1 << reg)) {
6578 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
6585 for (i = 0; i < 8; i++) {
6586 if (cond_vars & (1 << i)) {
6587 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
6594 fprintf(fout, " u32 tmp;\n");
6599 fprintf(fout, " u64 tmp64;\n");
6604 fprintf(fout, "\n");
6606 // do stack clear, if needed
6607 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6609 if (g_stack_clear_len != 0) {
6610 if (g_stack_clear_len <= 4) {
6611 for (i = 0; i < g_stack_clear_len; i++)
6612 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6613 fprintf(fout, "0;\n");
6616 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6617 g_stack_clear_start, g_stack_clear_len * 4);
6621 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6624 if (g_func_pp->is_vararg) {
6625 if (g_func_pp->argc_stack == 0)
6626 ferr(ops, "vararg func without stack args?\n");
6627 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
6631 for (i = 0; i < opcnt; i++)
6633 if (g_labels[i] != NULL) {
6634 fprintf(fout, "\n%s:\n", g_labels[i]);
6637 delayed_flag_op = NULL;
6638 last_arith_dst = NULL;
6642 if (po->flags & OPF_RMD)
6647 #define assert_operand_cnt(n_) \
6648 if (po->operand_cnt != n_) \
6649 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6651 // conditional/flag using op?
6652 if (po->flags & OPF_CC)
6658 // we go through all this trouble to avoid using parsed_flag_op,
6659 // which makes generated code much nicer
6660 if (delayed_flag_op != NULL)
6662 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6663 po->pfo, po->pfo_inv);
6666 else if (last_arith_dst != NULL
6667 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6668 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6671 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6672 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6673 last_arith_dst->lmod, buf3);
6676 else if (tmp_op != NULL) {
6677 // use preprocessed flag calc results
6678 if (!(tmp_op->pfomask & (1 << po->pfo)))
6679 ferr(po, "not prepared for pfo %d\n", po->pfo);
6681 // note: pfo_inv was not yet applied
6682 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6683 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6686 ferr(po, "all methods of finding comparison failed\n");
6689 if (po->flags & OPF_JMP) {
6690 fprintf(fout, " if %s", buf1);
6692 else if (po->op == OP_RCL || po->op == OP_RCR
6693 || po->op == OP_ADC || po->op == OP_SBB)
6696 fprintf(fout, " cond_%s = %s;\n",
6697 parsed_flag_op_names[po->pfo], buf1);
6699 else if (po->flags & OPF_DATA) { // SETcc
6700 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6701 fprintf(fout, " %s = %s;", buf2, buf1);
6704 ferr(po, "unhandled conditional op\n");
6708 pfomask = po->pfomask;
6713 assert_operand_cnt(2);
6714 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6715 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6716 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
6717 fprintf(fout, " %s = %s;", buf1,
6718 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6723 assert_operand_cnt(2);
6724 po->operand[1].lmod = OPLM_DWORD; // always
6725 fprintf(fout, " %s = %s;",
6726 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6727 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6732 assert_operand_cnt(2);
6733 fprintf(fout, " %s = %s;",
6734 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6735 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6739 assert_operand_cnt(2);
6740 switch (po->operand[1].lmod) {
6742 strcpy(buf3, "(s8)");
6745 strcpy(buf3, "(s16)");
6748 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6750 fprintf(fout, " %s = %s;",
6751 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6752 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6757 assert_operand_cnt(2);
6758 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6759 fprintf(fout, " tmp = %s;",
6760 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6761 fprintf(fout, " %s = %s;",
6762 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6763 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6764 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6765 fprintf(fout, " %s = %stmp;",
6766 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6767 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
6768 snprintf(g_comment, sizeof(g_comment), "xchg");
6772 assert_operand_cnt(1);
6773 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6774 fprintf(fout, " %s = ~%s;", buf1, buf1);
6778 assert_operand_cnt(2);
6779 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6780 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6781 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6782 strcpy(g_comment, "xlat");
6786 assert_operand_cnt(2);
6787 fprintf(fout, " %s = (s32)%s >> 31;",
6788 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6789 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6790 strcpy(g_comment, "cdq");
6794 assert_operand_cnt(1);
6795 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6796 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
6800 if (po->flags & OPF_REP) {
6801 assert_operand_cnt(3);
6806 assert_operand_cnt(2);
6807 fprintf(fout, " %s = %sesi; esi %c= %d;",
6808 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6809 lmod_cast_u_ptr(po, po->operand[1].lmod),
6810 (po->flags & OPF_DF) ? '-' : '+',
6811 lmod_bytes(po, po->operand[1].lmod));
6812 strcpy(g_comment, "lods");
6817 if (po->flags & OPF_REP) {
6818 assert_operand_cnt(3);
6819 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
6820 (po->flags & OPF_DF) ? '-' : '+',
6821 lmod_bytes(po, po->operand[1].lmod));
6822 fprintf(fout, " %sedi = eax;",
6823 lmod_cast_u_ptr(po, po->operand[1].lmod));
6824 strcpy(g_comment, "rep stos");
6827 assert_operand_cnt(2);
6828 fprintf(fout, " %sedi = eax; edi %c= %d;",
6829 lmod_cast_u_ptr(po, po->operand[1].lmod),
6830 (po->flags & OPF_DF) ? '-' : '+',
6831 lmod_bytes(po, po->operand[1].lmod));
6832 strcpy(g_comment, "stos");
6837 j = lmod_bytes(po, po->operand[0].lmod);
6838 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6839 l = (po->flags & OPF_DF) ? '-' : '+';
6840 if (po->flags & OPF_REP) {
6841 assert_operand_cnt(3);
6843 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
6846 " %sedi = %sesi;", buf1, buf1);
6847 strcpy(g_comment, "rep movs");
6850 assert_operand_cnt(2);
6851 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
6852 buf1, buf1, l, j, l, j);
6853 strcpy(g_comment, "movs");
6858 // repe ~ repeat while ZF=1
6859 j = lmod_bytes(po, po->operand[0].lmod);
6860 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6861 l = (po->flags & OPF_DF) ? '-' : '+';
6862 if (po->flags & OPF_REP) {
6863 assert_operand_cnt(3);
6865 " while (ecx != 0) {\n");
6866 if (pfomask & (1 << PFO_C)) {
6869 " cond_c = %sesi < %sedi;\n", buf1, buf1);
6870 pfomask &= ~(1 << PFO_C);
6873 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
6874 buf1, buf1, l, j, l, j);
6877 " if (cond_z %s 0) break;\n",
6878 (po->flags & OPF_REPZ) ? "==" : "!=");
6881 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
6882 (po->flags & OPF_REPZ) ? "e" : "ne");
6885 assert_operand_cnt(2);
6887 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
6888 buf1, buf1, l, j, l, j);
6889 strcpy(g_comment, "cmps");
6891 pfomask &= ~(1 << PFO_Z);
6892 last_arith_dst = NULL;
6893 delayed_flag_op = NULL;
6897 // only does ZF (for now)
6898 // repe ~ repeat while ZF=1
6899 j = lmod_bytes(po, po->operand[1].lmod);
6900 l = (po->flags & OPF_DF) ? '-' : '+';
6901 if (po->flags & OPF_REP) {
6902 assert_operand_cnt(3);
6904 " while (ecx != 0) {\n");
6906 " cond_z = (%seax == %sedi); edi %c= %d;\n",
6907 lmod_cast_u(po, po->operand[1].lmod),
6908 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6911 " if (cond_z %s 0) break;\n",
6912 (po->flags & OPF_REPZ) ? "==" : "!=");
6915 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
6916 (po->flags & OPF_REPZ) ? "e" : "ne");
6919 assert_operand_cnt(2);
6920 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
6921 lmod_cast_u(po, po->operand[1].lmod),
6922 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6923 strcpy(g_comment, "scas");
6925 pfomask &= ~(1 << PFO_Z);
6926 last_arith_dst = NULL;
6927 delayed_flag_op = NULL;
6930 // arithmetic w/flags
6932 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
6933 goto dualop_arith_const;
6934 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6938 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6939 if (po->operand[1].type == OPT_CONST) {
6940 j = lmod_bytes(po, po->operand[0].lmod);
6941 if (((1ull << j * 8) - 1) == po->operand[1].val)
6942 goto dualop_arith_const;
6947 assert_operand_cnt(2);
6948 fprintf(fout, " %s %s= %s;",
6949 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6951 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6952 output_std_flags(fout, po, &pfomask, buf1);
6953 last_arith_dst = &po->operand[0];
6954 delayed_flag_op = NULL;
6958 // and 0, or ~0 used instead mov
6959 assert_operand_cnt(2);
6960 fprintf(fout, " %s = %s;",
6961 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6962 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6963 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6964 output_std_flags(fout, po, &pfomask, buf1);
6965 last_arith_dst = &po->operand[0];
6966 delayed_flag_op = NULL;
6971 assert_operand_cnt(2);
6972 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6973 if (pfomask & (1 << PFO_C)) {
6974 if (po->operand[1].type == OPT_CONST) {
6975 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6976 j = po->operand[1].val;
6979 if (po->op == OP_SHL)
6983 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
6987 ferr(po, "zero shift?\n");
6991 pfomask &= ~(1 << PFO_C);
6993 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
6994 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6995 if (po->operand[1].type != OPT_CONST)
6996 fprintf(fout, " & 0x1f");
6998 output_std_flags(fout, po, &pfomask, buf1);
6999 last_arith_dst = &po->operand[0];
7000 delayed_flag_op = NULL;
7004 assert_operand_cnt(2);
7005 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7006 fprintf(fout, " %s = %s%s >> %s;", buf1,
7007 lmod_cast_s(po, po->operand[0].lmod), buf1,
7008 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7009 output_std_flags(fout, po, &pfomask, buf1);
7010 last_arith_dst = &po->operand[0];
7011 delayed_flag_op = NULL;
7016 assert_operand_cnt(3);
7017 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7018 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7019 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
7020 if (po->operand[2].type != OPT_CONST) {
7021 // no handling for "undefined" case, hopefully not needed
7022 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
7025 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7026 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7027 if (po->op == OP_SHLD) {
7028 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
7029 buf1, buf3, buf1, buf2, l, buf3);
7030 strcpy(g_comment, "shld");
7033 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
7034 buf1, buf3, buf1, buf2, l, buf3);
7035 strcpy(g_comment, "shrd");
7037 output_std_flags(fout, po, &pfomask, buf1);
7038 last_arith_dst = &po->operand[0];
7039 delayed_flag_op = NULL;
7044 assert_operand_cnt(2);
7045 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7046 if (po->operand[1].type == OPT_CONST) {
7047 j = po->operand[1].val;
7048 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
7049 fprintf(fout, po->op == OP_ROL ?
7050 " %s = (%s << %d) | (%s >> %d);" :
7051 " %s = (%s >> %d) | (%s << %d);",
7052 buf1, buf1, j, buf1,
7053 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
7057 output_std_flags(fout, po, &pfomask, buf1);
7058 last_arith_dst = &po->operand[0];
7059 delayed_flag_op = NULL;
7064 assert_operand_cnt(2);
7065 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7066 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7067 if (po->operand[1].type == OPT_CONST) {
7068 j = po->operand[1].val % l;
7070 ferr(po, "zero rotate\n");
7071 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
7072 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
7073 if (po->op == OP_RCL) {
7075 " %s = (%s << %d) | (cond_c << %d)",
7076 buf1, buf1, j, j - 1);
7078 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
7082 " %s = (%s >> %d) | (cond_c << %d)",
7083 buf1, buf1, j, l - j);
7085 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
7087 fprintf(fout, ";\n");
7088 fprintf(fout, " cond_c = tmp;");
7092 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
7093 output_std_flags(fout, po, &pfomask, buf1);
7094 last_arith_dst = &po->operand[0];
7095 delayed_flag_op = NULL;
7099 assert_operand_cnt(2);
7100 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7101 if (IS(opr_name(po, 0), opr_name(po, 1))) {
7102 // special case for XOR
7103 int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
7104 for (j = 0; j <= PFO_LE; j++) {
7105 if (pfomask & (1 << j)) {
7106 fprintf(fout, " cond_%s = %d;\n",
7107 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
7108 pfomask &= ~(1 << j);
7111 fprintf(fout, " %s = 0;",
7112 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7113 last_arith_dst = &po->operand[0];
7114 delayed_flag_op = NULL;
7120 assert_operand_cnt(2);
7121 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7122 if (pfomask & (1 << PFO_C)) {
7123 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7124 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7125 if (po->operand[0].lmod == OPLM_DWORD) {
7126 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
7127 fprintf(fout, " cond_c = tmp64 >> 32;\n");
7128 fprintf(fout, " %s = (u32)tmp64;",
7129 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7130 strcat(g_comment, " add64");
7133 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
7134 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
7135 fprintf(fout, " %s += %s;",
7136 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7139 pfomask &= ~(1 << PFO_C);
7140 output_std_flags(fout, po, &pfomask, buf1);
7141 last_arith_dst = &po->operand[0];
7142 delayed_flag_op = NULL;
7145 if (pfomask & (1 << PFO_LE)) {
7146 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
7147 fprintf(fout, " cond_%s = %s;\n",
7148 parsed_flag_op_names[PFO_LE], buf1);
7149 pfomask &= ~(1 << PFO_LE);
7154 assert_operand_cnt(2);
7155 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7156 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
7157 for (j = 0; j <= PFO_LE; j++) {
7158 if (!(pfomask & (1 << j)))
7160 if (j == PFO_Z || j == PFO_S)
7163 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7164 fprintf(fout, " cond_%s = %s;\n",
7165 parsed_flag_op_names[j], buf1);
7166 pfomask &= ~(1 << j);
7173 assert_operand_cnt(2);
7174 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7175 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7176 if (po->op == OP_SBB
7177 && IS(po->operand[0].name, po->operand[1].name))
7179 // avoid use of unitialized var
7180 fprintf(fout, " %s = -cond_c;", buf1);
7181 // carry remains what it was
7182 pfomask &= ~(1 << PFO_C);
7185 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
7186 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7188 output_std_flags(fout, po, &pfomask, buf1);
7189 last_arith_dst = &po->operand[0];
7190 delayed_flag_op = NULL;
7195 // on SKL, if src is 0, dst is left unchanged
7196 assert_operand_cnt(2);
7197 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7198 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7199 output_std_flag_z(fout, po, &pfomask, buf2);
7200 if (po->op == OP_BSF)
7201 snprintf(buf3, sizeof(buf3), "__builtin_ffs(%s) - 1", buf2);
7203 snprintf(buf3, sizeof(buf3), "31 - __builtin_clz(%s)", buf2);
7204 fprintf(fout, " if (%s) %s = %s;", buf2, buf1, buf3);
7205 last_arith_dst = &po->operand[0];
7206 delayed_flag_op = NULL;
7207 strcat(g_comment, po->op == OP_BSF ? " bsf" : " bsr");
7211 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
7212 for (j = 0; j <= PFO_LE; j++) {
7213 if (!(pfomask & (1 << j)))
7215 if (j == PFO_Z || j == PFO_S || j == PFO_C)
7218 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7219 fprintf(fout, " cond_%s = %s;\n",
7220 parsed_flag_op_names[j], buf1);
7221 pfomask &= ~(1 << j);
7227 if (pfomask & (1 << PFO_C))
7228 // carry is unaffected by inc/dec.. wtf?
7229 ferr(po, "carry propagation needed\n");
7231 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7232 if (po->operand[0].type == OPT_REG) {
7233 strcpy(buf2, po->op == OP_INC ? "++" : "--");
7234 fprintf(fout, " %s%s;", buf1, buf2);
7237 strcpy(buf2, po->op == OP_INC ? "+" : "-");
7238 fprintf(fout, " %s %s= 1;", buf1, buf2);
7240 output_std_flags(fout, po, &pfomask, buf1);
7241 last_arith_dst = &po->operand[0];
7242 delayed_flag_op = NULL;
7246 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7247 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
7248 fprintf(fout, " %s = -%s%s;", buf1,
7249 lmod_cast_s(po, po->operand[0].lmod), buf2);
7250 last_arith_dst = &po->operand[0];
7251 delayed_flag_op = NULL;
7252 if (pfomask & PFOB_C) {
7253 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
7256 output_std_flags(fout, po, &pfomask, buf1);
7260 if (po->operand_cnt == 2) {
7261 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7264 if (po->operand_cnt == 3)
7265 ferr(po, "TODO imul3\n");
7268 assert_operand_cnt(1);
7269 switch (po->operand[0].lmod) {
7271 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
7272 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
7273 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
7274 fprintf(fout, " edx = tmp64 >> 32;\n");
7275 fprintf(fout, " eax = tmp64;");
7278 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
7279 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
7280 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
7284 ferr(po, "TODO: unhandled mul type\n");
7287 last_arith_dst = NULL;
7288 delayed_flag_op = NULL;
7293 assert_operand_cnt(1);
7294 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7295 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
7296 po->op == OP_IDIV));
7297 switch (po->operand[0].lmod) {
7299 if (po->flags & OPF_32BIT)
7300 snprintf(buf2, sizeof(buf2), "%seax", cast);
7302 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7303 snprintf(buf2, sizeof(buf2), "%stmp64",
7304 (po->op == OP_IDIV) ? "(s64)" : "");
7306 if (po->operand[0].type == OPT_REG
7307 && po->operand[0].reg == xDX)
7309 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
7310 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
7313 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
7314 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
7318 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
7319 snprintf(buf2, sizeof(buf2), "%stmp",
7320 (po->op == OP_IDIV) ? "(s32)" : "");
7321 if (po->operand[0].type == OPT_REG
7322 && po->operand[0].reg == xDX)
7324 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
7326 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
7330 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
7332 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
7335 strcat(g_comment, " div16");
7338 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
7340 last_arith_dst = NULL;
7341 delayed_flag_op = NULL;
7346 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7348 for (j = 0; j < 8; j++) {
7349 if (pfomask & (1 << j)) {
7350 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
7351 fprintf(fout, " cond_%s = %s;",
7352 parsed_flag_op_names[j], buf1);
7359 last_arith_dst = NULL;
7360 delayed_flag_op = po;
7364 // SETcc - should already be handled
7367 // note: we reuse OP_Jcc for SETcc, only flags differ
7369 fprintf(fout, "\n goto %s;", po->operand[0].name);
7373 fprintf(fout, " if (ecx == 0)\n");
7374 fprintf(fout, " goto %s;", po->operand[0].name);
7375 strcat(g_comment, " jecxz");
7379 fprintf(fout, " if (--ecx != 0)\n");
7380 fprintf(fout, " goto %s;", po->operand[0].name);
7381 strcat(g_comment, " loop");
7385 assert_operand_cnt(1);
7386 last_arith_dst = NULL;
7387 delayed_flag_op = NULL;
7389 if (po->operand[0].type == OPT_REGMEM) {
7390 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
7393 ferr(po, "parse failure for jmp '%s'\n",
7394 po->operand[0].name);
7395 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
7398 else if (po->operand[0].type != OPT_LABEL)
7399 ferr(po, "unhandled jmp type\n");
7401 fprintf(fout, " goto %s;", po->operand[0].name);
7405 assert_operand_cnt(1);
7407 my_assert_not(pp, NULL);
7410 if (po->flags & OPF_CC) {
7411 // we treat conditional branch to another func
7412 // (yes such code exists..) as conditional tailcall
7414 fprintf(fout, " {\n");
7417 if (pp->is_fptr && !pp->is_arg) {
7418 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
7419 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7422 if (pp->is_fptr && (pp->is_unresolved || pp->is_guessed)) {
7423 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
7424 buf3, asmfn, po->asmln, pp->name);
7427 fprintf(fout, "%s", buf3);
7428 if (strstr(pp->ret_type.name, "int64")) {
7429 if (po->flags & OPF_TAIL)
7430 ferr(po, "int64 and tail?\n");
7431 fprintf(fout, "tmp64 = ");
7433 else if (!IS(pp->ret_type.name, "void")) {
7434 if (po->flags & OPF_TAIL) {
7435 if (regmask_ret & mxAX) {
7436 fprintf(fout, "return ");
7437 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
7438 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
7440 else if (regmask_ret & mxST0)
7441 ferr(po, "float tailcall\n");
7443 else if (po->regmask_dst & mxAX) {
7444 fprintf(fout, "eax = ");
7445 if (pp->ret_type.is_ptr)
7446 fprintf(fout, "(u32)");
7448 else if (po->regmask_dst & mxST0) {
7449 ferr_assert(po, po->flags & OPF_FPUSH);
7450 if (need_float_stack)
7451 fprintf(fout, "f_st[--f_stp & 7] = ");
7453 fprintf(fout, "f_st0 = ");
7457 if (pp->name[0] == 0)
7458 ferr(po, "missing pp->name\n");
7459 fprintf(fout, "%s%s(", pp->name,
7460 pp->has_structarg ? "_sa" : "");
7462 if (po->flags & OPF_ATAIL) {
7464 g_func_pp->is_stdcall && g_func_pp->argc_stack > 0;
7465 check_compat |= pp->argc_stack > 0;
7467 && (pp->argc_stack != g_func_pp->argc_stack
7468 || pp->is_stdcall != g_func_pp->is_stdcall))
7469 ferr(po, "incompatible arg-reuse tailcall\n");
7470 if (g_func_pp->has_retreg)
7471 ferr(po, "TODO: retreg+tailcall\n");
7473 for (arg = j = 0; arg < pp->argc; arg++) {
7475 fprintf(fout, ", ");
7478 if (pp->arg[arg].type.is_ptr)
7479 snprintf(cast, sizeof(cast), "(%s)",
7480 pp->arg[arg].type.name);
7482 if (pp->arg[arg].reg != NULL) {
7483 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7487 for (; j < g_func_pp->argc; j++)
7488 if (g_func_pp->arg[j].reg == NULL)
7490 fprintf(fout, "%sa%d", cast, j + 1);
7495 for (arg = 0; arg < pp->argc; arg++) {
7497 fprintf(fout, ", ");
7500 if (pp->arg[arg].type.is_ptr)
7501 snprintf(cast, sizeof(cast), "(%s)",
7502 pp->arg[arg].type.name);
7504 if (pp->arg[arg].reg != NULL) {
7505 if (pp->arg[arg].type.is_retreg)
7506 fprintf(fout, "&%s", pp->arg[arg].reg);
7507 else if (IS(pp->arg[arg].reg, "ebp")
7508 && g_bp_frame && !(po->flags & OPF_EBP_S))
7510 // rare special case
7511 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
7512 strcat(g_comment, " bp_ref");
7515 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7520 tmp_op = pp->arg[arg].datap;
7522 ferr(po, "parsed_op missing for arg%d\n", arg);
7524 if (tmp_op->flags & OPF_VAPUSH) {
7525 fprintf(fout, "ap");
7527 else if (tmp_op->op == OP_FST) {
7528 fprintf(fout, "fs_%d", tmp_op->p_argnum);
7529 if (tmp_op->operand[0].lmod == OPLM_QWORD)
7532 else if (pp->arg[arg].type.is_64bit) {
7533 ferr_assert(po, tmp_op->p_argpass == 0);
7534 ferr_assert(po, !pp->arg[arg].is_saved);
7535 ferr_assert(po, !pp->arg[arg].type.is_float);
7536 ferr_assert(po, cast[0] == 0);
7537 out_src_opr(buf1, sizeof(buf1),
7538 tmp_op, &tmp_op->operand[0], cast, 0);
7539 tmp_op = pp->arg[++arg].datap;
7540 ferr_assert(po, tmp_op != NULL);
7541 out_src_opr(buf2, sizeof(buf2),
7542 tmp_op, &tmp_op->operand[0], cast, 0);
7543 fprintf(fout, "((u64)(%s) << 32) | (%s)",
7546 else if (tmp_op->p_argpass != 0) {
7547 ferr_assert(po, !pp->arg[arg].type.is_float);
7548 fprintf(fout, "a%d", tmp_op->p_argpass);
7550 else if (pp->arg[arg].is_saved) {
7551 ferr_assert(po, tmp_op->p_argnum > 0);
7552 ferr_assert(po, !pp->arg[arg].type.is_float);
7553 fprintf(fout, "%s%s", cast,
7554 saved_arg_name(buf1, sizeof(buf1),
7555 tmp_op->p_arggrp, tmp_op->p_argnum));
7557 else if (pp->arg[arg].type.is_float) {
7558 ferr_assert(po, !pp->arg[arg].type.is_64bit);
7560 out_src_opr_float(buf1, sizeof(buf1),
7561 tmp_op, &tmp_op->operand[0], need_float_stack));
7565 out_src_opr(buf1, sizeof(buf1),
7566 tmp_op, &tmp_op->operand[0], cast, 0));
7570 fprintf(fout, ");");
7572 if (strstr(pp->ret_type.name, "int64")) {
7573 fprintf(fout, "\n");
7574 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7575 fprintf(fout, "%seax = tmp64;", buf3);
7578 if (pp->is_unresolved) {
7579 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
7581 strcat(g_comment, buf2);
7584 if (po->flags & OPF_TAIL) {
7586 if (i == opcnt - 1 || pp->is_noreturn)
7588 else if (IS(pp->ret_type.name, "void"))
7590 else if (!(regmask_ret & (1 << xAX)))
7592 // else already handled as 'return f()'
7595 fprintf(fout, "\n%sreturn;", buf3);
7596 strcat(g_comment, " ^ tailcall");
7599 strcat(g_comment, " tailcall");
7601 if ((regmask_ret & (1 << xAX))
7602 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7604 ferr(po, "int func -> void func tailcall?\n");
7607 if (pp->is_noreturn)
7608 strcat(g_comment, " noreturn");
7609 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7610 strcat(g_comment, " argframe");
7611 if (po->flags & OPF_CC)
7612 strcat(g_comment, " cond");
7614 if (po->flags & OPF_CC)
7615 fprintf(fout, "\n }");
7617 delayed_flag_op = NULL;
7618 last_arith_dst = NULL;
7622 if (g_func_pp->is_vararg)
7623 fprintf(fout, " va_end(ap);\n");
7624 if (g_func_pp->has_retreg) {
7625 for (arg = 0; arg < g_func_pp->argc; arg++)
7626 if (g_func_pp->arg[arg].type.is_retreg)
7627 fprintf(fout, " *r_%s = %s;\n",
7628 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7631 if (regmask_ret & mxST0) {
7632 fprintf(fout, " return %s;", float_st0);
7634 else if (!(regmask_ret & mxAX)) {
7635 if (i != opcnt - 1 || label_pending)
7636 fprintf(fout, " return;");
7638 else if (g_func_pp->ret_type.is_ptr) {
7639 fprintf(fout, " return (%s)eax;",
7640 g_func_pp->ret_type.name);
7642 else if (IS(g_func_pp->ret_type.name, "__int64"))
7643 fprintf(fout, " return ((u64)edx << 32) | eax;");
7645 fprintf(fout, " return eax;");
7647 last_arith_dst = NULL;
7648 delayed_flag_op = NULL;
7652 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7653 if (po->p_argnum != 0) {
7654 // special case - saved func arg
7655 fprintf(fout, " %s = %s;",
7656 saved_arg_name(buf2, sizeof(buf2),
7657 po->p_arggrp, po->p_argnum), buf1);
7660 else if (po->flags & OPF_RSAVE) {
7661 fprintf(fout, " s_%s = %s;", buf1, buf1);
7664 else if (po->flags & OPF_PPUSH) {
7666 ferr_assert(po, tmp_op != NULL);
7667 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7668 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7671 else if (g_func_pp->is_userstack) {
7672 fprintf(fout, " *(--esp) = %s;", buf1);
7675 if (!(g_ida_func_attr & IDAFA_NORETURN))
7676 ferr(po, "stray push encountered\n");
7681 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7682 if (po->flags & OPF_RSAVE) {
7683 fprintf(fout, " %s = s_%s;", buf1, buf1);
7686 else if (po->flags & OPF_PPUSH) {
7687 // push/pop graph / non-const
7688 ferr_assert(po, po->datap == NULL);
7689 fprintf(fout, " %s = pp_%s;", buf1, buf1);
7692 else if (po->datap != NULL) {
7695 fprintf(fout, " %s = %s;", buf1,
7696 out_src_opr(buf2, sizeof(buf2),
7697 tmp_op, &tmp_op->operand[0],
7698 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7701 else if (g_func_pp->is_userstack) {
7702 fprintf(fout, " %s = *esp++;", buf1);
7706 ferr(po, "stray pop encountered\n");
7716 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7717 fprintf(fout, " tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
7718 po->op == OPP_ALLSHL ? "<<" : ">>");
7719 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
7720 strcat(g_comment, po->op == OPP_ALLSHL
7721 ? " allshl" : " allshr");
7726 if (need_float_stack) {
7727 out_src_opr_float(buf1, sizeof(buf1),
7728 po, &po->operand[0], 1);
7729 if (po->regmask_src & mxSTa) {
7730 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7734 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
7737 if (po->flags & OPF_FSHIFT)
7738 fprintf(fout, " f_st1 = f_st0;");
7739 if (po->operand[0].type == OPT_REG
7740 && po->operand[0].reg == xST0)
7742 strcat(g_comment, " fld st");
7745 fprintf(fout, " f_st0 = %s;",
7746 out_src_opr_float(buf1, sizeof(buf1),
7747 po, &po->operand[0], 0));
7749 strcat(g_comment, " fld");
7753 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7754 lmod_cast(po, po->operand[0].lmod, 1), 0);
7755 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7756 if (need_float_stack) {
7757 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
7760 if (po->flags & OPF_FSHIFT)
7761 fprintf(fout, " f_st1 = f_st0;");
7762 fprintf(fout, " f_st0 = %s;", buf2);
7764 strcat(g_comment, " fild");
7768 if (need_float_stack)
7769 fprintf(fout, " f_st[--f_stp & 7] = ");
7771 if (po->flags & OPF_FSHIFT)
7772 fprintf(fout, " f_st1 = f_st0;");
7773 fprintf(fout, " f_st0 = ");
7775 switch (po->operand[0].val) {
7776 case X87_CONST_1: fprintf(fout, "1.0;"); break;
7777 case X87_CONST_L2T: fprintf(fout, "3.321928094887362;"); break;
7778 case X87_CONST_L2E: fprintf(fout, "M_LOG2E;"); break;
7779 case X87_CONST_PI: fprintf(fout, "M_PI;"); break;
7780 case X87_CONST_LG2: fprintf(fout, "0.301029995663981;"); break;
7781 case X87_CONST_LN2: fprintf(fout, "M_LN2;"); break;
7782 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
7783 default: ferr_assert(po, 0); break;
7788 if (po->flags & OPF_FARG) {
7789 // store to stack as func arg
7790 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7794 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7796 dead_dst = po->operand[0].type == OPT_REG
7797 && po->operand[0].reg == xST0;
7800 fprintf(fout, " %s = %s;", buf1, float_st0);
7801 if (po->flags & OPF_FSHIFT) {
7802 if (need_float_stack)
7803 fprintf(fout, " f_stp++;");
7805 fprintf(fout, " f_st0 = f_st1;");
7807 if (dead_dst && !(po->flags & OPF_FSHIFT))
7810 strcat(g_comment, " fst");
7814 fprintf(fout, " %s = %s%s;",
7815 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7816 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7817 if (po->flags & OPF_FSHIFT) {
7818 if (need_float_stack)
7819 fprintf(fout, " f_stp++;");
7821 fprintf(fout, " f_st0 = f_st1;");
7823 strcat(g_comment, " fist");
7830 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7832 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7834 dead_dst = (po->flags & OPF_FPOP)
7835 && po->operand[0].type == OPT_REG
7836 && po->operand[0].reg == xST0;
7838 case OP_FADD: j = '+'; break;
7839 case OP_FDIV: j = '/'; break;
7840 case OP_FMUL: j = '*'; break;
7841 case OP_FSUB: j = '-'; break;
7842 default: j = 'x'; break;
7844 if (need_float_stack) {
7846 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7847 if (po->flags & OPF_FSHIFT)
7848 fprintf(fout, " f_stp++;");
7851 if (po->flags & OPF_FSHIFT) {
7852 // note: assumes only 2 regs handled
7854 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
7856 fprintf(fout, " f_st0 = f_st1;");
7859 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7861 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7866 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7868 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7870 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
7872 dead_dst = (po->flags & OPF_FPOP)
7873 && po->operand[0].type == OPT_REG
7874 && po->operand[0].reg == xST0;
7875 j = po->op == OP_FDIVR ? '/' : '-';
7876 if (need_float_stack) {
7878 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7879 if (po->flags & OPF_FSHIFT)
7880 fprintf(fout, " f_stp++;");
7883 if (po->flags & OPF_FSHIFT) {
7885 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
7887 fprintf(fout, " f_st0 = f_st1;");
7890 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7892 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7900 case OP_FIADD: j = '+'; break;
7901 case OP_FIDIV: j = '/'; break;
7902 case OP_FIMUL: j = '*'; break;
7903 case OP_FISUB: j = '-'; break;
7904 default: j = 'x'; break;
7906 fprintf(fout, " %s %c= (%s)%s;", float_st0,
7908 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7909 lmod_cast(po, po->operand[0].lmod, 1), 0));
7914 fprintf(fout, " %s = %s %c %s;", float_st0,
7915 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7917 po->op == OP_FIDIVR ? '/' : '-', float_st0);
7922 ferr_assert(po, po->datap != NULL);
7923 mask = (long)po->datap & 0xffff;
7924 z_check = ((long)po->datap >> 16) & 1;
7925 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7927 if (mask == 0x0100 || mask == 0x0500) { // C0 -> <
7928 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
7931 else if (mask == 0x4000 || mask == 0x4400) { // C3 -> =
7932 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
7935 else if (mask == 0x4100) { // C3, C0
7937 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
7939 strcat(g_comment, " z_chk_det");
7942 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
7943 "(%s < %s ? 0x0100 : 0);",
7944 float_st0, buf1, float_st0, buf1);
7948 ferr(po, "unhandled sw mask: %x\n", mask);
7949 if (po->flags & OPF_FSHIFT) {
7950 if (need_float_stack) {
7951 if (po->flags & OPF_FPOPP)
7952 fprintf(fout, " f_stp += 2;");
7954 fprintf(fout, " f_stp++;");
7957 ferr_assert(po, !(po->flags & OPF_FPOPP));
7958 fprintf(fout, " f_st0 = f_st1;");
7965 fprintf(fout, " %s = f_sw;",
7966 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7970 fprintf(fout, " %s = -%s;", float_st0, float_st0);
7974 fprintf(fout, " %s = cos%s(%s);", float_st0,
7975 need_double ? "" : "f", float_st0);
7979 if (need_float_stack) {
7980 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
7981 need_double ? "" : "f", float_st1, float_st0);
7982 fprintf(fout, " f_stp++;");
7985 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
7986 need_double ? "" : "f");
7991 if (need_float_stack) {
7992 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
7993 float_st1, need_double ? "" : "f", float_st0);
7994 fprintf(fout, " f_stp++;");
7997 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
7998 need_double ? "" : "f");
8000 strcat(g_comment, " fyl2x");
8004 fprintf(fout, " %s = sin%s(%s);", float_st0,
8005 need_double ? "" : "f", float_st0);
8009 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
8010 need_double ? "" : "f", float_st0);
8014 dead_dst = po->operand[0].type == OPT_REG
8015 && po->operand[0].reg == xST0;
8017 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8019 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
8020 float_st0, float_st0, buf1, buf1);
8021 strcat(g_comment, " fxch");
8028 ferr_assert(po, po->flags & OPF_32BIT);
8029 fprintf(fout, " eax = (s32)%s;", float_st0);
8030 if (po->flags & OPF_FSHIFT) {
8031 if (need_float_stack)
8032 fprintf(fout, " f_stp++;");
8034 fprintf(fout, " f_st0 = f_st1;");
8036 strcat(g_comment, " ftol");
8040 if (need_float_stack) {
8041 fprintf(fout, " %s = pow%s(%s, %s);", float_st1,
8042 need_double ? "" : "f", float_st1, float_st0);
8043 fprintf(fout, " f_stp++;");
8046 fprintf(fout, " f_st0 = pow%s(f_st1, f_st0);",
8047 need_double ? "" : "f");
8049 strcat(g_comment, " CIpow");
8053 fprintf(fout, " do_skip_code_abort();");
8058 fprintf(fout, " do_emms();");
8063 ferr(po, "unhandled op type %d, flags %x\n",
8068 if (g_comment[0] != 0) {
8069 char *p = g_comment;
8070 while (my_isblank(*p))
8072 fprintf(fout, " // %s", p);
8077 fprintf(fout, "\n");
8079 // some sanity checking
8080 if (po->flags & OPF_REP) {
8081 if (po->op != OP_STOS && po->op != OP_MOVS
8082 && po->op != OP_CMPS && po->op != OP_SCAS)
8083 ferr(po, "unexpected rep\n");
8084 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
8085 && (po->op == OP_CMPS || po->op == OP_SCAS))
8086 ferr(po, "cmps/scas with plain rep\n");
8088 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
8089 && po->op != OP_CMPS && po->op != OP_SCAS)
8090 ferr(po, "unexpected repz/repnz\n");
8093 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
8095 // see is delayed flag stuff is still valid
8096 if (delayed_flag_op != NULL && delayed_flag_op != po) {
8097 if (is_any_opr_modified(delayed_flag_op, po, 0))
8098 delayed_flag_op = NULL;
8101 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
8102 if (is_opr_modified(last_arith_dst, po))
8103 last_arith_dst = NULL;
8110 if (g_stack_fsz && !g_stack_frame_used)
8111 fprintf(fout, " (void)sf;\n");
8113 fprintf(fout, "}\n\n");
8115 gen_x_cleanup(opcnt);
8118 static void gen_x_cleanup(int opcnt)
8122 for (i = 0; i < opcnt; i++) {
8123 struct label_ref *lr, *lr_del;
8125 lr = g_label_refs[i].next;
8126 while (lr != NULL) {
8131 g_label_refs[i].i = -1;
8132 g_label_refs[i].next = NULL;
8134 if (ops[i].op == OP_CALL) {
8136 proto_release(ops[i].pp);
8142 struct func_proto_dep;
8144 struct func_prototype {
8148 int regmask_dep; // likely register args
8149 int regmask_use; // used registers
8150 int has_ret:3; // -1, 0, 1: unresolved, no, yes
8151 unsigned int has_ret64:1;
8152 unsigned int dep_resolved:1;
8153 unsigned int is_stdcall:1;
8154 unsigned int eax_pass:1; // returns without touching eax
8155 struct func_proto_dep *dep_func;
8157 const struct parsed_proto *pp; // seed pp, if any
8160 struct func_proto_dep {
8162 struct func_prototype *proto;
8163 int regmask_live; // .. at the time of call
8164 unsigned int ret_dep:1; // return from this is caller's return
8165 unsigned int has_ret:1; // found from eax use after return
8166 unsigned int has_ret64:1;
8169 static struct func_prototype *hg_fp;
8170 static int hg_fp_cnt;
8172 static struct scanned_var {
8174 enum opr_lenmod lmod;
8175 unsigned int is_seeded:1;
8176 unsigned int is_c_str:1;
8177 const struct parsed_proto *pp; // seed pp, if any
8179 static int hg_var_cnt;
8181 static char **hg_refs;
8182 static int hg_ref_cnt;
8184 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8187 static struct func_prototype *hg_fp_add(const char *funcn)
8189 struct func_prototype *fp;
8191 if ((hg_fp_cnt & 0xff) == 0) {
8192 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
8193 my_assert_not(hg_fp, NULL);
8194 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
8197 fp = &hg_fp[hg_fp_cnt];
8198 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
8200 fp->argc_stack = -1;
8206 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
8211 for (i = 0; i < fp->dep_func_cnt; i++)
8212 if (IS(fp->dep_func[i].name, name))
8213 return &fp->dep_func[i];
8218 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
8221 if (hg_fp_find_dep(fp, name))
8224 if ((fp->dep_func_cnt & 0xff) == 0) {
8225 fp->dep_func = realloc(fp->dep_func,
8226 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
8227 my_assert_not(fp->dep_func, NULL);
8228 memset(&fp->dep_func[fp->dep_func_cnt], 0,
8229 sizeof(fp->dep_func[0]) * 0x100);
8231 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
8235 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
8237 const struct func_prototype *p1 = p1_, *p2 = p2_;
8238 return strcmp(p1->name, p2->name);
8242 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
8244 const struct func_prototype *p1 = p1_, *p2 = p2_;
8245 return p1->id - p2->id;
8249 static void hg_ref_add(const char *name)
8251 if ((hg_ref_cnt & 0xff) == 0) {
8252 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
8253 my_assert_not(hg_refs, NULL);
8254 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
8257 hg_refs[hg_ref_cnt] = strdup(name);
8258 my_assert_not(hg_refs[hg_ref_cnt], NULL);
8262 // recursive register dep pass
8263 // - track saved regs (part 2)
8264 // - try to figure out arg-regs
8265 // - calculate reg deps
8266 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
8267 struct func_prototype *fp, int regmask_save, int regmask_dst,
8268 int *regmask_dep, int *regmask_use, int *has_ret)
8270 struct func_proto_dep *dep;
8271 struct parsed_op *po;
8272 int from_caller = 0;
8277 for (; i < opcnt; i++)
8279 if (cbits[i >> 3] & (1 << (i & 7)))
8281 cbits[i >> 3] |= (1 << (i & 7));
8285 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
8286 if (po->flags & OPF_RMD)
8289 if (po->btj != NULL) {
8291 for (j = 0; j < po->btj->count; j++) {
8292 check_i(po, po->btj->d[j].bt_i);
8293 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
8294 regmask_save, regmask_dst, regmask_dep, regmask_use,
8300 check_i(po, po->bt_i);
8301 if (po->flags & OPF_CJMP) {
8302 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
8303 regmask_save, regmask_dst, regmask_dep, regmask_use,
8312 if (po->flags & OPF_FARG)
8313 /* (just calculate register deps) */;
8314 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
8316 reg = po->operand[0].reg;
8317 ferr_assert(po, reg >= 0);
8319 if (po->flags & OPF_RSAVE) {
8320 regmask_save |= 1 << reg;
8323 if (po->flags & OPF_DONE)
8326 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0, 0);
8328 regmask_save |= 1 << reg;
8329 po->flags |= OPF_RMD;
8330 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, OPF_RMD);
8334 else if (po->flags & OPF_RMD)
8336 else if (po->op == OP_CALL) {
8337 po->regmask_dst |= 1 << xAX;
8339 dep = hg_fp_find_dep(fp, po->operand[0].name);
8341 dep->regmask_live = regmask_save | regmask_dst;
8342 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8343 dep->regmask_live |= 1 << xBP;
8346 else if (po->op == OP_RET) {
8347 if (po->operand_cnt > 0) {
8349 if (fp->argc_stack >= 0
8350 && fp->argc_stack != po->operand[0].val / 4)
8351 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
8352 fp->argc_stack = po->operand[0].val / 4;
8356 if (!fp->eax_pass && (po->flags & OPF_TAIL)) {
8357 if (po->op == OP_CALL) {
8362 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
8365 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
8368 if (ret != 1 && from_caller) {
8369 // unresolved eax - probably void func
8374 if (j >= 0 && ops[j].op == OP_CALL) {
8375 if (ops[j].pp != NULL && !ops[j].pp->is_unresolved) {
8376 int call_has_ret = !IS(ops[j].pp->ret_type.name, "void");
8377 if (ops[j].pp->is_noreturn) {
8378 // could be some fail path
8380 *has_ret = call_has_ret;
8383 *has_ret = call_has_ret;
8386 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
8398 l = regmask_save | regmask_dst;
8399 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8402 l = po->regmask_src & ~l;
8405 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
8406 l, regmask_dst, regmask_save, po->flags);
8409 *regmask_use |= (po->regmask_src | po->regmask_dst)
8411 regmask_dst |= po->regmask_dst;
8413 if (po->flags & OPF_TAIL)
8418 static void gen_hdr(const char *funcn, int opcnt)
8420 unsigned char cbits[MAX_OPS / 8];
8421 const struct parsed_proto *pp_c;
8422 struct parsed_proto *pp;
8423 struct func_prototype *fp;
8424 struct func_proto_dep *dep;
8425 struct parsed_op *po;
8426 int regmask_dummy = 0;
8429 int max_bp_offset = 0;
8434 pp_c = proto_parse(g_fhdr, funcn, 1);
8436 // already in seed, will add to hg_fp later
8439 fp = hg_fp_add(funcn);
8441 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
8442 g_stack_frame_used = 0;
8446 // - resolve all branches
8447 // - parse calls with labels
8448 resolve_branches_parse_calls(opcnt);
8451 // - handle ebp/esp frame, remove ops related to it
8452 scan_prologue_epilogue(opcnt, NULL);
8455 // - remove dead labels
8457 for (i = 0; i < opcnt; i++)
8459 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8465 if (po->flags & (OPF_RMD|OPF_DONE))
8468 if (po->op == OP_CALL) {
8469 if (po->operand[0].type == OPT_LABEL)
8470 hg_fp_add_dep(fp, opr_name(po, 0));
8471 else if (po->pp != NULL)
8472 hg_fp_add_dep(fp, po->pp->name);
8477 // - handle push <const>/pop pairs
8478 for (i = 0; i < opcnt; i++)
8481 if (po->flags & (OPF_RMD|OPF_DONE))
8484 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
8485 scan_for_pop_const(i, opcnt, i + opcnt * 13);
8489 // - process trivial calls
8490 for (i = 0; i < opcnt; i++)
8493 if (po->flags & (OPF_RMD|OPF_DONE))
8496 if (po->op == OP_CALL)
8498 pp = process_call_early(i, opcnt, &j);
8500 if (!(po->flags & OPF_ATAIL))
8501 // since we know the args, try to collect them
8502 if (collect_call_args_early(i, pp, NULL, NULL) != 0)
8508 // commit esp adjust
8509 if (ops[j].op != OP_POP)
8510 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
8512 for (l = 0; l < pp->argc_stack; l++)
8513 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
8517 po->flags |= OPF_DONE;
8523 // - track saved regs (simple)
8525 for (i = 0; i < opcnt; i++)
8528 if (po->flags & (OPF_RMD|OPF_DONE))
8531 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
8532 && po->operand[0].reg != xCX)
8534 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
8536 // regmask_save |= 1 << po->operand[0].reg; // do it later
8537 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
8538 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
8541 else if (po->op == OP_CALL)
8543 pp = process_call(i, opcnt);
8545 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
8546 // since we know the args, collect them
8547 ret = collect_call_args(po, i, pp, ®mask_dummy,
8550 if (!(po->flags & OPF_TAIL)
8551 && po->operand[0].type == OPT_LABEL)
8553 dep = hg_fp_find_dep(fp, opr_name(po, 0));
8554 ferr_assert(po, dep != NULL);
8555 // treat al write as overwrite to avoid many false positives
8556 find_next_read_reg(i + 1, opcnt, xAX, OPLM_BYTE,
8557 i + opcnt * 25, &j);
8560 find_next_read_reg(i + 1, opcnt, xDX, OPLM_BYTE,
8561 i + opcnt * 26, &j);
8562 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j]))
8569 memset(cbits, 0, sizeof(cbits));
8570 regmask_dep = regmask_use = 0;
8573 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0,
8574 ®mask_dep, ®mask_use, &has_ret);
8576 // find unreachable code - must be fixed in IDA
8577 for (i = 0; i < opcnt; i++)
8579 if (cbits[i >> 3] & (1 << (i & 7)))
8582 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
8583 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
8585 // the compiler sometimes still generates code after
8586 // noreturn OS functions
8589 if (!(ops[i].flags & OPF_RMD)
8590 && ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
8592 ferr(&ops[i], "unreachable code\n");
8596 for (i = 0; i < g_eqcnt; i++) {
8597 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
8598 max_bp_offset = g_eqs[i].offset;
8601 if (fp->argc_stack < 0) {
8602 max_bp_offset = (max_bp_offset + 3) & ~3;
8603 fp->argc_stack = max_bp_offset / 4;
8604 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
8608 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
8609 fp->regmask_use = regmask_use;
8610 fp->has_ret = has_ret;
8612 printf("// has_ret %d, regmask_dep %x\n",
8613 fp->has_ret, fp->regmask_dep);
8614 output_hdr_fp(stdout, fp, 1);
8615 if (IS(funcn, "sub_10007F72")) exit(1);
8618 gen_x_cleanup(opcnt);
8621 static void hg_fp_resolve_deps(struct func_prototype *fp)
8623 struct func_prototype fp_s;
8624 struct func_proto_dep *dep;
8628 // this thing is recursive, so mark first..
8629 fp->dep_resolved = 1;
8631 for (i = 0; i < fp->dep_func_cnt; i++) {
8632 dep = &fp->dep_func[i];
8634 strcpy(fp_s.name, dep->name);
8635 dep->proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8636 sizeof(hg_fp[0]), hg_fp_cmp_name);
8637 if (dep->proto != NULL) {
8638 if (!dep->proto->dep_resolved)
8639 hg_fp_resolve_deps(dep->proto);
8641 regmask_dep = ~dep->regmask_live
8642 & dep->proto->regmask_dep;
8643 fp->regmask_dep |= regmask_dep;
8644 // printf("dep %s %s |= %x\n", fp->name,
8645 // fp->dep_func[i].name, regmask_dep);
8647 if (dep->has_ret && (dep->proto->regmask_use & mxAX))
8648 dep->proto->has_ret = 1;
8649 if (dep->has_ret64 && (dep->proto->regmask_use & mxDX))
8650 dep->proto->has_ret64 = 1;
8651 if (fp->has_ret == -1 && dep->ret_dep)
8652 fp->has_ret = dep->proto->has_ret;
8657 // make all thiscall/edx arg functions referenced from .data fastcall
8658 static void do_func_refs_from_data(void)
8660 struct func_prototype *fp, fp_s;
8663 for (i = 0; i < hg_ref_cnt; i++) {
8664 strcpy(fp_s.name, hg_refs[i]);
8665 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8666 sizeof(hg_fp[0]), hg_fp_cmp_name);
8670 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
8671 fp->regmask_dep |= mxCX | mxDX;
8675 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8678 const struct parsed_proto *pp;
8679 char *p, namebuf[NAMELEN];
8685 for (; count > 0; count--, fp++) {
8686 if (fp->has_ret == -1)
8687 fprintf(fout, "// ret unresolved\n");
8689 fprintf(fout, "// dep:");
8690 for (j = 0; j < fp->dep_func_cnt; j++) {
8691 fprintf(fout, " %s/", fp->dep_func[j].name);
8692 if (fp->dep_func[j].proto != NULL)
8693 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8694 fp->dep_func[j].proto->has_ret);
8696 fprintf(fout, "\n");
8699 p = strchr(fp->name, '@');
8701 memcpy(namebuf, fp->name, p - fp->name);
8702 namebuf[p - fp->name] = 0;
8710 pp = proto_parse(g_fhdr, name, 1);
8711 if (pp != NULL && pp->is_include)
8714 if (fp->pp != NULL) {
8715 // part of seed, output later
8719 regmask_dep = fp->regmask_dep;
8720 argc_normal = fp->argc_stack;
8722 fprintf(fout, "%-5s",
8723 fp->pp ? fp->pp->ret_type.name :
8724 fp->has_ret64 ? "__int64" :
8725 fp->has_ret ? "int" : "void");
8726 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
8727 && (regmask_dep & ~mxCX) == 0)
8729 fprintf(fout, "/*__thiscall*/ ");
8733 else if ((regmask_dep == (mxCX | mxDX)
8734 && (fp->is_stdcall || fp->argc_stack == 0))
8735 || (regmask_dep == mxCX && fp->argc_stack == 0))
8737 fprintf(fout, " __fastcall ");
8738 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8744 else if (regmask_dep && !fp->is_stdcall) {
8745 fprintf(fout, "/*__usercall*/ ");
8747 else if (regmask_dep) {
8748 fprintf(fout, "/*__userpurge*/ ");
8750 else if (fp->is_stdcall)
8751 fprintf(fout, " __stdcall ");
8753 fprintf(fout, " __cdecl ");
8755 fprintf(fout, "%s(", name);
8758 for (j = 0; j < xSP; j++) {
8759 if (regmask_dep & (1 << j)) {
8762 fprintf(fout, ", ");
8764 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8766 fprintf(fout, "int");
8767 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
8771 for (j = 0; j < argc_normal; j++) {
8774 fprintf(fout, ", ");
8775 if (fp->pp != NULL) {
8776 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8777 if (!fp->pp->arg[arg - 1].type.is_ptr)
8781 fprintf(fout, "int ");
8782 fprintf(fout, "a%d", arg);
8785 fprintf(fout, ");\n");
8789 static void output_hdr(FILE *fout)
8791 static const char *lmod_c_names[] = {
8792 [OPLM_UNSPEC] = "???",
8793 [OPLM_BYTE] = "uint8_t",
8794 [OPLM_WORD] = "uint16_t",
8795 [OPLM_DWORD] = "uint32_t",
8796 [OPLM_QWORD] = "uint64_t",
8798 const struct scanned_var *var;
8799 struct func_prototype *fp;
8800 char line[256] = { 0, };
8804 // add stuff from headers
8805 for (i = 0; i < pp_cache_size; i++) {
8806 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
8807 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
8809 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
8810 fp = hg_fp_add(name);
8811 fp->pp = &pp_cache[i];
8812 fp->argc_stack = fp->pp->argc_stack;
8813 fp->is_stdcall = fp->pp->is_stdcall;
8814 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
8815 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
8819 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
8820 for (i = 0; i < hg_fp_cnt; i++)
8821 hg_fp_resolve_deps(&hg_fp[i]);
8823 // adjust functions referenced from data segment
8824 do_func_refs_from_data();
8826 // final adjustments
8827 for (i = 0; i < hg_fp_cnt; i++) {
8828 if (hg_fp[i].eax_pass && (hg_fp[i].regmask_dep & mxAX))
8829 hg_fp[i].has_ret = 1;
8832 // note: messes up .proto ptr, don't use
8833 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
8836 for (i = 0; i < hg_var_cnt; i++) {
8839 if (var->pp != NULL)
8842 else if (var->is_c_str)
8843 fprintf(fout, "extern %-8s %s[];", "char", var->name);
8845 fprintf(fout, "extern %-8s %s;",
8846 lmod_c_names[var->lmod], var->name);
8849 fprintf(fout, " // seeded");
8850 fprintf(fout, "\n");
8853 fprintf(fout, "\n");
8855 // output function prototypes
8856 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
8859 fprintf(fout, "\n// - seed -\n");
8862 while (fgets(line, sizeof(line), g_fhdr))
8863 fwrite(line, 1, strlen(line), fout);
8866 // '=' needs special treatment
8868 static char *next_word_s(char *w, size_t wsize, char *s)
8875 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
8877 for (i = 1; i < wsize - 1; i++) {
8879 printf("warning: missing closing quote: \"%s\"\n", s);
8888 for (; i < wsize - 1; i++) {
8889 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
8895 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
8896 printf("warning: '%s' truncated\n", w);
8901 static int cmpstringp(const void *p1, const void *p2)
8903 return strcmp(*(char * const *)p1, *(char * const *)p2);
8906 static int is_xref_needed(char *p, char **rlist, int rlist_len)
8911 if (strstr(p, "..."))
8912 // unable to determine, assume needed
8915 if (*p == '.') // .text, .data, ...
8916 // ref from other data or non-function -> no
8919 p2 = strpbrk(p, "+:\r\n\x18");
8922 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8923 // referenced from removed code
8929 static int ida_xrefs_show_need(FILE *fasm, char *p,
8930 char **rlist, int rlist_len)
8936 p = strrchr(p, ';');
8937 if (p != NULL && *p == ';') {
8938 if (IS_START(p + 2, "sctref"))
8940 if (IS_START(p + 2, "DATA XREF: ")) {
8942 if (is_xref_needed(p, rlist, rlist_len))
8950 if (!my_fgets(line, sizeof(line), fasm))
8952 // non-first line is always indented
8953 if (!my_isblank(line[0]))
8956 // should be no content, just comment
8961 p = strrchr(p, ';');
8964 if (IS_START(p, "sctref")) {
8969 // it's printed once, but no harm to check again
8970 if (IS_START(p, "DATA XREF: "))
8973 if (is_xref_needed(p, rlist, rlist_len)) {
8978 fseek(fasm, pos, SEEK_SET);
8982 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
8984 struct scanned_var *var;
8985 char line[256] = { 0, };
8994 // skip to next data section
8995 while (my_fgets(line, sizeof(line), fasm))
9000 if (*p == 0 || *p == ';')
9003 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
9004 if (*p == 0 || *p == ';')
9007 if (*p != 's' || !IS_START(p, "segment para public"))
9013 if (p == NULL || !IS_START(p, "segment para public"))
9017 if (!IS_START(p, "'DATA'"))
9021 while (my_fgets(line, sizeof(line), fasm))
9026 no_identifier = my_isblank(*p);
9029 if (*p == 0 || *p == ';')
9032 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9033 words[wordc][0] = 0;
9034 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9035 if (*p == 0 || *p == ';') {
9041 if (wordc == 2 && IS(words[1], "ends"))
9046 if (no_identifier) {
9047 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
9048 hg_ref_add(words[2]);
9052 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
9053 // when this starts, we don't need anything from this section
9057 // check refs comment(s)
9058 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
9061 if ((hg_var_cnt & 0xff) == 0) {
9062 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
9063 * (hg_var_cnt + 0x100));
9064 my_assert_not(hg_vars, NULL);
9065 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
9068 var = &hg_vars[hg_var_cnt++];
9069 snprintf(var->name, sizeof(var->name), "%s", words[0]);
9071 // maybe already in seed header?
9072 var->pp = proto_parse(g_fhdr, var->name, 1);
9073 if (var->pp != NULL) {
9074 if (var->pp->is_fptr) {
9075 var->lmod = OPLM_DWORD;
9078 else if (var->pp->is_func)
9080 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
9081 aerr("unhandled C type '%s' for '%s'\n",
9082 var->pp->type.name, var->name);
9088 if (IS(words[1], "dd")) {
9089 var->lmod = OPLM_DWORD;
9090 if (wordc >= 4 && IS(words[2], "offset"))
9091 hg_ref_add(words[3]);
9093 else if (IS(words[1], "dw"))
9094 var->lmod = OPLM_WORD;
9095 else if (IS(words[1], "db")) {
9096 var->lmod = OPLM_BYTE;
9097 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
9098 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
9102 else if (IS(words[1], "dq"))
9103 var->lmod = OPLM_QWORD;
9104 //else if (IS(words[1], "dt"))
9106 aerr("type '%s' not known\n", words[1]);
9114 static void set_label(int i, const char *name)
9120 p = strchr(name, ':');
9124 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
9125 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
9126 g_labels[i] = realloc(g_labels[i], len + 1);
9127 my_assert_not(g_labels[i], NULL);
9128 memcpy(g_labels[i], name, len);
9129 g_labels[i][len] = 0;
9138 static struct chunk_item *func_chunks;
9139 static int func_chunk_cnt;
9140 static int func_chunk_alloc;
9142 static void add_func_chunk(FILE *fasm, const char *name, int line)
9144 if (func_chunk_cnt >= func_chunk_alloc) {
9145 func_chunk_alloc *= 2;
9146 func_chunks = realloc(func_chunks,
9147 func_chunk_alloc * sizeof(func_chunks[0]));
9148 my_assert_not(func_chunks, NULL);
9150 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
9151 func_chunks[func_chunk_cnt].name = strdup(name);
9152 func_chunks[func_chunk_cnt].asmln = line;
9156 static int cmp_chunks(const void *p1, const void *p2)
9158 const struct chunk_item *c1 = p1, *c2 = p2;
9159 return strcmp(c1->name, c2->name);
9162 static void scan_ahead_for_chunks(FILE *fasm)
9172 oldpos = ftell(fasm);
9175 while (my_fgets(line, sizeof(line), fasm))
9186 // get rid of random tabs
9187 for (i = 0; line[i] != 0; i++)
9188 if (line[i] == '\t')
9191 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9194 next_word(words[0], sizeof(words[0]), p);
9195 if (words[0][0] == 0)
9196 aerr("missing name for func chunk?\n");
9198 add_func_chunk(fasm, words[0], asmln);
9200 else if (IS_START(p, "; sctend"))
9206 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9207 words[wordc][0] = 0;
9208 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9209 if (*p == 0 || *p == ';') {
9215 if (wordc == 2 && IS(words[1], "ends"))
9219 fseek(fasm, oldpos, SEEK_SET);
9223 int main(int argc, char *argv[])
9225 FILE *fout, *fasm, *frlist;
9226 struct parsed_data *pd = NULL;
9228 char **rlist = NULL;
9230 int rlist_alloc = 0;
9231 int func_chunks_used = 0;
9232 int func_chunks_sorted = 0;
9233 int func_chunk_i = -1;
9234 long func_chunk_ret = 0;
9235 int func_chunk_ret_ln = 0;
9236 int scanned_ahead = 0;
9238 char words[20][256];
9239 enum opr_lenmod lmod;
9240 char *sctproto = NULL;
9242 int pending_endp = 0;
9244 int skip_code_end = 0;
9245 int skip_warned = 0;
9258 for (arg = 1; arg < argc; arg++) {
9259 if (IS(argv[arg], "-v"))
9261 else if (IS(argv[arg], "-rf"))
9262 g_allow_regfunc = 1;
9263 else if (IS(argv[arg], "-uc"))
9264 g_allow_user_icall = 1;
9265 else if (IS(argv[arg], "-m"))
9267 else if (IS(argv[arg], "-hdr"))
9268 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
9273 if (argc < arg + 3) {
9274 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
9275 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
9277 " -hdr - header generation mode\n"
9278 " -rf - allow unannotated indirect calls\n"
9279 " -uc - allow ind. calls/refs to __usercall\n"
9280 " -m - allow multiple .text sections\n"
9281 "[rlist] is a file with function names to skip,"
9289 asmfn = argv[arg++];
9290 fasm = fopen(asmfn, "r");
9291 my_assert_not(fasm, NULL);
9293 hdrfn = argv[arg++];
9294 g_fhdr = fopen(hdrfn, "r");
9295 my_assert_not(g_fhdr, NULL);
9298 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
9299 my_assert_not(rlist, NULL);
9300 // needs special handling..
9301 rlist[rlist_len++] = "__alloca_probe";
9303 func_chunk_alloc = 32;
9304 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
9305 my_assert_not(func_chunks, NULL);
9307 memset(words, 0, sizeof(words));
9309 for (; arg < argc; arg++) {
9312 frlist = fopen(argv[arg], "r");
9313 my_assert_not(frlist, NULL);
9315 while (my_fgets(line, sizeof(line), frlist)) {
9317 if (*p == 0 || *p == ';')
9320 if (IS_START(p, "#if 0")
9321 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
9325 else if (IS_START(p, "#endif"))
9332 p = next_word(words[0], sizeof(words[0]), p);
9333 if (words[0][0] == 0)
9336 if (rlist_len >= rlist_alloc) {
9337 rlist_alloc = rlist_alloc * 2 + 64;
9338 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
9339 my_assert_not(rlist, NULL);
9341 rlist[rlist_len++] = strdup(words[0]);
9349 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
9351 fout = fopen(argv[arg_out], "w");
9352 my_assert_not(fout, NULL);
9355 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
9356 my_assert_not(g_eqs, NULL);
9358 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
9359 g_label_refs[i].i = -1;
9360 g_label_refs[i].next = NULL;
9364 scan_variables(fasm, rlist, rlist_len);
9366 while (my_fgets(line, sizeof(line), fasm))
9375 // get rid of random tabs
9376 for (i = 0; line[i] != 0; i++)
9377 if (line[i] == '\t')
9382 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
9383 goto do_pending_endp; // eww..
9385 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
9387 static const char *attrs[] = {
9396 // parse IDA's attribute-list comment
9397 g_ida_func_attr = 0;
9400 for (; *p != 0; p = sskip(p)) {
9401 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9402 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9403 g_ida_func_attr |= 1 << i;
9404 p += strlen(attrs[i]);
9408 if (i == ARRAY_SIZE(attrs)) {
9409 anote("unparsed IDA attr: %s\n", p);
9412 if (IS(attrs[i], "fpd=")) {
9413 p = next_word(words[0], sizeof(words[0]), p);
9418 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
9420 static const char *attrs[] = {
9427 // parse manual attribute-list comment
9428 g_sct_func_attr = 0;
9431 for (; *p != 0; p = sskip(p)) {
9432 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9433 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9434 g_sct_func_attr |= 1 << i;
9435 p += strlen(attrs[i]);
9442 // clear_sf=start,len (in dwords)
9443 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
9444 &g_stack_clear_len, &j);
9446 // clear_regmask=<mask>
9447 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
9449 // rm_regmask=<mask>
9450 ret = sscanf(p, "=%x%n", &g_regmask_rm, &j) + 1;
9452 anote("unparsed attr value: %s\n", p);
9457 else if (i == ARRAY_SIZE(attrs)) {
9458 anote("unparsed sct attr: %s\n", p);
9463 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9466 next_word(words[0], sizeof(words[0]), p);
9467 if (words[0][0] == 0)
9468 aerr("missing name for func chunk?\n");
9470 if (!scanned_ahead) {
9471 add_func_chunk(fasm, words[0], asmln);
9472 func_chunks_sorted = 0;
9475 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
9477 if (func_chunk_i >= 0) {
9478 if (func_chunk_i < func_chunk_cnt
9479 && IS(func_chunks[func_chunk_i].name, g_func))
9481 // move on to next chunk
9482 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9484 aerr("seek failed for '%s' chunk #%d\n",
9485 g_func, func_chunk_i);
9486 asmln = func_chunks[func_chunk_i].asmln;
9490 if (func_chunk_ret == 0)
9491 aerr("no return from chunk?\n");
9492 fseek(fasm, func_chunk_ret, SEEK_SET);
9493 asmln = func_chunk_ret_ln;
9499 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
9500 func_chunks_used = 1;
9502 if (IS_START(g_func, "sub_")) {
9503 unsigned long addr = strtoul(p, NULL, 16);
9504 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
9505 if (addr > f_addr && !scanned_ahead) {
9506 //anote("scan_ahead caused by '%s', addr %lx\n",
9508 scan_ahead_for_chunks(fasm);
9510 func_chunks_sorted = 0;
9518 for (i = wordc; i < ARRAY_SIZE(words); i++)
9520 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9521 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9522 if (*p == 0 || *p == ';') {
9527 if (*p != 0 && *p != ';')
9528 aerr("too many words\n");
9530 if (skip_code_end) {
9535 // allow asm patches in comments
9537 // skip IDA's forced non-removable comment
9538 if (!IS_START(p, "; sct") && (p2 = strchr(p + 1, ';')))
9541 if (*p == ';' && IS_START(p, "; sct")) {
9542 if (IS_START(p, "; sctpatch:")) {
9544 if (*p == 0 || *p == ';')
9546 goto parse_words; // lame
9548 if (IS_START(p, "; sctproto:")) {
9549 sctproto = strdup(p + 11);
9551 else if (IS_START(p, "; sctend")) {
9556 else if (IS_START(p, "; sctskip_start")) {
9557 if (in_func && !g_skip_func) {
9559 ops[pi].op = OPP_ABORT;
9560 ops[pi].asmln = asmln;
9566 else if (IS_START(p, "; sctskip_end")) {
9574 awarn("wordc == 0?\n");
9578 // don't care about this:
9579 if (words[0][0] == '.'
9580 || IS(words[0], "include")
9581 || IS(words[0], "assume") || IS(words[1], "segment")
9582 || IS(words[0], "align"))
9588 // do delayed endp processing to collect switch jumptables
9590 if (in_func && !g_skip_func && !end && wordc >= 2
9591 && ((words[0][0] == 'd' && words[0][2] == 0)
9592 || (words[1][0] == 'd' && words[1][2] == 0)))
9595 if (words[1][0] == 'd' && words[1][2] == 0) {
9597 if (g_func_pd_cnt >= pd_alloc) {
9598 pd_alloc = pd_alloc * 2 + 16;
9599 g_func_pd = realloc(g_func_pd,
9600 sizeof(g_func_pd[0]) * pd_alloc);
9601 my_assert_not(g_func_pd, NULL);
9603 pd = &g_func_pd[g_func_pd_cnt];
9605 memset(pd, 0, sizeof(*pd));
9606 strcpy(pd->label, words[0]);
9607 pd->type = OPT_CONST;
9608 pd->lmod = lmod_from_directive(words[1]);
9614 anote("skipping alignment byte?\n");
9617 lmod = lmod_from_directive(words[0]);
9618 if (lmod != pd->lmod)
9619 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
9622 if (pd->count_alloc < pd->count + wordc) {
9623 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
9624 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
9625 my_assert_not(pd->d, NULL);
9627 for (; i < wordc; i++) {
9628 if (IS(words[i], "offset")) {
9629 pd->type = OPT_OFFSET;
9632 p = strchr(words[i], ',');
9635 if (pd->type == OPT_OFFSET)
9636 pd->d[pd->count].u.label = strdup(words[i]);
9638 pd->d[pd->count].u.val = parse_number(words[i], 0);
9639 pd->d[pd->count].bt_i = -1;
9645 if (in_func && !g_skip_func) {
9647 gen_hdr(g_func, pi);
9649 gen_func(fout, g_fhdr, g_func, pi);
9654 g_ida_func_attr = 0;
9655 g_sct_func_attr = 0;
9656 g_stack_clear_start = 0;
9657 g_stack_clear_len = 0;
9664 func_chunks_used = 0;
9667 memset(&ops, 0, pi * sizeof(ops[0]));
9672 for (i = 0; i < g_func_pd_cnt; i++) {
9674 if (pd->type == OPT_OFFSET) {
9675 for (j = 0; j < pd->count; j++)
9676 free(pd->d[j].u.label);
9691 if (IS(words[1], "proc")) {
9693 aerr("proc '%s' while in_func '%s'?\n",
9696 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9698 strcpy(g_func, words[0]);
9699 set_label(0, words[0]);
9704 if (IS(words[1], "endp"))
9707 aerr("endp '%s' while not in_func?\n", words[0]);
9708 if (!IS(g_func, words[0]))
9709 aerr("endp '%s' while in_func '%s'?\n",
9712 aerr("endp '%s' while skipping code\n", words[0]);
9714 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
9715 && ops[0].op == OP_JMP && ops[0].operand[0].segment)
9721 if (!g_skip_func && func_chunks_used) {
9722 // start processing chunks
9723 struct chunk_item *ci, key = { g_func, 0 };
9725 func_chunk_ret = ftell(fasm);
9726 func_chunk_ret_ln = asmln;
9727 if (!func_chunks_sorted) {
9728 qsort(func_chunks, func_chunk_cnt,
9729 sizeof(func_chunks[0]), cmp_chunks);
9730 func_chunks_sorted = 1;
9732 ci = bsearch(&key, func_chunks, func_chunk_cnt,
9733 sizeof(func_chunks[0]), cmp_chunks);
9735 aerr("'%s' needs chunks, but none found\n", g_func);
9736 func_chunk_i = ci - func_chunks;
9737 for (; func_chunk_i > 0; func_chunk_i--)
9738 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
9741 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9743 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
9744 asmln = func_chunks[func_chunk_i].asmln;
9752 if (wordc == 2 && IS(words[1], "ends")) {
9756 goto do_pending_endp;
9760 // scan for next text segment
9761 while (my_fgets(line, sizeof(line), fasm)) {
9764 if (*p == 0 || *p == ';')
9767 if (strstr(p, "segment para public 'CODE' use32"))
9774 p = strchr(words[0], ':');
9776 set_label(pi, words[0]);
9780 if (!in_func || g_skip_func || skip_code) {
9781 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
9783 anote("skipping from '%s'\n", g_labels[pi]);
9787 g_labels[pi] = NULL;
9791 if (wordc > 1 && IS(words[1], "="))
9794 aerr("unhandled equ, wc=%d\n", wordc);
9795 if (g_eqcnt >= eq_alloc) {
9797 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
9798 my_assert_not(g_eqs, NULL);
9801 len = strlen(words[0]);
9802 if (len > sizeof(g_eqs[0].name) - 1)
9803 aerr("equ name too long: %d\n", len);
9804 strcpy(g_eqs[g_eqcnt].name, words[0]);
9806 if (!IS(words[3], "ptr"))
9807 aerr("unhandled equ\n");
9808 if (IS(words[2], "dword"))
9809 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
9810 else if (IS(words[2], "word"))
9811 g_eqs[g_eqcnt].lmod = OPLM_WORD;
9812 else if (IS(words[2], "byte"))
9813 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
9814 else if (IS(words[2], "qword"))
9815 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
9817 aerr("bad lmod: '%s'\n", words[2]);
9819 g_eqs[g_eqcnt].offset = parse_number(words[4], 0);
9824 if (pi >= ARRAY_SIZE(ops))
9825 aerr("too many ops\n");
9827 parse_op(&ops[pi], words, wordc);
9829 ops[pi].datap = sctproto;
9844 // vim:ts=2:shiftwidth=2:expandtab