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), /* 32bit division */
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),
282 SCTFA_CLEAR_SF = (1 << 0), // clear stack frame
283 SCTFA_CLEAR_REGS = (1 << 1), // clear registers (mask)
305 // note: limited to 32k due to p_argnext
307 #define MAX_ARG_GRP 2
309 static struct parsed_op ops[MAX_OPS];
310 static struct parsed_equ *g_eqs;
312 static char *g_labels[MAX_OPS];
313 static struct label_ref g_label_refs[MAX_OPS];
314 static const struct parsed_proto *g_func_pp;
315 static struct parsed_data *g_func_pd;
316 static int g_func_pd_cnt;
317 static int g_func_lmods;
318 static char g_func[256];
319 static char g_comment[256];
320 static int g_bp_frame;
321 static int g_sp_frame;
322 static int g_stack_frame_used;
323 static int g_stack_fsz;
324 static int g_seh_found;
325 static int g_seh_size;
326 static int g_ida_func_attr;
327 static int g_sct_func_attr;
328 static int g_stack_clear_start; // in dwords
329 static int g_stack_clear_len;
330 static int g_regmask_init;
331 static int g_skip_func;
332 static int g_allow_regfunc;
333 static int g_allow_user_icall;
334 static int g_quiet_pp;
335 static int g_header_mode;
337 #define ferr(op_, fmt, ...) do { \
338 printf("%s:%d: error %u: [%s] '%s': " fmt, asmfn, (op_)->asmln, \
339 __LINE__, g_func, dump_op(op_), ##__VA_ARGS__); \
343 #define fnote(op_, fmt, ...) \
344 printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
345 dump_op(op_), ##__VA_ARGS__)
347 #define ferr_assert(op_, cond) do { \
348 if (!(cond)) ferr(op_, "assertion '%s' failed\n", #cond); \
351 const char *regs_r32[] = {
352 "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
353 // not r32, but list here for easy parsing and printing
354 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
355 "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"
357 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
358 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
359 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
365 xMM0, xMM1, xMM2, xMM3, // mmx
366 xMM4, xMM5, xMM6, xMM7,
367 xST0, xST1, xST2, xST3, // x87
368 xST4, xST5, xST6, xST7,
371 #define mxAX (1 << xAX)
372 #define mxCX (1 << xCX)
373 #define mxDX (1 << xDX)
374 #define mxSP (1 << xSP)
375 #define mxST0 (1 << xST0)
376 #define mxST1 (1 << xST1)
377 #define mxST1_0 (mxST1 | mxST0)
378 #define mxST7_2 (0xfc << xST0)
379 #define mxSTa (0xff << xST0)
381 // possible basic comparison types (without inversion)
382 enum parsed_flag_op {
386 PFO_BE, // 6 CF=1||ZF=1
390 PFO_LE, // e ZF=1||SF!=OF
393 #define PFOB_O (1 << PFO_O)
394 #define PFOB_C (1 << PFO_C)
395 #define PFOB_Z (1 << PFO_Z)
396 #define PFOB_S (1 << PFO_S)
398 static const char *parsed_flag_op_names[] = {
399 "o", "c", "z", "be", "s", "p", "l", "le"
402 static int char_array_i(const char *array[], size_t len, const char *s)
406 for (i = 0; i < len; i++)
413 static void printf_number(char *buf, size_t buf_size,
414 unsigned long number)
416 // output in C-friendly form
417 snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
420 static int check_segment_prefix(const char *s)
422 if (s[0] == 0 || s[1] != 's' || s[2] != ':')
426 case 'c': return SEG_CS;
427 case 'd': return SEG_DS;
428 case 's': return SEG_SS;
429 case 'e': return SEG_ES;
430 case 'f': return SEG_FS;
431 case 'g': return SEG_GS;
436 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
440 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
442 *reg_lmod = OPLM_QWORD;
446 *reg_lmod = OPLM_DWORD;
449 reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
451 *reg_lmod = OPLM_WORD;
454 reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
456 *reg_lmod = OPLM_BYTE;
459 reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
461 *reg_lmod = OPLM_BYTE;
468 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
470 enum opr_lenmod lmod;
483 while (my_isblank(*s))
485 for (; my_issep(*s); d++, s++)
487 while (my_isblank(*s))
491 // skip '?s:' prefixes
492 if (check_segment_prefix(s))
495 s = next_idt(w, sizeof(w), s);
500 reg = parse_reg(&lmod, w);
502 *regmask |= 1 << reg;
506 if ('0' <= w[0] && w[0] <= '9') {
507 number = parse_number(w, 0);
508 printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
512 // probably some label/identifier - pass
515 snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
519 strcpy(name, cvtbuf);
524 static int is_reg_in_str(const char *s)
528 if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
531 for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
532 if (!strncmp(s, regs_r32[i], 3))
538 static const char *parse_stack_el(const char *name, char *extra_reg,
539 int *base_val, int early_try)
541 const char *p, *p2, *s;
547 if (g_bp_frame || early_try)
550 if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
552 if (extra_reg != NULL) {
553 strncpy(extra_reg, name, 3);
558 if (IS_START(p, "ebp+")) {
562 if (p2 != NULL && is_reg_in_str(p)) {
563 if (extra_reg != NULL) {
564 strncpy(extra_reg, p, p2 - p);
565 extra_reg[p2 - p] = 0;
570 if (!('0' <= *p && *p <= '9'))
577 if (!IS_START(name, "esp+"))
583 if (is_reg_in_str(s)) {
584 if (extra_reg != NULL) {
585 strncpy(extra_reg, s, p - s);
586 extra_reg[p - s] = 0;
591 aerr("%s IDA stackvar not set?\n", __func__);
593 if (!('0' <= *s && *s <= '9')) {
594 aerr("%s IDA stackvar offset not set?\n", __func__);
597 if (s[0] == '0' && s[1] == 'x')
600 if (len < sizeof(buf) - 1) {
601 strncpy(buf, s, len);
604 val = strtol(buf, &endp, 16);
605 if (val == 0 || *endp != 0 || errno != 0) {
606 aerr("%s num parse fail for '%s'\n", __func__, buf);
615 if ('0' <= *p && *p <= '9')
618 if (base_val != NULL)
623 static int guess_lmod_from_name(struct parsed_opr *opr)
625 if (IS_START(opr->name, "dword_") || IS_START(opr->name, "off_")) {
626 opr->lmod = OPLM_DWORD;
629 if (IS_START(opr->name, "word_")) {
630 opr->lmod = OPLM_WORD;
633 if (IS_START(opr->name, "byte_")) {
634 opr->lmod = OPLM_BYTE;
637 if (IS_START(opr->name, "qword_")) {
638 opr->lmod = OPLM_QWORD;
644 static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
645 const struct parsed_type *c_type)
647 static const char *qword_types[] = {
648 "uint64_t", "int64_t", "__int64",
650 static const char *dword_types[] = {
651 "uint32_t", "int", "_DWORD", "UINT_PTR", "DWORD",
652 "WPARAM", "LPARAM", "UINT", "__int32",
653 "LONG", "HIMC", "BOOL", "size_t",
656 static const char *word_types[] = {
657 "uint16_t", "int16_t", "_WORD", "WORD",
658 "unsigned __int16", "__int16",
660 static const char *byte_types[] = {
661 "uint8_t", "int8_t", "char",
662 "unsigned __int8", "__int8", "BYTE", "_BYTE",
664 // structures.. deal the same as with _UNKNOWN for now
670 if (c_type->is_ptr) {
675 n = skip_type_mod(c_type->name);
677 for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
678 if (IS(n, dword_types[i])) {
684 for (i = 0; i < ARRAY_SIZE(word_types); i++) {
685 if (IS(n, word_types[i])) {
691 for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
692 if (IS(n, byte_types[i])) {
698 for (i = 0; i < ARRAY_SIZE(qword_types); i++) {
699 if (IS(n, qword_types[i])) {
708 static char *default_cast_to(char *buf, size_t buf_size,
709 struct parsed_opr *opr)
713 if (!opr->is_ptr || strchr(opr->name, '['))
715 if (opr->pp == NULL || opr->pp->type.name == NULL
718 snprintf(buf, buf_size, "%s", "(void *)");
722 snprintf(buf, buf_size, "(%s)", opr->pp->type.name);
726 static enum opr_type lmod_from_directive(const char *d)
730 else if (IS(d, "dw"))
732 else if (IS(d, "db"))
735 aerr("unhandled directive: '%s'\n", d);
739 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
745 *regmask |= 1 << reg;
748 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
751 static int parse_operand(struct parsed_opr *opr,
752 int *regmask, int *regmask_indirect,
753 char words[16][256], int wordc, int w, unsigned int op_flags)
755 const struct parsed_proto *pp = NULL;
756 enum opr_lenmod tmplmod;
757 unsigned long number;
765 aerr("parse_operand w %d, wordc %d\n", w, wordc);
769 for (i = w; i < wordc; i++) {
770 len = strlen(words[i]);
771 if (words[i][len - 1] == ',') {
772 words[i][len - 1] = 0;
778 wordc_in = wordc - w;
780 if ((op_flags & OPF_JMP) && wordc_in > 0
781 && !('0' <= words[w][0] && words[w][0] <= '9'))
783 const char *label = NULL;
785 if (wordc_in == 3 && !strncmp(words[w], "near", 4)
786 && IS(words[w + 1], "ptr"))
787 label = words[w + 2];
788 else if (wordc_in == 2 && IS(words[w], "short"))
789 label = words[w + 1];
790 else if (wordc_in == 1
791 && strchr(words[w], '[') == NULL
792 && parse_reg(&tmplmod, words[w]) < 0)
796 opr->type = OPT_LABEL;
797 ret = check_segment_prefix(label);
802 strcpy(opr->name, label);
808 if (IS(words[w + 1], "ptr")) {
809 if (IS(words[w], "dword"))
810 opr->lmod = OPLM_DWORD;
811 else if (IS(words[w], "word"))
812 opr->lmod = OPLM_WORD;
813 else if (IS(words[w], "byte"))
814 opr->lmod = OPLM_BYTE;
815 else if (IS(words[w], "qword"))
816 opr->lmod = OPLM_QWORD;
818 aerr("type parsing failed\n");
820 wordc_in = wordc - w;
825 if (IS(words[w], "offset")) {
826 opr->type = OPT_OFFSET;
827 opr->lmod = OPLM_DWORD;
828 strcpy(opr->name, words[w + 1]);
829 pp = proto_parse(g_fhdr, opr->name, 1);
832 if (IS(words[w], "(offset")) {
833 p = strchr(words[w + 1], ')');
835 aerr("parse of bracketed offset failed\n");
837 opr->type = OPT_OFFSET;
838 strcpy(opr->name, words[w + 1]);
844 aerr("parse_operand 1 word expected\n");
846 ret = check_segment_prefix(words[w]);
849 memmove(words[w], words[w] + 3, strlen(words[w]) - 2);
850 if (ret == SEG_FS && IS(words[w], "0"))
853 strcpy(opr->name, words[w]);
855 if (words[w][0] == '[') {
856 opr->type = OPT_REGMEM;
857 ret = sscanf(words[w], "[%[^]]]", opr->name);
859 aerr("[] parse failure\n");
861 parse_indmode(opr->name, regmask_indirect, 1);
862 if (opr->lmod == OPLM_UNSPEC
863 && parse_stack_el(opr->name, NULL, NULL, 1))
866 struct parsed_equ *eq =
867 equ_find(NULL, parse_stack_el(opr->name, NULL, NULL, 1), &i);
869 opr->lmod = eq->lmod;
871 // might be unaligned access
872 g_func_lmods |= 1 << OPLM_BYTE;
876 else if (strchr(words[w], '[')) {
878 p = strchr(words[w], '[');
879 opr->type = OPT_REGMEM;
880 parse_indmode(p, regmask_indirect, 0);
881 strncpy(buf, words[w], p - words[w]);
882 buf[p - words[w]] = 0;
883 pp = proto_parse(g_fhdr, buf, 1);
886 else if (('0' <= words[w][0] && words[w][0] <= '9')
887 || words[w][0] == '-')
889 number = parse_number(words[w], 0);
890 opr->type = OPT_CONST;
892 printf_number(opr->name, sizeof(opr->name), number);
896 ret = parse_reg(&tmplmod, opr->name);
898 setup_reg_opr(opr, ret, tmplmod, regmask);
902 // most likely var in data segment
903 opr->type = OPT_LABEL;
904 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
908 if (pp->is_fptr || pp->is_func) {
909 opr->lmod = OPLM_DWORD;
913 tmplmod = OPLM_UNSPEC;
914 if (!guess_lmod_from_c_type(&tmplmod, &pp->type))
915 anote("unhandled C type '%s' for '%s'\n",
916 pp->type.name, opr->name);
918 if (opr->lmod == OPLM_UNSPEC) {
920 opr->type_from_var = 1;
922 else if (opr->lmod != tmplmod) {
923 opr->size_mismatch = 1;
924 if (tmplmod < opr->lmod)
927 opr->is_ptr = pp->type.is_ptr;
929 opr->is_array = pp->type.is_array;
933 if (opr->lmod == OPLM_UNSPEC)
934 guess_lmod_from_name(opr);
938 static const struct {
943 { "repe", OPF_REP|OPF_REPZ },
944 { "repz", OPF_REP|OPF_REPZ },
945 { "repne", OPF_REP|OPF_REPNZ },
946 { "repnz", OPF_REP|OPF_REPNZ },
947 { "lock", OPF_LOCK }, // ignored for now..
950 #define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
952 static const struct {
955 unsigned short minopr;
956 unsigned short maxopr;
959 unsigned char pfo_inv;
961 { "nop", OP_NOP, 0, 0, 0 },
962 { "push", OP_PUSH, 1, 1, 0 },
963 { "pop", OP_POP, 1, 1, OPF_DATA },
964 { "pusha",OP_PUSHA, 0, 0, 0 },
965 { "popa", OP_POPA, 0, 0, OPF_DATA },
966 { "leave",OP_LEAVE, 0, 0, OPF_DATA },
967 { "mov" , OP_MOV, 2, 2, OPF_DATA },
968 { "lea", OP_LEA, 2, 2, OPF_DATA },
969 { "movzx",OP_MOVZX, 2, 2, OPF_DATA },
970 { "movsx",OP_MOVSX, 2, 2, OPF_DATA },
971 { "xchg", OP_XCHG, 2, 2, OPF_DATA },
972 { "not", OP_NOT, 1, 1, OPF_DATA },
973 { "xlat", OP_XLAT, 0, 0, OPF_DATA },
974 { "cdq", OP_CDQ, 0, 0, OPF_DATA },
975 { "bswap",OP_BSWAP, 1, 1, OPF_DATA },
976 { "lodsb",OP_LODS, 0, 0, OPF_DATA },
977 { "lodsw",OP_LODS, 0, 0, OPF_DATA },
978 { "lodsd",OP_LODS, 0, 0, OPF_DATA },
979 { "stosb",OP_STOS, 0, 0, OPF_DATA },
980 { "stosw",OP_STOS, 0, 0, OPF_DATA },
981 { "stosd",OP_STOS, 0, 0, OPF_DATA },
982 { "movsb",OP_MOVS, 0, 0, OPF_DATA },
983 { "movsw",OP_MOVS, 0, 0, OPF_DATA },
984 { "movsd",OP_MOVS, 0, 0, OPF_DATA },
985 { "cmpsb",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
986 { "cmpsw",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
987 { "cmpsd",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
988 { "scasb",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
989 { "scasw",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
990 { "scasd",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
991 { "std", OP_STD, 0, 0, OPF_DATA }, // special flag
992 { "cld", OP_CLD, 0, 0, OPF_DATA },
993 { "add", OP_ADD, 2, 2, OPF_DATA|OPF_FLAGS },
994 { "sub", OP_SUB, 2, 2, OPF_DATA|OPF_FLAGS },
995 { "and", OP_AND, 2, 2, OPF_DATA|OPF_FLAGS },
996 { "or", OP_OR, 2, 2, OPF_DATA|OPF_FLAGS },
997 { "xor", OP_XOR, 2, 2, OPF_DATA|OPF_FLAGS },
998 { "shl", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
999 { "shr", OP_SHR, 2, 2, OPF_DATA|OPF_FLAGS },
1000 { "sal", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
1001 { "sar", OP_SAR, 2, 2, OPF_DATA|OPF_FLAGS },
1002 { "shld", OP_SHLD, 3, 3, OPF_DATA|OPF_FLAGS },
1003 { "shrd", OP_SHRD, 3, 3, OPF_DATA|OPF_FLAGS },
1004 { "rol", OP_ROL, 2, 2, OPF_DATA|OPF_FLAGS },
1005 { "ror", OP_ROR, 2, 2, OPF_DATA|OPF_FLAGS },
1006 { "rcl", OP_RCL, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1007 { "rcr", OP_RCR, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1008 { "adc", OP_ADC, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1009 { "sbb", OP_SBB, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1010 { "bsf", OP_BSF, 2, 2, OPF_DATA|OPF_FLAGS },
1011 { "bsr", OP_BSR, 2, 2, OPF_DATA|OPF_FLAGS },
1012 { "inc", OP_INC, 1, 1, OPF_DATA|OPF_FLAGS },
1013 { "dec", OP_DEC, 1, 1, OPF_DATA|OPF_FLAGS },
1014 { "neg", OP_NEG, 1, 1, OPF_DATA|OPF_FLAGS },
1015 { "mul", OP_MUL, 1, 1, OPF_DATA|OPF_FLAGS },
1016 { "imul", OP_IMUL, 1, 3, OPF_DATA|OPF_FLAGS },
1017 { "div", OP_DIV, 1, 1, OPF_DATA|OPF_FLAGS },
1018 { "idiv", OP_IDIV, 1, 1, OPF_DATA|OPF_FLAGS },
1019 { "test", OP_TEST, 2, 2, OPF_FLAGS },
1020 { "cmp", OP_CMP, 2, 2, OPF_FLAGS },
1021 { "retn", OP_RET, 0, 1, OPF_TAIL },
1022 { "call", OP_CALL, 1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
1023 { "jmp", OP_JMP, 1, 1, OPF_JMP },
1024 { "jecxz",OP_JECXZ, 1, 1, OPF_JMP|OPF_CJMP },
1025 { "loop", OP_LOOP, 1, 1, OPF_JMP|OPF_CJMP|OPF_DATA },
1026 { "jo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 0 }, // 70 OF=1
1027 { "jno", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 1 }, // 71 OF=0
1028 { "jc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72 CF=1
1029 { "jb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72
1030 { "jnc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73 CF=0
1031 { "jnb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1032 { "jae", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1033 { "jz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74 ZF=1
1034 { "je", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74
1035 { "jnz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75 ZF=0
1036 { "jne", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75
1037 { "jbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76 CF=1||ZF=1
1038 { "jna", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76
1039 { "ja", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77 CF=0&&ZF=0
1040 { "jnbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77
1041 { "js", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 0 }, // 78 SF=1
1042 { "jns", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 1 }, // 79 SF=0
1043 { "jp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a PF=1
1044 { "jpe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a
1045 { "jnp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b PF=0
1046 { "jpo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b
1047 { "jl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c SF!=OF
1048 { "jnge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c
1049 { "jge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d SF=OF
1050 { "jnl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d
1051 { "jle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e ZF=1||SF!=OF
1052 { "jng", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e
1053 { "jg", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f ZF=0&&SF=OF
1054 { "jnle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f
1055 { "seto", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 0 },
1056 { "setno", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 1 },
1057 { "setc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1058 { "setb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1059 { "setnc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1060 { "setae", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1061 { "setnb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1062 { "setz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1063 { "sete", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1064 { "setnz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1065 { "setne", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1066 { "setbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1067 { "setna", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1068 { "seta", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1069 { "setnbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1070 { "sets", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 0 },
1071 { "setns", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 1 },
1072 { "setp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1073 { "setpe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1074 { "setnp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1075 { "setpo", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1076 { "setl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1077 { "setnge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1078 { "setge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1079 { "setnl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1080 { "setle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1081 { "setng", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1082 { "setg", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1083 { "setnle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1085 { "fld", OP_FLD, 1, 1, OPF_FPUSH },
1086 { "fild", OP_FILD, 1, 1, OPF_FPUSH|OPF_FINT },
1087 { "fld1", OP_FLDc, 0, 0, OPF_FPUSH },
1088 { "fldl2t", OP_FLDc, 0, 0, OPF_FPUSH },
1089 { "fldl2e", OP_FLDc, 0, 0, OPF_FPUSH },
1090 { "fldpi", OP_FLDc, 0, 0, OPF_FPUSH },
1091 { "fldlg2", OP_FLDc, 0, 0, OPF_FPUSH },
1092 { "fldln2", OP_FLDc, 0, 0, OPF_FPUSH },
1093 { "fldz", OP_FLDc, 0, 0, OPF_FPUSH },
1094 { "fst", OP_FST, 1, 1, 0 },
1095 { "fstp", OP_FST, 1, 1, OPF_FPOP },
1096 { "fist", OP_FIST, 1, 1, OPF_FINT },
1097 { "fistp", OP_FIST, 1, 1, OPF_FPOP|OPF_FINT },
1098 { "fadd", OP_FADD, 0, 2, 0 },
1099 { "faddp", OP_FADD, 0, 2, OPF_FPOP },
1100 { "fdiv", OP_FDIV, 0, 2, 0 },
1101 { "fdivp", OP_FDIV, 0, 2, OPF_FPOP },
1102 { "fmul", OP_FMUL, 0, 2, 0 },
1103 { "fmulp", OP_FMUL, 0, 2, OPF_FPOP },
1104 { "fsub", OP_FSUB, 0, 2, 0 },
1105 { "fsubp", OP_FSUB, 0, 2, OPF_FPOP },
1106 { "fdivr", OP_FDIVR, 0, 2, 0 },
1107 { "fdivrp", OP_FDIVR, 0, 2, OPF_FPOP },
1108 { "fsubr", OP_FSUBR, 0, 2, 0 },
1109 { "fsubrp", OP_FSUBR, 0, 2, OPF_FPOP },
1110 { "fiadd", OP_FIADD, 1, 1, OPF_FINT },
1111 { "fidiv", OP_FIDIV, 1, 1, OPF_FINT },
1112 { "fimul", OP_FIMUL, 1, 1, OPF_FINT },
1113 { "fisub", OP_FISUB, 1, 1, OPF_FINT },
1114 { "fidivr", OP_FIDIVR, 1, 1, OPF_FINT },
1115 { "fisubr", OP_FISUBR, 1, 1, OPF_FINT },
1116 { "fcom", OP_FCOM, 0, 1, 0 },
1117 { "fcomp", OP_FCOM, 0, 1, OPF_FPOP },
1118 { "fcompp", OP_FCOM, 0, 0, OPF_FPOPP },
1119 { "fucom", OP_FCOM, 0, 1, 0 },
1120 { "fucomp", OP_FCOM, 0, 1, OPF_FPOP },
1121 { "fucompp",OP_FCOM, 0, 0, OPF_FPOPP },
1122 { "fnstsw", OP_FNSTSW, 1, 1, OPF_DATA },
1123 { "fchs", OP_FCHS, 0, 0, 0 },
1124 { "fcos", OP_FCOS, 0, 0, 0 },
1125 { "fpatan", OP_FPATAN, 0, 0, OPF_FPOP },
1126 { "fptan", OP_FPTAN, 0, 0, OPF_FPUSH },
1127 { "fsin", OP_FSIN, 0, 0, 0 },
1128 { "fsqrt", OP_FSQRT, 0, 0, 0 },
1129 { "fxch", OP_FXCH, 1, 1, 0 },
1130 { "fyl2x", OP_FYL2X, 0, 0, OPF_FPOP },
1132 { "emms", OP_EMMS, 0, 0, OPF_DATA },
1133 { "movq", OP_MOV, 2, 2, OPF_DATA },
1134 // pseudo-ops for lib calls
1135 { "_allshl",OPP_ALLSHL },
1136 { "_allshr",OPP_ALLSHR },
1137 { "_ftol", OPP_FTOL },
1138 { "_CIpow", OPP_CIPOW },
1139 { "abort", OPP_ABORT },
1144 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
1146 enum opr_lenmod lmod = OPLM_UNSPEC;
1147 int prefix_flags = 0;
1155 for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
1156 if (IS(words[w], pref_table[i].name)) {
1157 prefix_flags = pref_table[i].flags;
1164 aerr("lone prefix: '%s'\n", words[0]);
1169 for (i = 0; i < ARRAY_SIZE(op_table); i++) {
1170 if (IS(words[w], op_table[i].name))
1174 if (i == ARRAY_SIZE(op_table)) {
1176 aerr("unhandled op: '%s'\n", words[0]);
1181 op->op = op_table[i].op;
1182 op->flags = op_table[i].flags | prefix_flags;
1183 op->pfo = op_table[i].pfo;
1184 op->pfo_inv = op_table[i].pfo_inv;
1185 op->regmask_src = op->regmask_dst = 0;
1188 if (op->op == OP_UD2)
1191 for (opr = 0; opr < op_table[i].maxopr; opr++) {
1192 if (opr >= op_table[i].minopr && w >= wordc)
1195 regmask = regmask_ind = 0;
1196 w = parse_operand(&op->operand[opr], ®mask, ®mask_ind,
1197 words, wordc, w, op->flags);
1199 if (opr == 0 && (op->flags & OPF_DATA))
1200 op->regmask_dst = regmask;
1202 op->regmask_src |= regmask;
1203 op->regmask_src |= regmask_ind;
1205 if (op->operand[opr].lmod != OPLM_UNSPEC)
1206 g_func_lmods |= 1 << op->operand[opr].lmod;
1210 aerr("parse_op %s incomplete: %d/%d\n",
1211 words[0], w, wordc);
1214 op->operand_cnt = opr;
1215 if (!strncmp(op_table[i].name, "set", 3))
1216 op->operand[0].lmod = OPLM_BYTE;
1219 // first operand is not dst
1222 op->regmask_src |= op->regmask_dst;
1223 op->regmask_dst = 0;
1226 // first operand is src too
1239 op->regmask_src |= op->regmask_dst;
1244 op->regmask_src |= op->regmask_dst;
1245 op->regmask_dst |= op->regmask_src;
1251 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1252 && op->operand[0].lmod == op->operand[1].lmod
1253 && op->operand[0].reg == op->operand[1].reg
1254 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1256 op->regmask_src = 0;
1259 op->regmask_src |= op->regmask_dst;
1262 // ops with implicit argumets
1264 op->operand_cnt = 2;
1265 setup_reg_opr(&op->operand[0], xAX, OPLM_BYTE, &op->regmask_src);
1266 op->regmask_dst = op->regmask_src;
1267 setup_reg_opr(&op->operand[1], xBX, OPLM_DWORD, &op->regmask_src);
1271 op->operand_cnt = 2;
1272 setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
1273 setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
1279 if (words[op_w][4] == 'b')
1281 else if (words[op_w][4] == 'w')
1283 else if (words[op_w][4] == 'd')
1286 op->regmask_src = 0;
1287 setup_reg_opr(&op->operand[j++], op->op == OP_LODS ? xSI : xDI,
1288 OPLM_DWORD, &op->regmask_src);
1289 op->regmask_dst = op->regmask_src;
1290 setup_reg_opr(&op->operand[j++], xAX, lmod,
1291 op->op == OP_LODS ? &op->regmask_dst : &op->regmask_src);
1292 if (op->flags & OPF_REP) {
1293 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1294 op->regmask_dst |= 1 << xCX;
1296 op->operand_cnt = j;
1301 if (words[op_w][4] == 'b')
1303 else if (words[op_w][4] == 'w')
1305 else if (words[op_w][4] == 'd')
1308 op->regmask_src = 0;
1309 // note: lmod is not correct, don't have where to place it
1310 setup_reg_opr(&op->operand[j++], xDI, lmod, &op->regmask_src);
1311 setup_reg_opr(&op->operand[j++], xSI, OPLM_DWORD, &op->regmask_src);
1312 if (op->flags & OPF_REP)
1313 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1314 op->operand_cnt = j;
1315 op->regmask_dst = op->regmask_src;
1319 op->regmask_dst = 1 << xCX;
1322 op->operand_cnt = 2;
1323 op->regmask_src = 1 << xCX;
1324 op->operand[1].type = OPT_REG;
1325 op->operand[1].reg = xCX;
1326 op->operand[1].lmod = OPLM_DWORD;
1330 if (op->operand_cnt == 2) {
1331 if (op->operand[0].type != OPT_REG)
1332 aerr("reg expected\n");
1333 op->regmask_src |= 1 << op->operand[0].reg;
1335 if (op->operand_cnt != 1)
1340 op->regmask_src |= op->regmask_dst;
1341 op->regmask_dst = (1 << xDX) | (1 << xAX);
1342 if (op->operand[0].lmod == OPLM_UNSPEC)
1343 op->operand[0].lmod = OPLM_DWORD;
1348 // we could set up operands for edx:eax, but there is no real need to
1349 // (see is_opr_modified())
1350 op->regmask_src |= op->regmask_dst;
1351 op->regmask_dst = (1 << xDX) | (1 << xAX);
1352 if (op->operand[0].lmod == OPLM_UNSPEC)
1353 op->operand[0].lmod = OPLM_DWORD;
1361 op->regmask_src |= op->regmask_dst;
1362 if (op->operand[1].lmod == OPLM_UNSPEC)
1363 op->operand[1].lmod = OPLM_BYTE;
1368 op->regmask_src |= op->regmask_dst;
1369 if (op->operand[2].lmod == OPLM_UNSPEC)
1370 op->operand[2].lmod = OPLM_BYTE;
1374 op->regmask_src |= op->regmask_dst;
1375 op->regmask_dst = 0;
1376 if (op->operand[0].lmod == OPLM_UNSPEC
1377 && (op->operand[0].type == OPT_CONST
1378 || op->operand[0].type == OPT_OFFSET
1379 || op->operand[0].type == OPT_LABEL))
1380 op->operand[0].lmod = OPLM_DWORD;
1386 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1387 && op->operand[0].lmod == op->operand[1].lmod
1388 && op->operand[0].reg == op->operand[1].reg
1389 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1391 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1392 op->regmask_src = op->regmask_dst = 0;
1397 if (op->operand[0].type == OPT_REG
1398 && op->operand[1].type == OPT_REGMEM)
1401 snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1402 if (IS(buf, op->operand[1].name))
1403 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1408 // trashed regs must be explicitly detected later
1409 op->regmask_dst = 0;
1413 op->regmask_dst = (1 << xBP) | (1 << xSP);
1414 op->regmask_src = 1 << xBP;
1419 op->regmask_dst |= mxST0;
1423 op->regmask_dst |= mxST0;
1424 if (IS(words[op_w] + 3, "1"))
1425 op->operand[0].val = X87_CONST_1;
1426 else if (IS(words[op_w] + 3, "l2t"))
1427 op->operand[0].val = X87_CONST_L2T;
1428 else if (IS(words[op_w] + 3, "l2e"))
1429 op->operand[0].val = X87_CONST_L2E;
1430 else if (IS(words[op_w] + 3, "pi"))
1431 op->operand[0].val = X87_CONST_PI;
1432 else if (IS(words[op_w] + 3, "lg2"))
1433 op->operand[0].val = X87_CONST_LG2;
1434 else if (IS(words[op_w] + 3, "ln2"))
1435 op->operand[0].val = X87_CONST_LN2;
1436 else if (IS(words[op_w] + 3, "z"))
1437 op->operand[0].val = X87_CONST_Z;
1439 aerr("fld what?\n");
1444 op->regmask_src |= mxST0;
1453 op->regmask_src |= mxST0;
1454 if (op->operand_cnt == 2)
1455 op->regmask_src |= op->regmask_dst;
1456 else if (op->operand_cnt == 1) {
1457 memcpy(&op->operand[1], &op->operand[0], sizeof(op->operand[1]));
1458 op->operand[0].type = OPT_REG;
1459 op->operand[0].lmod = OPLM_QWORD;
1460 op->operand[0].reg = xST0;
1461 op->regmask_dst |= mxST0;
1464 // IDA doesn't use this
1465 aerr("no operands?\n");
1479 op->regmask_src |= mxST0;
1480 op->regmask_dst |= mxST0;
1485 op->regmask_src |= mxST0 | mxST1;
1486 op->regmask_dst |= mxST0;
1494 op->regmask_src |= mxST0;
1495 if (op->operand_cnt == 0) {
1496 op->operand_cnt = 1;
1497 op->operand[0].type = OPT_REG;
1498 op->operand[0].lmod = OPLM_QWORD;
1499 op->operand[0].reg = xST1;
1500 op->regmask_src |= mxST1;
1508 if (op->operand[0].type == OPT_REG
1509 && op->operand[1].type == OPT_CONST)
1511 struct parsed_opr *op1 = &op->operand[1];
1512 if ((op->op == OP_AND && op1->val == 0)
1515 || (op->operand[0].lmod == OPLM_WORD && op1->val == 0xffff)
1516 || (op->operand[0].lmod == OPLM_BYTE && op1->val == 0xff))))
1518 op->regmask_src = 0;
1523 static const char *op_name(struct parsed_op *po)
1525 static char buf[16];
1529 if (po->op == OP_JCC || po->op == OP_SCC) {
1531 *p++ = (po->op == OP_JCC) ? 'j' : 's';
1534 strcpy(p, parsed_flag_op_names[po->pfo]);
1538 for (i = 0; i < ARRAY_SIZE(op_table); i++)
1539 if (op_table[i].op == po->op)
1540 return op_table[i].name;
1546 static const char *dump_op(struct parsed_op *po)
1548 static char out[128];
1555 snprintf(out, sizeof(out), "%s", op_name(po));
1556 for (i = 0; i < po->operand_cnt; i++) {
1560 snprintf(p, sizeof(out) - (p - out),
1561 po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1562 po->operand[i].name);
1568 static const char *lmod_type_u(struct parsed_op *po,
1569 enum opr_lenmod lmod)
1581 ferr(po, "invalid lmod: %d\n", lmod);
1582 return "(_invalid_)";
1586 static const char *lmod_cast_u(struct parsed_op *po,
1587 enum opr_lenmod lmod)
1599 ferr(po, "invalid lmod: %d\n", lmod);
1600 return "(_invalid_)";
1604 static const char *lmod_cast_u_ptr(struct parsed_op *po,
1605 enum opr_lenmod lmod)
1617 ferr(po, "invalid lmod: %d\n", lmod);
1618 return "(_invalid_)";
1622 static const char *lmod_cast_s(struct parsed_op *po,
1623 enum opr_lenmod lmod)
1635 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1636 return "(_invalid_)";
1640 static const char *lmod_cast(struct parsed_op *po,
1641 enum opr_lenmod lmod, int is_signed)
1644 lmod_cast_s(po, lmod) :
1645 lmod_cast_u(po, lmod);
1648 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1660 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1665 static const char *opr_name(struct parsed_op *po, int opr_num)
1667 if (opr_num >= po->operand_cnt)
1668 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1669 return po->operand[opr_num].name;
1672 static unsigned int opr_const(struct parsed_op *po, int opr_num)
1674 if (opr_num >= po->operand_cnt)
1675 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1676 if (po->operand[opr_num].type != OPT_CONST)
1677 ferr(po, "opr %d: const expected\n", opr_num);
1678 return po->operand[opr_num].val;
1681 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1683 if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
1684 ferr(po, "invalid reg: %d\n", popr->reg);
1685 return regs_r32[popr->reg];
1688 static int check_simple_cast(const char *cast, int *bits, int *is_signed)
1690 if (IS_START(cast, "(s8)") || IS_START(cast, "(u8)"))
1692 else if (IS_START(cast, "(s16)") || IS_START(cast, "(u16)"))
1694 else if (IS_START(cast, "(s32)") || IS_START(cast, "(u32)"))
1696 else if (IS_START(cast, "(s64)") || IS_START(cast, "(u64)"))
1701 *is_signed = cast[1] == 's' ? 1 : 0;
1705 static int check_deref_cast(const char *cast, int *bits)
1707 if (IS_START(cast, "*(u8 *)"))
1709 else if (IS_START(cast, "*(u16 *)"))
1711 else if (IS_START(cast, "*(u32 *)"))
1713 else if (IS_START(cast, "*(u64 *)"))
1721 // cast1 is the "final" cast
1722 static const char *simplify_cast(const char *cast1, const char *cast2)
1724 static char buf[256];
1732 if (IS(cast1, cast2))
1735 if (check_simple_cast(cast1, &bits1, &s1) == 0
1736 && check_simple_cast(cast2, &bits2, &s2) == 0)
1741 if (check_simple_cast(cast1, &bits1, &s1) == 0
1742 && check_deref_cast(cast2, &bits2) == 0)
1744 if (bits1 == bits2) {
1745 snprintf(buf, sizeof(buf), "*(%c%d *)", s1 ? 's' : 'u', bits1);
1750 if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1753 snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1757 static const char *simplify_cast_num(const char *cast, unsigned int val)
1759 if (IS(cast, "(u8)") && val < 0x100)
1761 if (IS(cast, "(s8)") && val < 0x80)
1763 if (IS(cast, "(u16)") && val < 0x10000)
1765 if (IS(cast, "(s16)") && val < 0x8000)
1767 if (IS(cast, "(s32)") && val < 0x80000000)
1773 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1782 namelen = strlen(name);
1784 p = strpbrk(name, "+-");
1788 ferr(po, "equ parse failed for '%s'\n", name);
1791 *extra_offs = strtol(p, &endp, 16);
1792 if (*endp != 0 || errno != 0)
1793 ferr(po, "equ parse failed for '%s'\n", name);
1796 for (i = 0; i < g_eqcnt; i++)
1797 if (strncmp(g_eqs[i].name, name, namelen) == 0
1798 && g_eqs[i].name[namelen] == 0)
1802 ferr(po, "unresolved equ name: '%s'\n", name);
1809 static int is_stack_access(struct parsed_op *po,
1810 const struct parsed_opr *popr)
1812 return (parse_stack_el(popr->name, NULL, NULL, 0)
1813 || (g_bp_frame && !(po->flags & OPF_EBP_S)
1814 && IS_START(popr->name, "ebp")));
1817 static void parse_stack_access(struct parsed_op *po,
1818 const char *name, char *ofs_reg, int *offset_out,
1819 int *stack_ra_out, const char **bp_arg_out, int is_lea)
1821 const char *bp_arg = "";
1822 const char *p = NULL;
1823 struct parsed_equ *eq;
1830 if (IS_START(name, "ebp-")
1831 || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1834 if (IS_START(p, "0x"))
1837 offset = strtoul(p, &endp, 16);
1840 if (*endp != 0 || errno != 0)
1841 ferr(po, "ebp- parse of '%s' failed\n", name);
1844 bp_arg = parse_stack_el(name, ofs_reg, NULL, 0);
1845 eq = equ_find(po, bp_arg, &offset);
1847 ferr(po, "detected but missing eq\n");
1848 offset += eq->offset;
1851 if (!strncmp(name, "ebp", 3))
1854 // yes it sometimes LEAs ra for compares..
1855 if (!is_lea && ofs_reg[0] == 0
1856 && stack_ra <= offset && offset < stack_ra + 4)
1858 ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1861 *offset_out = offset;
1863 *stack_ra_out = stack_ra;
1865 *bp_arg_out = bp_arg;
1868 static int parse_stack_esp_offset(struct parsed_op *po,
1869 const char *name, int *offset_out)
1871 char ofs_reg[16] = { 0, };
1872 struct parsed_equ *eq;
1878 if (strstr(name, "esp") == NULL)
1880 bp_arg = parse_stack_el(name, ofs_reg, &base_val, 0);
1881 if (bp_arg == NULL) {
1882 // just plain offset?
1883 if (!IS_START(name, "esp+"))
1886 offset = strtol(name + 4, &endp, 0);
1887 if (endp == NULL || *endp != 0 || errno != 0)
1889 *offset_out = offset;
1893 if (ofs_reg[0] != 0)
1895 eq = equ_find(po, bp_arg, &offset);
1897 ferr(po, "detected but missing eq\n");
1898 offset += eq->offset;
1899 *offset_out = base_val + offset;
1903 static int stack_frame_access(struct parsed_op *po,
1904 struct parsed_opr *popr, char *buf, size_t buf_size,
1905 const char *name, const char *cast, int is_src, int is_lea)
1907 enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1908 const char *prefix = "";
1909 const char *bp_arg = NULL;
1910 char ofs_reg[16] = { 0, };
1911 int i, arg_i, arg_s;
1918 if (g_bp_frame && (po->flags & OPF_EBP_S)
1919 && !(po->regmask_src & mxSP))
1920 ferr(po, "stack_frame_access while ebp is scratch\n");
1922 parse_stack_access(po, name, ofs_reg, &offset,
1923 &stack_ra, &bp_arg, is_lea);
1925 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1927 if (offset > stack_ra)
1929 arg_i = (offset - stack_ra - 4) / 4;
1930 if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1932 if (g_func_pp->is_vararg
1933 && arg_i == g_func_pp->argc_stack && is_lea)
1935 // should be va_list
1938 snprintf(buf, buf_size, "%sap", cast);
1941 ferr(po, "offset %d (%s,%d) doesn't map to any arg\n",
1942 offset, bp_arg, arg_i);
1944 if (ofs_reg[0] != 0)
1945 ferr(po, "offset reg on arg access?\n");
1947 for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1948 if (g_func_pp->arg[i].reg != NULL)
1954 if (i == g_func_pp->argc)
1955 ferr(po, "arg %d not in prototype?\n", arg_i);
1957 popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
1964 ferr(po, "lea/byte to arg?\n");
1965 if (is_src && (offset & 3) == 0)
1966 snprintf(buf, buf_size, "%sa%d",
1967 simplify_cast(cast, "(u8)"), i + 1);
1969 snprintf(buf, buf_size, "%sBYTE%d(a%d)",
1970 cast, offset & 3, i + 1);
1975 ferr(po, "lea/word to arg?\n");
1980 ferr(po, "problematic arg store\n");
1981 snprintf(buf, buf_size, "%s((char *)&a%d + 1)",
1982 simplify_cast(cast, "*(u16 *)"), i + 1);
1985 ferr(po, "unaligned arg word load\n");
1987 else if (is_src && (offset & 2) == 0)
1988 snprintf(buf, buf_size, "%sa%d",
1989 simplify_cast(cast, "(u16)"), i + 1);
1991 snprintf(buf, buf_size, "%s%sWORD(a%d)",
1992 cast, (offset & 2) ? "HI" : "LO", i + 1);
2004 snprintf(buf, buf_size, "(u32)&a%d + %d",
2007 ferr(po, "unaligned arg store\n");
2009 // mov edx, [ebp+arg_4+2]; movsx ecx, dx
2010 snprintf(buf, buf_size, "%s(a%d >> %d)",
2011 prefix, i + 1, (offset & 3) * 8);
2015 snprintf(buf, buf_size, "%s%sa%d",
2016 prefix, is_lea ? "&" : "", i + 1);
2021 ferr_assert(po, !(offset & 7));
2024 snprintf(buf, buf_size, "%s%sa%d",
2025 prefix, is_lea ? "&" : "", i + 1);
2029 ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
2033 strcat(g_comment, " unaligned");
2036 guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
2037 if (tmp_lmod != OPLM_DWORD
2038 && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
2039 < lmod_bytes(po, popr->lmod) + (offset & 3))))
2041 ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
2042 i + 1, offset, g_func_pp->arg[i].type.name);
2044 // can't check this because msvc likes to reuse
2045 // arg space for scratch..
2046 //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
2047 // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
2051 if (g_stack_fsz == 0)
2052 ferr(po, "stack var access without stackframe\n");
2053 g_stack_frame_used = 1;
2055 sf_ofs = g_stack_fsz + offset;
2056 if (ofs_reg[0] == 0 && (offset > 0 || sf_ofs < 0))
2057 ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
2067 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2068 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2072 if ((sf_ofs & 1) || ofs_reg[0] != 0) {
2073 // known unaligned or possibly unaligned
2074 strcat(g_comment, " unaligned");
2076 prefix = "*(u16 *)&";
2077 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2078 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2081 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
2085 if ((sf_ofs & 3) || ofs_reg[0] != 0) {
2086 // known unaligned or possibly unaligned
2087 strcat(g_comment, " unaligned");
2089 prefix = "*(u32 *)&";
2090 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2091 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2094 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
2098 ferr_assert(po, !(sf_ofs & 7));
2099 ferr_assert(po, ofs_reg[0] == 0);
2100 // only used for x87 int64/float, float sets is_lea
2101 if (!is_lea && (po->flags & OPF_FINT))
2102 prefix = "*(s64 *)&";
2103 snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
2107 ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
2114 static void check_func_pp(struct parsed_op *po,
2115 const struct parsed_proto *pp, const char *pfx)
2117 enum opr_lenmod tmp_lmod;
2121 if (pp->argc_reg != 0) {
2122 if (!g_allow_user_icall && !pp->is_fastcall) {
2123 pp_print(buf, sizeof(buf), pp);
2124 ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
2126 if (pp->argc_stack > 0 && pp->argc_reg != 2)
2127 ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
2128 pfx, pp->argc_reg, pp->argc_stack);
2131 // fptrs must use 32bit args, callsite might have no information and
2132 // lack a cast to smaller types, which results in incorrectly masked
2133 // args passed (callee may assume masked args, it does on ARM)
2134 if (!pp->is_osinc) {
2135 for (i = 0; i < pp->argc; i++) {
2136 ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
2137 if (ret && tmp_lmod != OPLM_DWORD)
2138 ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
2139 i + 1, pp->arg[i].type.name);
2144 static const char *check_label_read_ref(struct parsed_op *po,
2147 const struct parsed_proto *pp;
2149 pp = proto_parse(g_fhdr, name, 0);
2151 ferr(po, "proto_parse failed for ref '%s'\n", name);
2154 check_func_pp(po, pp, "ref");
2159 static void check_opr(struct parsed_op *po, struct parsed_opr *popr)
2161 if (popr->segment == SEG_FS)
2162 ferr(po, "fs: used\n");
2163 if (popr->segment == SEG_GS)
2164 ferr(po, "gs: used\n");
2167 static char *out_src_opr(char *buf, size_t buf_size,
2168 struct parsed_op *po, struct parsed_opr *popr, const char *cast,
2171 char tmp1[256], tmp2[256];
2177 check_opr(po, popr);
2182 switch (popr->type) {
2185 ferr(po, "lea from reg?\n");
2187 switch (popr->lmod) {
2189 snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2192 snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2195 snprintf(buf, buf_size, "%s%s",
2196 simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2199 if (popr->name[1] == 'h') // XXX..
2200 snprintf(buf, buf_size, "%s(%s >> 8)",
2201 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2203 snprintf(buf, buf_size, "%s%s",
2204 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2207 ferr(po, "invalid src lmod: %d\n", popr->lmod);
2212 if (is_stack_access(po, popr)) {
2213 stack_frame_access(po, popr, buf, buf_size,
2214 popr->name, cast, 1, is_lea);
2218 strcpy(expr, popr->name);
2219 if (strchr(expr, '[')) {
2220 // special case: '[' can only be left for label[reg] form
2221 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2223 ferr(po, "parse failure for '%s'\n", expr);
2224 if (tmp1[0] == '(') {
2225 // (off_4FFF50+3)[eax]
2226 p = strchr(tmp1 + 1, ')');
2227 if (p == NULL || p[1] != 0)
2228 ferr(po, "parse failure (2) for '%s'\n", expr);
2230 memmove(tmp1, tmp1 + 1, strlen(tmp1));
2232 snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2235 // XXX: do we need more parsing?
2237 snprintf(buf, buf_size, "%s", expr);
2241 snprintf(buf, buf_size, "%s(%s)",
2242 simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2246 name = check_label_read_ref(po, popr->name);
2247 if (cast[0] == 0 && popr->is_ptr)
2251 snprintf(buf, buf_size, "(u32)&%s", name);
2252 else if (popr->size_lt)
2253 snprintf(buf, buf_size, "%s%s%s%s", cast,
2254 lmod_cast_u_ptr(po, popr->lmod),
2255 popr->is_array ? "" : "&", name);
2257 snprintf(buf, buf_size, "%s%s%s", cast, name,
2258 popr->is_array ? "[0]" : "");
2262 name = check_label_read_ref(po, popr->name);
2266 ferr(po, "lea an offset?\n");
2267 snprintf(buf, buf_size, "%s&%s", cast, name);
2272 ferr(po, "lea from const?\n");
2274 printf_number(tmp1, sizeof(tmp1), popr->val);
2275 if (popr->val == 0 && strchr(cast, '*'))
2276 snprintf(buf, buf_size, "NULL");
2278 snprintf(buf, buf_size, "%s%s",
2279 simplify_cast_num(cast, popr->val), tmp1);
2283 ferr(po, "invalid src type: %d\n", popr->type);
2289 // note: may set is_ptr (we find that out late for ebp frame..)
2290 static char *out_dst_opr(char *buf, size_t buf_size,
2291 struct parsed_op *po, struct parsed_opr *popr)
2293 check_opr(po, popr);
2295 switch (popr->type) {
2297 switch (popr->lmod) {
2299 snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2302 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2306 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2310 if (popr->name[1] == 'h') // XXX..
2311 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2313 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2316 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2321 if (is_stack_access(po, popr)) {
2322 stack_frame_access(po, popr, buf, buf_size,
2323 popr->name, "", 0, 0);
2327 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2330 if (popr->size_mismatch)
2331 snprintf(buf, buf_size, "%s%s%s",
2332 lmod_cast_u_ptr(po, popr->lmod),
2333 popr->is_array ? "" : "&", popr->name);
2335 snprintf(buf, buf_size, "%s%s", popr->name,
2336 popr->is_array ? "[0]" : "");
2340 ferr(po, "invalid dst type: %d\n", popr->type);
2346 static char *out_src_opr_u32(char *buf, size_t buf_size,
2347 struct parsed_op *po, struct parsed_opr *popr)
2349 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2352 static char *out_opr_float(char *buf, size_t buf_size,
2353 struct parsed_op *po, struct parsed_opr *popr, int is_src,
2354 int need_float_stack)
2356 const char *cast = NULL;
2363 switch (popr->type) {
2365 if (popr->reg < xST0 || popr->reg > xST7) {
2367 ferr_assert(po, po->op == OP_PUSH);
2368 ferr_assert(po, popr->lmod == OPLM_DWORD);
2369 snprintf(buf, buf_size, "*(float *)&%s", opr_reg_p(po, popr));
2373 if (need_float_stack) {
2374 if (popr->reg == xST0)
2375 snprintf(buf, buf_size, "f_st[f_stp & 7]");
2377 snprintf(buf, buf_size, "f_st[(f_stp + %d) & 7]",
2381 snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2385 if (popr->lmod == OPLM_QWORD && is_stack_access(po, popr)) {
2386 stack_frame_access(po, popr, buf, buf_size,
2387 popr->name, "", is_src, 0);
2393 switch (popr->lmod) {
2401 ferr(po, "unhandled lmod: %d\n", popr->lmod);
2404 out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2405 snprintf(buf, buf_size, "*(%s *)(%s)", cast, tmp);
2409 // only for func float args pushes
2410 ferr_assert(po, po->op == OP_PUSH);
2411 u.i = po->operand[0].val;
2412 if (ceilf(u.f) == u.f)
2413 snprintf(buf, buf_size, "%.1ff", u.f);
2415 snprintf(buf, buf_size, "%.8ff", u.f);
2419 ferr(po, "invalid float type: %d\n", popr->type);
2425 static char *out_src_opr_float(char *buf, size_t buf_size,
2426 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2428 return out_opr_float(buf, buf_size, po, popr, 1, need_float_stack);
2431 static char *out_dst_opr_float(char *buf, size_t buf_size,
2432 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2434 return out_opr_float(buf, buf_size, po, popr, 0, need_float_stack);
2437 static void out_test_for_cc(char *buf, size_t buf_size,
2438 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2439 enum opr_lenmod lmod, const char *expr)
2441 const char *cast, *scast;
2443 cast = lmod_cast_u(po, lmod);
2444 scast = lmod_cast_s(po, lmod);
2448 case PFO_BE: // CF==1||ZF==1; CF=0
2449 snprintf(buf, buf_size, "(%s%s %s 0)",
2450 cast, expr, is_inv ? "!=" : "==");
2454 case PFO_L: // SF!=OF; OF=0
2455 snprintf(buf, buf_size, "(%s%s %s 0)",
2456 scast, expr, is_inv ? ">=" : "<");
2459 case PFO_LE: // ZF==1||SF!=OF; OF=0
2460 snprintf(buf, buf_size, "(%s%s %s 0)",
2461 scast, expr, is_inv ? ">" : "<=");
2466 snprintf(buf, buf_size, "(%d)", !!is_inv);
2469 case PFO_P: // PF==1
2470 snprintf(buf, buf_size, "(%sdo_parity(%s))",
2471 is_inv ? "!" : "", expr);
2475 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2479 static void out_cmp_for_cc(char *buf, size_t buf_size,
2480 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2483 const char *cast, *scast, *cast_use;
2484 char buf1[256], buf2[256];
2485 enum opr_lenmod lmod;
2487 if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2488 ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2489 po->operand[0].lmod, po->operand[1].lmod);
2490 lmod = po->operand[0].lmod;
2492 cast = lmod_cast_u(po, lmod);
2493 scast = lmod_cast_s(po, lmod);
2509 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2512 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2513 if (po->op == OP_DEC)
2514 snprintf(buf2, sizeof(buf2), "1");
2517 snprintf(cast_op2, sizeof(cast_op2) - 1, "%s", cast_use);
2519 strcat(cast_op2, "-");
2520 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_op2, 0);
2525 // note: must be unsigned compare
2526 snprintf(buf, buf_size, "(%s %s %s)",
2527 buf1, is_inv ? ">=" : "<", buf2);
2531 snprintf(buf, buf_size, "(%s %s %s)",
2532 buf1, is_inv ? "!=" : "==", buf2);
2536 // note: must be unsigned compare
2537 snprintf(buf, buf_size, "(%s %s %s)",
2538 buf1, is_inv ? ">" : "<=", buf2);
2541 if (is_inv && lmod == OPLM_BYTE
2542 && po->operand[1].type == OPT_CONST
2543 && po->operand[1].val == 0xff)
2545 snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2546 snprintf(buf, buf_size, "(0)");
2550 // note: must be signed compare
2552 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2553 scast, buf1, buf2, is_inv ? ">=" : "<");
2557 snprintf(buf, buf_size, "(%s %s %s)",
2558 buf1, is_inv ? ">=" : "<", buf2);
2562 snprintf(buf, buf_size, "(%s %s %s)",
2563 buf1, is_inv ? ">" : "<=", buf2);
2571 static void out_cmp_test(char *buf, size_t buf_size,
2572 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2574 char buf1[256], buf2[256], buf3[256];
2576 if (po->op == OP_TEST) {
2577 if (IS(opr_name(po, 0), opr_name(po, 1))) {
2578 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2581 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2582 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2583 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2585 out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2586 po->operand[0].lmod, buf3);
2588 else if (po->op == OP_CMP) {
2589 out_cmp_for_cc(buf, buf_size, po, pfo, is_inv, 0);
2592 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2595 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2596 struct parsed_opr *popr2)
2598 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2599 ferr(po, "missing lmod for both operands\n");
2601 if (popr1->lmod == OPLM_UNSPEC)
2602 popr1->lmod = popr2->lmod;
2603 else if (popr2->lmod == OPLM_UNSPEC)
2604 popr2->lmod = popr1->lmod;
2605 else if (popr1->lmod != popr2->lmod) {
2606 if (popr1->type_from_var) {
2607 popr1->size_mismatch = 1;
2608 if (popr1->lmod < popr2->lmod)
2610 popr1->lmod = popr2->lmod;
2612 else if (popr2->type_from_var) {
2613 popr2->size_mismatch = 1;
2614 if (popr2->lmod < popr1->lmod)
2616 popr2->lmod = popr1->lmod;
2619 ferr(po, "conflicting lmods: %d vs %d\n",
2620 popr1->lmod, popr2->lmod);
2624 static const char *op_to_c(struct parsed_op *po)
2648 ferr(po, "op_to_c was supplied with %d\n", po->op);
2652 // last op in stream - unconditional branch or ret
2653 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2654 || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2655 && ops[_i].op != OP_CALL))
2657 #define check_i(po, i) \
2659 ferr(po, "bad " #i ": %d\n", i)
2661 // note: this skips over calls and rm'd stuff assuming they're handled
2662 // so it's intended to use at one of final passes
2663 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2664 int depth, int seen_noreturn, int flags_set)
2666 struct parsed_op *po;
2671 for (; i < opcnt; i++) {
2673 if (po->cc_scratch == magic)
2674 return ret; // already checked
2675 po->cc_scratch = magic;
2677 if (po->flags & OPF_TAIL) {
2678 if (po->op == OP_CALL) {
2679 if (po->pp != NULL && po->pp->is_noreturn)
2688 if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
2691 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2692 if (po->btj != NULL) {
2694 for (j = 0; j < po->btj->count; j++) {
2695 check_i(po, po->btj->d[j].bt_i);
2696 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2697 depth, seen_noreturn, flags_set);
2699 return ret; // dead end
2704 check_i(po, po->bt_i);
2705 if (po->flags & OPF_CJMP) {
2706 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2707 depth, seen_noreturn, flags_set);
2709 return ret; // dead end
2718 if ((po->op == OP_POP || po->op == OP_PUSH)
2719 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2724 if (po->op == OP_PUSH) {
2727 else if (po->op == OP_POP) {
2728 if (relevant && depth == 0) {
2729 po->flags |= flags_set;
2737 // for noreturn, assume msvc skipped stack cleanup
2738 return seen_noreturn ? 1 : -1;
2741 // scan for 'reg' pop backwards starting from i
2742 // intended to use for register restore search, so other reg
2743 // references are considered an error
2744 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2746 struct parsed_op *po;
2747 struct label_ref *lr;
2750 ops[i].cc_scratch = magic;
2754 if (g_labels[i] != NULL) {
2755 lr = &g_label_refs[i];
2756 for (; lr != NULL; lr = lr->next) {
2757 check_i(&ops[i], lr->i);
2758 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2762 if (i > 0 && LAST_OP(i - 1))
2770 if (ops[i].cc_scratch == magic)
2772 ops[i].cc_scratch = magic;
2775 if (po->op == OP_POP && po->operand[0].reg == reg) {
2776 if (po->flags & (OPF_RMD|OPF_DONE))
2779 po->flags |= set_flags;
2783 // this also covers the case where we reach corresponding push
2784 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2788 // nothing interesting on this path,
2789 // still return ret for something recursive calls could find
2793 static void find_reachable_exits(int i, int opcnt, int magic,
2794 int *exits, int *exit_count)
2796 struct parsed_op *po;
2799 for (; i < opcnt; i++)
2802 if (po->cc_scratch == magic)
2804 po->cc_scratch = magic;
2806 if (po->flags & OPF_TAIL) {
2807 ferr_assert(po, *exit_count < MAX_EXITS);
2808 exits[*exit_count] = i;
2813 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2814 if (po->flags & OPF_RMD)
2817 if (po->btj != NULL) {
2818 for (j = 0; j < po->btj->count; j++) {
2819 check_i(po, po->btj->d[j].bt_i);
2820 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2826 check_i(po, po->bt_i);
2827 if (po->flags & OPF_CJMP)
2828 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2836 // scan for 'reg' pop backwards starting from exits (all paths)
2837 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2839 static int exits[MAX_EXITS];
2840 static int exit_count;
2846 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2848 ferr_assert(&ops[i], exit_count > 0);
2851 for (j = 0; j < exit_count; j++) {
2853 ret = scan_for_rsave_pop_reg(e, i + opcnt * 16 + set_flags,
2859 if (ops[e].op == OP_CALL && ops[e].pp != NULL
2860 && ops[e].pp->is_noreturn)
2862 // assume stack cleanup was skipped
2871 // scan for one or more pop of push <const>
2872 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2873 int push_i, int is_probe)
2875 struct parsed_op *po;
2876 struct label_ref *lr;
2880 for (; i < opcnt; i++)
2883 if (po->cc_scratch == magic)
2884 return ret; // already checked
2885 po->cc_scratch = magic;
2887 if (po->flags & OPF_JMP) {
2888 if (po->flags & OPF_RMD)
2890 if (po->op == OP_CALL)
2893 if (po->btj != NULL) {
2894 for (j = 0; j < po->btj->count; j++) {
2895 check_i(po, po->btj->d[j].bt_i);
2896 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2904 check_i(po, po->bt_i);
2905 if (po->flags & OPF_CJMP) {
2906 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2917 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2920 if (g_labels[i] != NULL) {
2921 // all refs must be visited
2922 lr = &g_label_refs[i];
2923 for (; lr != NULL; lr = lr->next) {
2925 if (ops[lr->i].cc_scratch != magic)
2928 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2932 if (po->op == OP_POP)
2934 if (po->flags & (OPF_RMD|OPF_DONE))
2938 po->flags |= OPF_DONE;
2939 po->datap = &ops[push_i];
2948 static void scan_for_pop_const(int i, int opcnt, int magic)
2952 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
2954 ops[i].flags |= OPF_RMD | OPF_DONE;
2955 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
2959 // check if all branch targets within a marked path are also marked
2960 // note: the path checked must not be empty or end with a branch
2961 static int check_path_branches(int opcnt, int magic)
2963 struct parsed_op *po;
2966 for (i = 0; i < opcnt; i++) {
2968 if (po->cc_scratch != magic)
2971 if (po->flags & OPF_JMP) {
2972 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
2975 if (po->btj != NULL) {
2976 for (j = 0; j < po->btj->count; j++) {
2977 check_i(po, po->btj->d[j].bt_i);
2978 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
2983 check_i(po, po->bt_i);
2984 if (ops[po->bt_i].cc_scratch != magic)
2986 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
2994 // scan for multiple pushes for given pop
2995 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
2998 int reg = ops[pop_i].operand[0].reg;
2999 struct parsed_op *po;
3000 struct label_ref *lr;
3003 ops[i].cc_scratch = magic;
3007 if (g_labels[i] != NULL) {
3008 lr = &g_label_refs[i];
3009 for (; lr != NULL; lr = lr->next) {
3010 check_i(&ops[i], lr->i);
3011 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
3015 if (i > 0 && LAST_OP(i - 1))
3023 if (ops[i].cc_scratch == magic)
3025 ops[i].cc_scratch = magic;
3028 if (po->op == OP_CALL)
3030 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
3033 if (po->op == OP_PUSH)
3035 if (po->datap != NULL)
3037 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
3038 // leave this case for reg save/restore handlers
3042 po->flags |= OPF_PPUSH | OPF_DONE;
3043 po->datap = &ops[pop_i];
3052 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
3054 int magic = i + opcnt * 14;
3057 ret = scan_pushes_for_pop_r(i, magic, i, 1);
3059 ret = check_path_branches(opcnt, magic);
3061 ops[i].flags |= OPF_PPUSH | OPF_DONE;
3062 *regmask_pp |= 1 << ops[i].operand[0].reg;
3063 scan_pushes_for_pop_r(i, magic + 1, i, 0);
3068 static void scan_propagate_df(int i, int opcnt)
3070 struct parsed_op *po = &ops[i];
3073 for (; i < opcnt; i++) {
3075 if (po->flags & OPF_DF)
3076 return; // already resolved
3077 po->flags |= OPF_DF;
3079 if (po->op == OP_CALL)
3080 ferr(po, "call with DF set?\n");
3082 if (po->flags & OPF_JMP) {
3083 if (po->btj != NULL) {
3085 for (j = 0; j < po->btj->count; j++) {
3086 check_i(po, po->btj->d[j].bt_i);
3087 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
3092 if (po->flags & OPF_RMD)
3094 check_i(po, po->bt_i);
3095 if (po->flags & OPF_CJMP)
3096 scan_propagate_df(po->bt_i, opcnt);
3102 if (po->flags & OPF_TAIL)
3105 if (po->op == OP_CLD) {
3106 po->flags |= OPF_RMD | OPF_DONE;
3111 ferr(po, "missing DF clear?\n");
3114 // is operand 'opr' referenced by parsed_op 'po'?
3115 static int is_opr_referenced(const struct parsed_opr *opr,
3116 const struct parsed_op *po)
3120 if (opr->type == OPT_REG) {
3121 mask = po->regmask_dst | po->regmask_src;
3122 if (po->op == OP_CALL)
3123 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
3124 if ((1 << opr->reg) & mask)
3130 for (i = 0; i < po->operand_cnt; i++)
3131 if (IS(po->operand[0].name, opr->name))
3137 // is operand 'opr' read by parsed_op 'po'?
3138 static int is_opr_read(const struct parsed_opr *opr,
3139 const struct parsed_op *po)
3141 if (opr->type == OPT_REG) {
3142 if (po->regmask_src & (1 << opr->reg))
3152 // is operand 'opr' modified by parsed_op 'po'?
3153 static int is_opr_modified(const struct parsed_opr *opr,
3154 const struct parsed_op *po)
3158 if (opr->type == OPT_REG) {
3159 if (po->op == OP_CALL) {
3160 mask = po->regmask_dst;
3161 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
3162 if (mask & (1 << opr->reg))
3168 if (po->regmask_dst & (1 << opr->reg))
3174 return IS(po->operand[0].name, opr->name);
3177 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
3178 static int is_any_opr_modified(const struct parsed_op *po_test,
3179 const struct parsed_op *po, int c_mode)
3184 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
3187 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3190 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
3193 // in reality, it can wreck any register, but in decompiled C
3194 // version it can only overwrite eax or edx:eax
3195 mask = (1 << xAX) | (1 << xDX);
3199 if (po->op == OP_CALL
3200 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
3203 for (i = 0; i < po_test->operand_cnt; i++)
3204 if (IS(po_test->operand[i].name, po->operand[0].name))
3210 // scan for any po_test operand modification in range given
3211 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
3214 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3217 for (; i < opcnt; i++) {
3218 if (is_any_opr_modified(po_test, &ops[i], c_mode))
3225 // scan for po_test operand[0] modification in range given
3226 static int scan_for_mod_opr0(struct parsed_op *po_test,
3229 for (; i < opcnt; i++) {
3230 if (is_opr_modified(&po_test->operand[0], &ops[i]))
3237 static int try_resolve_const(int i, const struct parsed_opr *opr,
3238 int magic, unsigned int *val);
3240 static int scan_for_flag_set(int i, int opcnt, int magic,
3241 int *branched, int *setters, int *setter_cnt)
3243 struct label_ref *lr;
3247 if (ops[i].cc_scratch == magic) {
3248 // is this a problem?
3249 //ferr(&ops[i], "%s looped\n", __func__);
3252 ops[i].cc_scratch = magic;
3254 if (g_labels[i] != NULL) {
3257 lr = &g_label_refs[i];
3258 for (; lr->next; lr = lr->next) {
3259 check_i(&ops[i], lr->i);
3260 ret = scan_for_flag_set(lr->i, opcnt, magic,
3261 branched, setters, setter_cnt);
3266 check_i(&ops[i], lr->i);
3267 if (i > 0 && LAST_OP(i - 1)) {
3271 ret = scan_for_flag_set(lr->i, opcnt, magic,
3272 branched, setters, setter_cnt);
3278 if (ops[i].flags & OPF_FLAGS) {
3279 setters[*setter_cnt] = i;
3282 if (ops[i].flags & OPF_REP) {
3283 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
3286 ret = try_resolve_const(i, &opr, i + opcnt * 7, &uval);
3287 if (ret != 1 || uval == 0) {
3288 // can't treat it as full setter because of ecx=0 case,
3289 // also disallow delayed compare
3298 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3305 // scan back for cdq, if anything modifies edx, fail
3306 static int scan_for_cdq_edx(int i)
3309 if (g_labels[i] != NULL) {
3310 if (g_label_refs[i].next != NULL)
3312 if (i > 0 && LAST_OP(i - 1)) {
3313 i = g_label_refs[i].i;
3320 if (ops[i].op == OP_CDQ)
3323 if (ops[i].regmask_dst & (1 << xDX))
3330 static int scan_for_reg_clear(int i, int reg)
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_XOR
3345 && ops[i].operand[0].lmod == OPLM_DWORD
3346 && ops[i].operand[0].reg == ops[i].operand[1].reg
3347 && ops[i].operand[0].reg == reg)
3350 if (ops[i].regmask_dst & (1 << reg))
3357 static void patch_esp_adjust(struct parsed_op *po, int adj)
3359 ferr_assert(po, po->op == OP_ADD);
3360 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3361 ferr_assert(po, po->operand[1].type == OPT_CONST);
3363 // this is a bit of a hack, but deals with use of
3364 // single adj for multiple calls
3365 po->operand[1].val -= adj;
3366 po->flags |= OPF_RMD;
3367 if (po->operand[1].val == 0)
3368 po->flags |= OPF_DONE;
3369 ferr_assert(po, (int)po->operand[1].val >= 0);
3372 // scan for positive, constant esp adjust
3373 // multipath case is preliminary
3374 static int scan_for_esp_adjust(int i, int opcnt,
3375 int adj_expect, int *adj, int *is_multipath, int do_update)
3377 int adj_expect_unknown = 0;
3378 struct parsed_op *po;
3382 *adj = *is_multipath = 0;
3383 if (adj_expect < 0) {
3384 adj_expect_unknown = 1;
3385 adj_expect = 32 * 4; // enough?
3388 for (; i < opcnt && *adj < adj_expect; i++) {
3389 if (g_labels[i] != NULL)
3393 if (po->flags & OPF_DONE)
3396 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3397 if (po->operand[1].type != OPT_CONST)
3398 ferr(&ops[i], "non-const esp adjust?\n");
3399 *adj += po->operand[1].val;
3401 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3404 patch_esp_adjust(po, adj_expect);
3406 po->flags |= OPF_RMD;
3410 else if (po->op == OP_PUSH) {
3411 //if (first_pop == -1)
3412 // first_pop = -2; // none
3413 *adj -= lmod_bytes(po, po->operand[0].lmod);
3415 else if (po->op == OP_POP) {
3416 if (!(po->flags & OPF_DONE)) {
3417 // seems like msvc only uses 'pop ecx' for stack realignment..
3418 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3420 if (first_pop == -1 && *adj >= 0)
3423 if (do_update && *adj >= 0) {
3424 po->flags |= OPF_RMD;
3426 po->flags |= OPF_DONE | OPF_NOREGS;
3429 *adj += lmod_bytes(po, po->operand[0].lmod);
3430 if (*adj > adj_best)
3433 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3434 if (po->op == OP_JMP && po->btj == NULL) {
3440 if (po->op != OP_CALL)
3442 if (po->operand[0].type != OPT_LABEL)
3444 if (po->pp != NULL && po->pp->is_stdcall)
3446 if (adj_expect_unknown && first_pop >= 0)
3448 // assume it's another cdecl call
3452 if (first_pop >= 0) {
3453 // probably only 'pop ecx' was used
3461 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3463 struct parsed_op *po;
3467 ferr(ops, "%s: followed bad branch?\n", __func__);
3469 for (; i < opcnt; i++) {
3471 if (po->cc_scratch == magic)
3473 po->cc_scratch = magic;
3476 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3477 if (po->btj != NULL) {
3479 for (j = 0; j < po->btj->count; j++)
3480 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3484 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3485 if (!(po->flags & OPF_CJMP))
3488 if (po->flags & OPF_TAIL)
3493 static const struct parsed_proto *try_recover_pp(
3494 struct parsed_op *po, const struct parsed_opr *opr,
3495 int is_call, int *search_instead)
3497 const struct parsed_proto *pp = NULL;
3501 // maybe an arg of g_func?
3502 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3504 char ofs_reg[16] = { 0, };
3505 int arg, arg_s, arg_i;
3512 parse_stack_access(po, opr->name, ofs_reg,
3513 &offset, &stack_ra, NULL, 0);
3514 if (ofs_reg[0] != 0)
3515 ferr(po, "offset reg on arg access?\n");
3516 if (offset <= stack_ra) {
3517 // search who set the stack var instead
3518 if (search_instead != NULL)
3519 *search_instead = 1;
3523 arg_i = (offset - stack_ra - 4) / 4;
3524 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3525 if (g_func_pp->arg[arg].reg != NULL)
3531 if (arg == g_func_pp->argc)
3532 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3534 pp = g_func_pp->arg[arg].pp;
3537 ferr(po, "icall arg: arg%d has no pp\n", arg + 1);
3538 check_func_pp(po, pp, "icall arg");
3541 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3543 p = strchr(opr->name + 1, '[');
3544 memcpy(buf, opr->name, p - opr->name);
3545 buf[p - opr->name] = 0;
3546 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3548 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3549 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3552 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3555 check_func_pp(po, pp, "reg-fptr ref");
3561 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3562 int magic, const struct parsed_proto **pp_found, int *pp_i,
3565 const struct parsed_proto *pp = NULL;
3566 struct parsed_op *po;
3567 struct label_ref *lr;
3569 ops[i].cc_scratch = magic;
3572 if (g_labels[i] != NULL) {
3573 lr = &g_label_refs[i];
3574 for (; lr != NULL; lr = lr->next) {
3575 check_i(&ops[i], lr->i);
3576 scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3578 if (i > 0 && LAST_OP(i - 1))
3586 if (ops[i].cc_scratch == magic)
3588 ops[i].cc_scratch = magic;
3590 if (!(ops[i].flags & OPF_DATA))
3592 if (!is_opr_modified(opr, &ops[i]))
3594 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3595 // most probably trashed by some processing
3600 opr = &ops[i].operand[1];
3601 if (opr->type != OPT_REG)
3605 po = (i >= 0) ? &ops[i] : ops;
3608 // reached the top - can only be an arg-reg
3609 if (opr->type != OPT_REG || g_func_pp == NULL)
3612 for (i = 0; i < g_func_pp->argc; i++) {
3613 if (g_func_pp->arg[i].reg == NULL)
3615 if (IS(opr->name, g_func_pp->arg[i].reg))
3618 if (i == g_func_pp->argc)
3620 pp = g_func_pp->arg[i].pp;
3622 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3623 i + 1, g_func_pp->arg[i].reg);
3624 check_func_pp(po, pp, "icall reg-arg");
3627 pp = try_recover_pp(po, opr, 1, NULL);
3629 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3630 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3631 || (*pp_found)->is_stdcall != pp->is_stdcall
3632 //|| (*pp_found)->is_fptr != pp->is_fptr
3633 || (*pp_found)->argc != pp->argc
3634 || (*pp_found)->argc_reg != pp->argc_reg
3635 || (*pp_found)->argc_stack != pp->argc_stack)
3637 ferr(po, "icall: parsed_proto mismatch\n");
3647 static void add_label_ref(struct label_ref *lr, int op_i)
3649 struct label_ref *lr_new;
3656 lr_new = calloc(1, sizeof(*lr_new));
3658 lr_new->next = lr->next;
3662 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3664 struct parsed_op *po = &ops[i];
3665 struct parsed_data *pd;
3666 char label[NAMELEN], *p;
3669 p = strchr(po->operand[0].name, '[');
3673 len = p - po->operand[0].name;
3674 strncpy(label, po->operand[0].name, len);
3677 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3678 if (IS(g_func_pd[j].label, label)) {
3684 //ferr(po, "label '%s' not parsed?\n", label);
3687 if (pd->type != OPT_OFFSET)
3688 ferr(po, "label '%s' with non-offset data?\n", label);
3690 // find all labels, link
3691 for (j = 0; j < pd->count; j++) {
3692 for (l = 0; l < opcnt; l++) {
3693 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3694 add_label_ref(&g_label_refs[l], i);
3704 static void clear_labels(int count)
3708 for (i = 0; i < count; i++) {
3709 if (g_labels[i] != NULL) {
3716 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3721 for (i = 0; i < pp->argc; i++) {
3722 if (pp->arg[i].reg != NULL) {
3723 reg = char_array_i(regs_r32,
3724 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3726 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3727 pp->arg[i].reg, pp->name);
3728 regmask |= 1 << reg;
3735 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3740 if (pp->has_retreg) {
3741 for (i = 0; i < pp->argc; i++) {
3742 if (pp->arg[i].type.is_retreg) {
3743 reg = char_array_i(regs_r32,
3744 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3745 ferr_assert(ops, reg >= 0);
3746 regmask |= 1 << reg;
3751 if (strstr(pp->ret_type.name, "int64"))
3752 return regmask | (1 << xAX) | (1 << xDX);
3753 if (IS(pp->ret_type.name, "float")
3754 || IS(pp->ret_type.name, "double"))
3756 return regmask | mxST0;
3758 if (strcasecmp(pp->ret_type.name, "void") == 0)
3761 return regmask | mxAX;
3764 static int are_ops_same(struct parsed_op *po1, struct parsed_op *po2)
3766 return po1->op == po2->op && po1->operand_cnt == po2->operand_cnt
3767 && memcmp(po1->operand, po2->operand,
3768 sizeof(po1->operand[0]) * po1->operand_cnt) == 0;
3771 static void resolve_branches_parse_calls(int opcnt)
3773 static const struct {
3777 unsigned int regmask_src;
3778 unsigned int regmask_dst;
3780 { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3781 { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3782 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3783 // more precise? Wine gets away with just __ftol handler
3784 { "__ftol2", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3785 { "__CIpow", OPP_CIPOW, OPF_FPOP, mxST0|mxST1, mxST0 },
3787 const struct parsed_proto *pp_c;
3788 struct parsed_proto *pp;
3789 struct parsed_data *pd;
3790 struct parsed_op *po;
3791 const char *tmpname;
3796 for (i = 0; i < opcnt; i++)
3802 if (po->datap != NULL) {
3803 pp = calloc(1, sizeof(*pp));
3804 my_assert_not(pp, NULL);
3806 ret = parse_protostr(po->datap, pp);
3808 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3814 if (po->op == OP_CALL) {
3819 else if (po->operand[0].type == OPT_LABEL)
3821 tmpname = opr_name(po, 0);
3822 if (IS_START(tmpname, "loc_")) {
3824 ferr(po, "call to loc_*\n");
3825 // eliminate_seh() must take care of it
3828 if (IS(tmpname, "__alloca_probe"))
3830 if (IS(tmpname, "__SEH_prolog")) {
3831 ferr_assert(po, g_seh_found == 0);
3835 if (IS(tmpname, "__SEH_epilog"))
3838 // convert some calls to pseudo-ops
3839 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3840 if (!IS(tmpname, pseudo_ops[l].name))
3843 po->op = pseudo_ops[l].op;
3844 po->operand_cnt = 0;
3845 po->regmask_src = pseudo_ops[l].regmask_src;
3846 po->regmask_dst = pseudo_ops[l].regmask_dst;
3847 po->flags = pseudo_ops[l].flags;
3848 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3851 if (l < ARRAY_SIZE(pseudo_ops))
3854 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3855 if (!g_header_mode && pp_c == NULL)
3856 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3859 pp = proto_clone(pp_c);
3860 my_assert_not(pp, NULL);
3866 check_func_pp(po, pp, "fptr var call");
3867 if (pp->is_noreturn) {
3868 po->flags |= OPF_TAIL;
3869 po->flags &= ~OPF_ATAIL; // most likely...
3876 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3879 if (po->operand[0].type == OPT_REGMEM) {
3880 pd = try_resolve_jumptab(i, opcnt);
3888 for (l = 0; l < opcnt; l++) {
3889 if (g_labels[l] != NULL
3890 && IS(po->operand[0].name, g_labels[l]))
3892 if (l == i + 1 && po->op == OP_JMP) {
3893 // yet another alignment type..
3894 po->flags |= OPF_RMD|OPF_DONE;
3897 add_label_ref(&g_label_refs[l], i);
3903 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3906 if (po->operand[0].type == OPT_LABEL)
3910 ferr(po, "unhandled branch\n");
3914 po->flags |= OPF_TAIL;
3915 prev_op = i > 0 ? ops[i - 1].op : OP_UD2;
3916 if (prev_op == OP_POP)
3917 po->flags |= OPF_ATAIL;
3918 if (g_stack_fsz + g_bp_frame == 0 && prev_op != OP_PUSH
3919 && (g_func_pp == NULL || g_func_pp->argc_stack > 0))
3921 po->flags |= OPF_ATAIL;
3927 static int resolve_origin(int i, const struct parsed_opr *opr,
3928 int magic, int *op_i, int *is_caller);
3929 static void set_label(int i, const char *name);
3931 static void eliminate_seh_writes(int opcnt)
3933 const struct parsed_opr *opr;
3938 // assume all sf writes above g_seh_size to be seh related
3939 // (probably unsafe but oh well)
3940 for (i = 0; i < opcnt; i++) {
3941 if (ops[i].op != OP_MOV)
3943 opr = &ops[i].operand[0];
3944 if (opr->type != OPT_REGMEM)
3946 if (!is_stack_access(&ops[i], opr))
3950 parse_stack_access(&ops[i], opr->name, ofs_reg, &offset,
3952 if (offset < 0 && offset >= -g_seh_size)
3953 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3957 static void eliminate_seh_finally(int opcnt)
3959 const char *target_name = NULL;
3960 const char *return_name = NULL;
3961 int exits[MAX_EXITS];
3969 for (i = 0; i < opcnt; i++) {
3970 if (ops[i].op != OP_CALL)
3972 if (!IS_START(opr_name(&ops[i], 0), "loc_"))
3974 if (target_name != NULL)
3975 ferr(&ops[i], "multiple finally calls? (last was %s)\n",
3977 target_name = opr_name(&ops[i], 0);
3980 if (g_labels[i + 1] == NULL)
3981 set_label(i + 1, "seh_fin_done");
3982 return_name = g_labels[i + 1];
3990 // find finally code (bt_i is not set because it's call)
3991 for (i = 0; i < opcnt; i++) {
3992 if (g_labels[i] == NULL)
3994 if (!IS(g_labels[i], target_name))
3997 ferr_assert(&ops[i], target_i == -1);
4000 ferr_assert(&ops[0], target_i != -1);
4002 find_reachable_exits(target_i, opcnt, target_i + opcnt * 24,
4003 exits, &exit_count);
4004 ferr_assert(&ops[target_i], exit_count == 1);
4005 ferr_assert(&ops[target_i], ops[exits[0]].op == OP_RET);
4008 // convert to jumps, link
4009 ops[call_i].op = OP_JMP;
4010 ops[call_i].bt_i = target_i;
4011 add_label_ref(&g_label_refs[target_i], call_i);
4013 ops[tgend_i].op = OP_JMP;
4014 ops[tgend_i].flags &= ~OPF_TAIL;
4015 ops[tgend_i].flags |= OPF_JMP;
4016 ops[tgend_i].bt_i = return_i;
4017 ops[tgend_i].operand_cnt = 1;
4018 ops[tgend_i].operand[0].type = OPT_LABEL;
4019 snprintf(ops[tgend_i].operand[0].name, NAMELEN, "%s", return_name);
4020 add_label_ref(&g_label_refs[return_i], tgend_i);
4022 // rm seh finally entry code
4023 for (i = target_i - 1; i >= 0; i--) {
4024 if (g_labels[i] != NULL && g_label_refs[i].i != -1)
4026 if (ops[i].flags & OPF_CJMP)
4028 if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4031 for (i = target_i - 1; i >= 0; i--) {
4032 if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4034 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4038 static void eliminate_seh(int opcnt)
4042 for (i = 0; i < opcnt; i++) {
4043 if (ops[i].op != OP_MOV)
4045 if (ops[i].operand[0].segment != SEG_FS)
4047 if (!IS(opr_name(&ops[i], 0), "0"))
4050 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4051 if (ops[i].operand[1].reg == xSP) {
4052 for (j = i - 1; j >= 0; j--) {
4053 if (ops[j].op != OP_PUSH)
4055 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4057 if (ops[j].operand[0].val == ~0)
4059 if (ops[j].operand[0].type == OPT_REG) {
4061 ret = resolve_origin(j, &ops[j].operand[0],
4062 j + opcnt * 22, &k, NULL);
4064 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4068 ferr(ops, "missing seh terminator\n");
4072 ret = resolve_origin(i, &ops[i].operand[1],
4073 i + opcnt * 23, &k, NULL);
4075 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4079 eliminate_seh_writes(opcnt);
4080 eliminate_seh_finally(opcnt);
4083 static void eliminate_seh_calls(int opcnt)
4085 int epilog_found = 0;
4092 ferr_assert(&ops[i], ops[i].op == OP_PUSH
4093 && ops[i].operand[0].type == OPT_CONST);
4094 g_stack_fsz = g_seh_size + ops[i].operand[0].val;
4095 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4098 ferr_assert(&ops[i], ops[i].op == OP_PUSH
4099 && ops[i].operand[0].type == OPT_OFFSET);
4100 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4103 ferr_assert(&ops[i], ops[i].op == OP_CALL
4104 && IS(opr_name(&ops[i], 0), "__SEH_prolog"));
4105 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4107 for (i++; i < opcnt; i++) {
4108 if (ops[i].op != OP_CALL)
4110 if (!IS(opr_name(&ops[i], 0), "__SEH_epilog"))
4113 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4116 ferr_assert(ops, epilog_found);
4118 eliminate_seh_writes(opcnt);
4119 eliminate_seh_finally(opcnt);
4122 static int scan_prologue(int i, int opcnt, int *ecx_push, int *esp_sub)
4126 for (; i < opcnt; i++)
4127 if (!(ops[i].flags & OPF_DONE))
4130 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4131 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4137 for (; i < opcnt; i++) {
4138 if (i > 0 && g_labels[i] != NULL)
4140 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
4142 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
4143 && ops[i].operand[1].type == OPT_CONST)
4145 g_stack_fsz += opr_const(&ops[i], 1);
4146 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4151 if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
4152 && ops[i].operand[1].type == OPT_CONST)
4154 for (j = i + 1; j < opcnt; j++)
4155 if (!(ops[j].flags & OPF_DONE))
4157 if (ops[j].op == OP_CALL
4158 && IS(opr_name(&ops[j], 0), "__alloca_probe"))
4160 g_stack_fsz += opr_const(&ops[i], 1);
4161 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4162 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4173 static void scan_prologue_epilogue(int opcnt, int *stack_align)
4175 int ecx_push = 0, esp_sub = 0, pusha = 0;
4176 int sandard_epilogue;
4180 if (g_seh_found == 2) {
4181 eliminate_seh_calls(opcnt);
4185 eliminate_seh(opcnt);
4186 // ida treats seh as part of sf
4187 g_stack_fsz = g_seh_size;
4191 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
4192 && ops[1].op == OP_MOV
4193 && IS(opr_name(&ops[1], 0), "ebp")
4194 && IS(opr_name(&ops[1], 1), "esp"))
4197 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4198 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4200 for (i = 2; i < opcnt; i++)
4201 if (!(ops[i].flags & OPF_DONE))
4204 if (ops[i].op == OP_PUSHA) {
4205 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4210 if (ops[i].op == OP_AND && ops[i].operand[0].reg == xSP
4211 && ops[i].operand[1].type == OPT_CONST)
4213 l = ops[i].operand[1].val;
4215 if (j == -1 || (l >> j) != -1)
4216 ferr(&ops[i], "unhandled esp align: %x\n", l);
4217 if (stack_align != NULL)
4218 *stack_align = 1 << j;
4219 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4223 i = scan_prologue(i, opcnt, &ecx_push, &esp_sub);
4227 for (; i < opcnt; i++)
4228 if (ops[i].flags & OPF_TAIL)
4231 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4232 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4238 sandard_epilogue = 0;
4239 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
4241 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4242 // the standard epilogue is sometimes even used without a sf
4243 if (ops[j - 1].op == OP_MOV
4244 && IS(opr_name(&ops[j - 1], 0), "esp")
4245 && IS(opr_name(&ops[j - 1], 1), "ebp"))
4246 sandard_epilogue = 1;
4248 else if (ops[j].op == OP_LEAVE)
4250 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4251 sandard_epilogue = 1;
4253 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
4254 && ops[i].pp->is_noreturn)
4256 // on noreturn, msvc sometimes cleans stack, sometimes not
4261 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4262 ferr(&ops[j], "'pop ebp' expected\n");
4264 if (g_stack_fsz != 0 || sandard_epilogue) {
4265 if (ops[j].op == OP_LEAVE)
4267 else if (sandard_epilogue) // mov esp, ebp
4269 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4272 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4274 ferr(&ops[j], "esp restore expected\n");
4277 if (ecx_push && j >= 0 && ops[j].op == OP_POP
4278 && IS(opr_name(&ops[j], 0), "ecx"))
4280 ferr(&ops[j], "unexpected ecx pop\n");
4285 if (ops[j].op == OP_POPA)
4286 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4288 ferr(&ops[j], "popa expected\n");
4293 } while (i < opcnt);
4296 ferr(ops, "missing ebp epilogue\n");
4301 i = scan_prologue(0, opcnt, &ecx_push, &esp_sub);
4303 if (ecx_push && !esp_sub) {
4304 // could actually be args for a call..
4305 for (; i < opcnt; i++)
4306 if (ops[i].op != OP_PUSH)
4309 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
4310 const struct parsed_proto *pp;
4311 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
4312 j = pp ? pp->argc_stack : 0;
4313 while (i > 0 && j > 0) {
4315 if (ops[i].op == OP_PUSH) {
4316 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
4321 ferr(&ops[i], "unhandled prologue\n");
4325 g_stack_fsz = g_seh_size;
4326 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4327 if (!(ops[i].flags & OPF_RMD))
4337 if (ecx_push || esp_sub)
4342 for (; i < opcnt; i++)
4343 if (ops[i].flags & OPF_TAIL)
4347 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4348 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4353 else if (i < opcnt && (ops[i].flags & OPF_ATAIL)) {
4354 // skip arg updates for arg-reuse tailcall
4355 for (; j >= 0; j--) {
4356 if (ops[j].op != OP_MOV)
4358 if (ops[j].operand[0].type != OPT_REGMEM)
4360 if (strstr(ops[j].operand[0].name, "arg_") == NULL)
4365 if (ecx_push > 0 && !esp_sub) {
4366 for (l = 0; l < ecx_push && j >= 0; l++) {
4367 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
4369 else if (ops[j].op == OP_ADD
4370 && IS(opr_name(&ops[j], 0), "esp")
4371 && ops[j].operand[1].type == OPT_CONST)
4374 l += ops[j].operand[1].val / 4 - 1;
4379 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4382 if (l != ecx_push) {
4383 if (i < opcnt && ops[i].op == OP_CALL
4384 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4386 // noreturn tailcall with no epilogue
4391 ferr(&ops[j], "epilogue scan failed\n");
4398 if (ops[j].op != OP_ADD
4399 || !IS(opr_name(&ops[j], 0), "esp")
4400 || ops[j].operand[1].type != OPT_CONST)
4402 if (i < opcnt && ops[i].op == OP_CALL
4403 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4405 // noreturn tailcall with no epilogue
4410 ferr(&ops[j], "'add esp' expected\n");
4413 if (ops[j].operand[1].val < g_stack_fsz)
4414 ferr(&ops[j], "esp adj is too low (need %d)\n", g_stack_fsz);
4416 ops[j].operand[1].val -= g_stack_fsz; // for stack arg scanner
4417 if (ops[j].operand[1].val == 0)
4418 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4423 } while (i < opcnt);
4426 ferr(ops, "missing esp epilogue\n");
4430 // find an instruction that changed opr before i op
4431 // *op_i must be set to -1 by the caller
4432 // *is_caller is set to 1 if one source is determined to be g_func arg
4433 // returns 1 if found, *op_i is then set to origin
4434 // returns -1 if multiple origins are found
4435 static int resolve_origin(int i, const struct parsed_opr *opr,
4436 int magic, int *op_i, int *is_caller)
4438 struct label_ref *lr;
4442 if (g_labels[i] != NULL) {
4443 lr = &g_label_refs[i];
4444 for (; lr != NULL; lr = lr->next) {
4445 check_i(&ops[i], lr->i);
4446 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4448 if (i > 0 && LAST_OP(i - 1))
4454 if (is_caller != NULL)
4459 if (ops[i].cc_scratch == magic)
4461 ops[i].cc_scratch = magic;
4463 if (!(ops[i].flags & OPF_DATA))
4465 if (!is_opr_modified(opr, &ops[i]))
4469 if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4480 // find an instruction that previously referenced opr
4481 // if multiple results are found - fail
4482 // *op_i must be set to -1 by the caller
4483 // returns 1 if found, *op_i is then set to referencer insn
4484 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4485 int magic, int *op_i)
4487 struct label_ref *lr;
4491 if (g_labels[i] != NULL) {
4492 lr = &g_label_refs[i];
4493 for (; lr != NULL; lr = lr->next) {
4494 check_i(&ops[i], lr->i);
4495 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4497 if (i > 0 && LAST_OP(i - 1))
4505 if (ops[i].cc_scratch == magic)
4507 ops[i].cc_scratch = magic;
4509 if (!is_opr_referenced(opr, &ops[i]))
4520 // adjust datap of all reachable 'op' insns when moving back
4521 // returns 1 if at least 1 op was found
4522 // returns -1 if path without an op was found
4523 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4525 struct label_ref *lr;
4528 if (ops[i].cc_scratch == magic)
4530 ops[i].cc_scratch = magic;
4533 if (g_labels[i] != NULL) {
4534 lr = &g_label_refs[i];
4535 for (; lr != NULL; lr = lr->next) {
4536 check_i(&ops[i], lr->i);
4537 ret |= adjust_prev_op(lr->i, op, magic, datap);
4539 if (i > 0 && LAST_OP(i - 1))
4547 if (ops[i].cc_scratch == magic)
4549 ops[i].cc_scratch = magic;
4551 if (ops[i].op != op)
4554 ops[i].datap = datap;
4559 // find next instruction that reads opr
4560 // *op_i must be set to -1 by the caller
4561 // on return, *op_i is set to first referencer insn
4562 // returns 1 if exactly 1 referencer is found
4563 static int find_next_read(int i, int opcnt,
4564 const struct parsed_opr *opr, int magic, int *op_i)
4566 struct parsed_op *po;
4569 for (; i < opcnt; i++)
4571 if (ops[i].cc_scratch == magic)
4573 ops[i].cc_scratch = magic;
4576 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4577 if (po->btj != NULL) {
4579 for (j = 0; j < po->btj->count; j++) {
4580 check_i(po, po->btj->d[j].bt_i);
4581 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4587 if (po->flags & OPF_RMD)
4589 check_i(po, po->bt_i);
4590 if (po->flags & OPF_CJMP) {
4591 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4600 if (!is_opr_read(opr, po)) {
4602 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4603 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4605 full_opr = po->operand[0].lmod >= opr->lmod;
4607 if (is_opr_modified(opr, po) && full_opr) {
4611 if (po->flags & OPF_TAIL)
4626 // find next instruction that reads opr
4627 // *op_i must be set to -1 by the caller
4628 // on return, *op_i is set to first flag user insn
4629 // returns 1 if exactly 1 flag user is found
4630 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4632 struct parsed_op *po;
4635 for (; i < opcnt; i++)
4637 if (ops[i].cc_scratch == magic)
4639 ops[i].cc_scratch = magic;
4642 if (po->op == OP_CALL)
4644 if (po->flags & OPF_JMP) {
4645 if (po->btj != NULL) {
4647 for (j = 0; j < po->btj->count; j++) {
4648 check_i(po, po->btj->d[j].bt_i);
4649 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4655 if (po->flags & OPF_RMD)
4657 check_i(po, po->bt_i);
4658 if (po->flags & OPF_CJMP)
4665 if (!(po->flags & OPF_CC)) {
4666 if (po->flags & OPF_FLAGS)
4669 if (po->flags & OPF_TAIL)
4685 static int try_resolve_const(int i, const struct parsed_opr *opr,
4686 int magic, unsigned int *val)
4691 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4694 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4697 *val = ops[i].operand[1].val;
4704 static int resolve_used_bits(int i, int opcnt, int reg,
4705 int *mask, int *is_z_check)
4707 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4711 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4715 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4717 fnote(&ops[j], "(first read)\n");
4718 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4721 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4722 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4724 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4725 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4727 *mask = ops[j].operand[1].val;
4728 if (ops[j].operand[0].lmod == OPLM_BYTE
4729 && ops[j].operand[0].name[1] == 'h')
4733 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4736 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4738 *is_z_check = ops[k].pfo == PFO_Z;
4743 static const struct parsed_proto *resolve_deref(int i, int magic,
4744 struct parsed_opr *opr, int level)
4746 struct parsed_opr opr_s = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
4747 const struct parsed_proto *pp = NULL;
4748 int from_caller = 0;
4757 ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4758 if (ret != 2 || len != strlen(opr->name)) {
4759 ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4760 if (ret != 1 || len != strlen(opr->name))
4764 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4769 ret = resolve_origin(i, &opr_s, i + magic, &j, NULL);
4773 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4774 && strlen(ops[j].operand[1].name) == 3
4775 && ops[j].operand[0].lmod == OPLM_DWORD
4776 && ops[j].pp == NULL // no hint
4779 // allow one simple dereference (com/directx)
4780 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4781 ops[j].operand[1].name);
4785 ret = resolve_origin(j, &opr_s, j + magic, &k, NULL);
4790 if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
4793 if (ops[j].pp != NULL) {
4797 else if (ops[j].operand[1].type == OPT_REGMEM) {
4798 pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
4800 // maybe structure ptr in structure
4801 pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
4804 else if (ops[j].operand[1].type == OPT_LABEL)
4805 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4806 else if (ops[j].operand[1].type == OPT_REG) {
4809 ret = resolve_origin(j, &ops[j].operand[1], i + magic,
4811 if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
4812 for (k = 0; k < g_func_pp->argc; k++) {
4813 if (g_func_pp->arg[k].reg == NULL)
4815 if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
4816 pp = g_func_pp->arg[k].pp;
4825 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4827 ferr(&ops[j], "expected struct, got '%s %s'\n",
4828 pp->type.name, pp->name);
4832 return proto_lookup_struct(g_fhdr, pp->type.name, offset);
4835 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4836 int *pp_i, int *multi_src)
4838 const struct parsed_proto *pp = NULL;
4839 int search_advice = 0;
4844 switch (ops[i].operand[0].type) {
4846 // try to resolve struct member calls
4847 pp = resolve_deref(i, i + opcnt * 19, &ops[i].operand[0], 0);
4853 pp = try_recover_pp(&ops[i], &ops[i].operand[0],
4859 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4867 static struct parsed_proto *process_call_early(int i, int opcnt,
4870 struct parsed_op *po = &ops[i];
4871 struct parsed_proto *pp;
4877 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4881 // look for and make use of esp adjust
4883 if (!pp->is_stdcall && pp->argc_stack > 0)
4884 ret = scan_for_esp_adjust(i + 1, opcnt,
4885 pp->argc_stack * 4, &adj, &multipath, 0);
4887 if (pp->argc_stack > adj / 4)
4891 if (ops[ret].op == OP_POP) {
4892 for (j = 1; j < adj / 4; j++) {
4893 if (ops[ret + j].op != OP_POP
4894 || ops[ret + j].operand[0].reg != xCX)
4906 static struct parsed_proto *process_call(int i, int opcnt)
4908 struct parsed_op *po = &ops[i];
4909 const struct parsed_proto *pp_c;
4910 struct parsed_proto *pp;
4911 const char *tmpname;
4912 int call_i = -1, ref_i = -1;
4913 int adj = 0, multipath = 0;
4916 tmpname = opr_name(po, 0);
4921 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4923 if (!pp_c->is_func && !pp_c->is_fptr)
4924 ferr(po, "call to non-func: %s\n", pp_c->name);
4925 pp = proto_clone(pp_c);
4926 my_assert_not(pp, NULL);
4928 // not resolved just to single func
4931 switch (po->operand[0].type) {
4933 // we resolved this call and no longer need the register
4934 po->regmask_src &= ~(1 << po->operand[0].reg);
4936 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4937 && ops[call_i].operand[1].type == OPT_LABEL)
4939 // no other source users?
4940 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4942 if (ret == 1 && call_i == ref_i) {
4943 // and nothing uses it after us?
4945 find_next_read(i + 1, opcnt, &po->operand[0],
4946 i + opcnt * 11, &ref_i);
4948 // then also don't need the source mov
4949 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4961 pp = calloc(1, sizeof(*pp));
4962 my_assert_not(pp, NULL);
4965 ret = scan_for_esp_adjust(i + 1, opcnt,
4966 -1, &adj, &multipath, 0);
4967 if (ret < 0 || adj < 0) {
4968 if (!g_allow_regfunc)
4969 ferr(po, "non-__cdecl indirect call unhandled yet\n");
4970 pp->is_unresolved = 1;
4974 if (adj > ARRAY_SIZE(pp->arg))
4975 ferr(po, "esp adjust too large: %d\n", adj);
4976 pp->ret_type.name = strdup("int");
4977 pp->argc = pp->argc_stack = adj;
4978 for (arg = 0; arg < pp->argc; arg++)
4979 pp->arg[arg].type.name = strdup("int");
4984 // look for and make use of esp adjust
4987 if (!pp->is_stdcall && pp->argc_stack > 0) {
4988 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
4989 ret = scan_for_esp_adjust(i + 1, opcnt,
4990 adj_expect, &adj, &multipath, 0);
4993 if (pp->is_vararg) {
4994 if (adj / 4 < pp->argc_stack) {
4995 fnote(po, "(this call)\n");
4996 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
4997 adj, pp->argc_stack * 4);
4999 // modify pp to make it have varargs as normal args
5001 pp->argc += adj / 4 - pp->argc_stack;
5002 for (; arg < pp->argc; arg++) {
5003 pp->arg[arg].type.name = strdup("int");
5006 if (pp->argc > ARRAY_SIZE(pp->arg))
5007 ferr(po, "too many args for '%s'\n", tmpname);
5009 if (pp->argc_stack > adj / 4) {
5010 if (pp->is_noreturn)
5011 // assume no stack adjust was emited
5013 fnote(po, "(this call)\n");
5014 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
5015 tmpname, pp->argc_stack * 4, adj);
5018 scan_for_esp_adjust(i + 1, opcnt,
5019 pp->argc_stack * 4, &adj, &multipath, 1);
5021 else if (pp->is_vararg)
5022 ferr(po, "missing esp_adjust for vararg func '%s'\n",
5029 static void mark_float_arg(struct parsed_op *po,
5030 struct parsed_proto *pp, int arg, int *regmask_ffca)
5033 po->p_argnum = arg + 1;
5034 ferr_assert(po, pp->arg[arg].datap == NULL);
5035 pp->arg[arg].datap = po;
5036 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
5037 if (regmask_ffca != NULL)
5038 *regmask_ffca |= 1 << arg;
5041 static int check_for_stp(int i, int i_to)
5043 struct parsed_op *po;
5045 for (; i < i_to; i++) {
5047 if (po->op == OP_FST)
5049 if (g_labels[i] != NULL || (po->flags & OPF_JMP))
5051 if (po->op == OP_CALL || po->op == OP_PUSH || po->op == OP_POP)
5053 if (po->op == OP_ADD && po->operand[0].reg == xSP)
5060 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
5063 struct parsed_op *po;
5069 for (base_arg = 0; base_arg < pp->argc; base_arg++)
5070 if (pp->arg[base_arg].reg == NULL)
5073 for (j = i; j > 0; )
5075 ferr_assert(&ops[j], g_labels[j] == NULL);
5079 ferr_assert(po, po->op != OP_PUSH);
5080 if (po->op == OP_FST)
5082 if (po->operand[0].type != OPT_REGMEM)
5084 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
5087 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3)) {
5088 //ferr(po, "offset %d, %d args\n", offset, pp->argc_stack);
5092 arg = base_arg + offset / 4;
5093 mark_float_arg(po, pp, arg, regmask_ffca);
5095 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5096 && po->operand[1].type == OPT_CONST)
5098 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5103 for (arg = base_arg; arg < pp->argc; arg++) {
5104 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
5105 po = pp->arg[arg].datap;
5107 ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
5108 if (po->operand[0].lmod == OPLM_QWORD)
5115 static int collect_call_args_early(int i, struct parsed_proto *pp,
5116 int *regmask, int *regmask_ffca)
5118 struct parsed_op *po;
5123 for (arg = 0; arg < pp->argc; arg++)
5124 if (pp->arg[arg].reg == NULL)
5127 // first see if it can be easily done
5128 for (j = i; j > 0 && arg < pp->argc; )
5130 if (g_labels[j] != NULL)
5135 if (po->op == OP_CALL)
5137 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
5139 else if (po->op == OP_POP)
5141 else if (po->flags & OPF_CJMP)
5143 else if (po->op == OP_PUSH) {
5144 if (po->flags & (OPF_FARG|OPF_FARGNR))
5146 if (!g_header_mode) {
5147 ret = scan_for_mod(po, j + 1, i, 1);
5152 if (pp->arg[arg].type.is_va_list)
5156 for (arg++; arg < pp->argc; arg++)
5157 if (pp->arg[arg].reg == NULL)
5160 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5161 && po->operand[1].type == OPT_CONST)
5163 if (po->flags & (OPF_RMD|OPF_DONE))
5165 if (po->operand[1].val != pp->argc_stack * 4)
5166 ferr(po, "unexpected esp adjust: %d\n",
5167 po->operand[1].val * 4);
5168 ferr_assert(po, pp->argc - arg == pp->argc_stack);
5169 return collect_call_args_no_push(i, pp, regmask_ffca);
5177 for (arg = 0; arg < pp->argc; arg++)
5178 if (pp->arg[arg].reg == NULL)
5181 for (j = i; j > 0 && arg < pp->argc; )
5185 if (ops[j].op == OP_PUSH)
5187 ops[j].p_argnext = -1;
5188 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
5190 k = check_for_stp(j + 1, i);
5192 // push ecx; fstp dword ptr [esp]
5193 ret = parse_stack_esp_offset(&ops[k],
5194 ops[k].operand[0].name, &offset);
5195 if (ret == 0 && offset == 0) {
5196 if (!pp->arg[arg].type.is_float)
5197 ferr(&ops[i], "arg %d should be float\n", arg + 1);
5198 mark_float_arg(&ops[k], pp, arg, regmask_ffca);
5202 if (pp->arg[arg].datap == NULL) {
5203 pp->arg[arg].datap = &ops[j];
5204 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
5205 *regmask |= 1 << ops[j].operand[0].reg;
5208 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5209 ops[j].flags &= ~OPF_RSAVE;
5212 for (arg++; arg < pp->argc; arg++)
5213 if (pp->arg[arg].reg == NULL)
5221 static int sync_argnum(struct parsed_op *po, int argnum)
5223 struct parsed_op *po_tmp;
5225 // see if other branches don't have higher argnum
5226 for (po_tmp = po; po_tmp != NULL; ) {
5227 if (argnum < po_tmp->p_argnum)
5228 argnum = po_tmp->p_argnum;
5229 // note: p_argnext is active on current collect_call_args only
5230 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5233 // make all argnums consistent
5234 for (po_tmp = po; po_tmp != NULL; ) {
5235 if (po_tmp->p_argnum != 0)
5236 po_tmp->p_argnum = argnum;
5237 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5243 static int collect_call_args_r(struct parsed_op *po, int i,
5244 struct parsed_proto *pp, int *regmask, int *arg_grp,
5245 int arg, int argnum, int magic, int need_op_saving, int may_reuse)
5247 struct parsed_proto *pp_tmp;
5248 struct parsed_op *po_tmp;
5249 struct label_ref *lr;
5250 int need_to_save_current;
5251 int arg_grp_current = 0;
5252 int save_args_seen = 0;
5259 ferr(po, "dead label encountered\n");
5263 for (; arg < pp->argc; arg++, argnum++)
5264 if (pp->arg[arg].reg == NULL)
5266 magic = (magic & 0xffffff) | (arg << 24);
5268 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
5270 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
5271 if (ops[j].cc_scratch != magic) {
5272 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
5276 // ok: have already been here
5279 ops[j].cc_scratch = magic;
5281 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
5282 lr = &g_label_refs[j];
5283 if (lr->next != NULL)
5285 for (; lr->next; lr = lr->next) {
5286 check_i(&ops[j], lr->i);
5287 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5289 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5290 arg, argnum, magic, need_op_saving, may_reuse);
5295 check_i(&ops[j], lr->i);
5296 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5298 if (j > 0 && LAST_OP(j - 1)) {
5299 // follow last branch in reverse
5304 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5305 arg, argnum, magic, need_op_saving, may_reuse);
5311 if (ops[j].op == OP_CALL)
5313 if (pp->is_unresolved)
5318 ferr(po, "arg collect %d/%d hit unparsed call '%s'\n",
5319 arg, pp->argc, ops[j].operand[0].name);
5320 if (may_reuse && pp_tmp->argc_stack > 0)
5321 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
5322 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
5324 // esp adjust of 0 means we collected it before
5325 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
5326 && (ops[j].operand[1].type != OPT_CONST
5327 || ops[j].operand[1].val != 0))
5329 if (pp->is_unresolved)
5332 fnote(po, "(this call)\n");
5333 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
5334 arg, pp->argc, ops[j].operand[1].val);
5336 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
5338 if (pp->is_unresolved)
5341 fnote(po, "(this call)\n");
5342 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
5344 else if (ops[j].flags & OPF_CJMP)
5346 if (pp->is_unresolved)
5351 else if (ops[j].op == OP_PUSH
5352 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
5354 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
5357 ops[j].p_argnext = -1;
5358 po_tmp = pp->arg[arg].datap;
5360 ops[j].p_argnext = po_tmp - ops;
5361 pp->arg[arg].datap = &ops[j];
5363 argnum = sync_argnum(&ops[j], argnum);
5365 need_to_save_current = 0;
5367 if (ops[j].operand[0].type == OPT_REG)
5368 reg = ops[j].operand[0].reg;
5370 if (!need_op_saving) {
5371 ret = scan_for_mod(&ops[j], j + 1, i, 1);
5372 need_to_save_current = (ret >= 0);
5374 if (need_op_saving || need_to_save_current) {
5375 // mark this arg as one that needs operand saving
5376 pp->arg[arg].is_saved = 1;
5378 if (save_args_seen & (1 << (argnum - 1))) {
5381 if (arg_grp_current >= MAX_ARG_GRP)
5382 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
5386 else if (ops[j].p_argnum == 0)
5387 ops[j].flags |= OPF_RMD;
5389 // some PUSHes are reused by different calls on other branches,
5390 // but that can't happen if we didn't branch, so they
5391 // can be removed from future searches (handles nested calls)
5393 ops[j].flags |= OPF_FARGNR;
5395 ops[j].flags |= OPF_FARG;
5396 ops[j].flags &= ~OPF_RSAVE;
5398 // check for __VALIST
5399 if (!pp->is_unresolved && g_func_pp != NULL
5400 && pp->arg[arg].type.is_va_list)
5403 ret = resolve_origin(j, &ops[j].operand[0],
5404 magic + 1, &k, NULL);
5405 if (ret == 1 && k >= 0)
5407 if (ops[k].op == OP_LEA) {
5408 if (!g_func_pp->is_vararg)
5409 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
5412 snprintf(buf, sizeof(buf), "arg_%X",
5413 g_func_pp->argc_stack * 4);
5414 if (strstr(ops[k].operand[1].name, buf)
5415 || strstr(ops[k].operand[1].name, "arglist"))
5417 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
5418 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
5419 pp->arg[arg].is_saved = 0;
5423 ferr(&ops[k], "va_list arg detection failed\n");
5425 // check for va_list from g_func_pp arg too
5426 else if (ops[k].op == OP_MOV
5427 && is_stack_access(&ops[k], &ops[k].operand[1]))
5429 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5430 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5432 ops[k].flags |= OPF_RMD | OPF_DONE;
5433 ops[j].flags |= OPF_RMD;
5434 ops[j].p_argpass = ret + 1;
5435 pp->arg[arg].is_saved = 0;
5442 if (pp->arg[arg].is_saved) {
5443 ops[j].flags &= ~OPF_RMD;
5444 ops[j].p_argnum = argnum;
5447 // tracking reg usage
5449 *regmask |= 1 << reg;
5453 if (!pp->is_unresolved) {
5455 for (; arg < pp->argc; arg++, argnum++)
5456 if (pp->arg[arg].reg == NULL)
5459 magic = (magic & 0xffffff) | (arg << 24);
5462 if (ops[j].p_arggrp > arg_grp_current) {
5464 arg_grp_current = ops[j].p_arggrp;
5466 if (ops[j].p_argnum > 0)
5467 save_args_seen |= 1 << (ops[j].p_argnum - 1);
5470 if (arg < pp->argc) {
5471 ferr(po, "arg collect failed for '%s': %d/%d\n",
5472 pp->name, arg, pp->argc);
5476 if (arg_grp_current > *arg_grp)
5477 *arg_grp = arg_grp_current;
5482 static int collect_call_args(struct parsed_op *po, int i,
5483 struct parsed_proto *pp, int *regmask, int magic)
5485 // arg group is for cases when pushes for
5486 // multiple funcs are going on
5487 struct parsed_op *po_tmp;
5492 ret = collect_call_args_r(po, i, pp, regmask, &arg_grp,
5498 // propagate arg_grp
5499 for (a = 0; a < pp->argc; a++) {
5500 if (pp->arg[a].reg != NULL)
5503 po_tmp = pp->arg[a].datap;
5504 while (po_tmp != NULL) {
5505 po_tmp->p_arggrp = arg_grp;
5506 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5511 if (pp->is_unresolved) {
5513 pp->argc_stack += ret;
5514 for (a = 0; a < pp->argc; a++)
5515 if (pp->arg[a].type.name == NULL)
5516 pp->arg[a].type.name = strdup("int");
5522 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5523 int regmask_now, int *regmask,
5524 int regmask_save_now, int *regmask_save,
5525 int *regmask_init, int regmask_arg)
5527 struct parsed_op *po;
5535 for (; i < opcnt; i++)
5538 if (cbits[i >> 3] & (1 << (i & 7)))
5540 cbits[i >> 3] |= (1 << (i & 7));
5542 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5543 if (po->flags & (OPF_RMD|OPF_DONE))
5545 if (po->btj != NULL) {
5546 for (j = 0; j < po->btj->count; j++) {
5547 check_i(po, po->btj->d[j].bt_i);
5548 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5549 regmask_now, regmask, regmask_save_now, regmask_save,
5550 regmask_init, regmask_arg);
5555 check_i(po, po->bt_i);
5556 if (po->flags & OPF_CJMP)
5557 reg_use_pass(po->bt_i, opcnt, cbits,
5558 regmask_now, regmask, regmask_save_now, regmask_save,
5559 regmask_init, regmask_arg);
5565 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5566 && !g_func_pp->is_userstack
5567 && po->operand[0].type == OPT_REG)
5569 reg = po->operand[0].reg;
5570 ferr_assert(po, reg >= 0);
5573 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5574 if (regmask_now & (1 << reg)) {
5575 already_saved = regmask_save_now & (1 << reg);
5576 flags_set = OPF_RSAVE | OPF_DONE;
5579 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, 0);
5581 scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5582 reg, 0, 0, flags_set);
5585 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5587 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5592 ferr_assert(po, !already_saved);
5593 po->flags |= flags_set;
5595 if (regmask_now & (1 << reg)) {
5596 regmask_save_now |= (1 << reg);
5597 *regmask_save |= regmask_save_now;
5602 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5603 reg = po->operand[0].reg;
5604 ferr_assert(po, reg >= 0);
5606 if (regmask_save_now & (1 << reg))
5607 regmask_save_now &= ~(1 << reg);
5609 regmask_now &= ~(1 << reg);
5612 else if (po->op == OP_CALL) {
5613 if ((po->regmask_dst & (1 << xAX))
5614 && !(po->regmask_dst & (1 << xDX)))
5616 if (po->flags & OPF_TAIL)
5617 // don't need eax, will do "return f();" or "f(); return;"
5618 po->regmask_dst &= ~(1 << xAX);
5620 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
5622 find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
5625 po->regmask_dst &= ~(1 << xAX);
5629 // not "full stack" mode and have something in stack
5630 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5631 ferr(po, "float stack is not empty on func call\n");
5634 if (po->flags & OPF_NOREGS)
5637 // if incomplete register is used, clear it on init to avoid
5638 // later use of uninitialized upper part in some situations
5639 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5640 && po->operand[0].lmod != OPLM_DWORD)
5642 reg = po->operand[0].reg;
5643 ferr_assert(po, reg >= 0);
5645 if (!(regmask_now & (1 << reg)))
5646 *regmask_init |= 1 << reg;
5649 regmask_op = po->regmask_src | po->regmask_dst;
5651 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5652 regmask_new &= ~(1 << xSP);
5653 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5654 regmask_new &= ~(1 << xBP);
5656 if (regmask_new != 0)
5657 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5659 if (regmask_op & (1 << xBP)) {
5660 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5661 if (po->regmask_dst & (1 << xBP))
5662 // compiler decided to drop bp frame and use ebp as scratch
5663 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5665 regmask_op &= ~(1 << xBP);
5669 if (po->flags & OPF_FPUSH) {
5670 if (regmask_now & mxST1)
5671 regmask_now |= mxSTa; // switch to "full stack" mode
5672 if (regmask_now & mxSTa)
5673 po->flags |= OPF_FSHIFT;
5674 if (!(regmask_now & mxST7_2)) {
5676 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5680 regmask_now |= regmask_op;
5681 *regmask |= regmask_now;
5684 if (po->flags & OPF_FPOPP) {
5685 if ((regmask_now & mxSTa) == 0)
5686 ferr(po, "float pop on empty stack?\n");
5687 if (regmask_now & mxST7_2)
5688 po->flags |= OPF_FSHIFT;
5689 if (!(regmask_now & mxST7_2))
5690 regmask_now &= ~mxST1_0;
5692 else if (po->flags & OPF_FPOP) {
5693 if ((regmask_now & mxSTa) == 0)
5694 ferr(po, "float pop on empty stack?\n");
5695 if (regmask_now & (mxST7_2 | mxST1))
5696 po->flags |= OPF_FSHIFT;
5697 if (!(regmask_now & mxST7_2)) {
5699 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5703 if (po->flags & OPF_TAIL) {
5704 if (!(regmask_now & mxST7_2)) {
5705 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5706 if (!(regmask_now & mxST0))
5707 ferr(po, "no st0 on float return, mask: %x\n",
5710 else if (regmask_now & mxST1_0)
5711 ferr(po, "float regs on tail: %x\n", regmask_now);
5714 // there is support for "conditional tailcall", sort of
5715 if (!(po->flags & OPF_CC))
5721 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5725 for (i = 0; i < pp->argc; i++)
5726 if (pp->arg[i].reg == NULL)
5730 memmove(&pp->arg[i + 1], &pp->arg[i],
5731 sizeof(pp->arg[0]) * pp->argc_stack);
5732 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5733 pp->arg[i].reg = strdup(reg);
5734 pp->arg[i].type.name = strdup("int");
5739 static void output_std_flag_z(FILE *fout, struct parsed_op *po,
5740 int *pfomask, const char *dst_opr_text)
5742 if (*pfomask & (1 << PFO_Z)) {
5743 fprintf(fout, "\n cond_z = (%s%s == 0);",
5744 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5745 *pfomask &= ~(1 << PFO_Z);
5749 static void output_std_flag_s(FILE *fout, struct parsed_op *po,
5750 int *pfomask, const char *dst_opr_text)
5752 if (*pfomask & (1 << PFO_S)) {
5753 fprintf(fout, "\n cond_s = (%s%s < 0);",
5754 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5755 *pfomask &= ~(1 << PFO_S);
5759 static void output_std_flags(FILE *fout, struct parsed_op *po,
5760 int *pfomask, const char *dst_opr_text)
5762 output_std_flag_z(fout, po, pfomask, dst_opr_text);
5763 output_std_flag_s(fout, po, pfomask, dst_opr_text);
5767 OPP_FORCE_NORETURN = (1 << 0),
5768 OPP_SIMPLE_ARGS = (1 << 1),
5769 OPP_ALIGN = (1 << 2),
5772 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
5775 const char *cconv = "";
5777 if (pp->is_fastcall)
5778 cconv = "__fastcall ";
5779 else if (pp->is_stdcall && pp->argc_reg == 0)
5780 cconv = "__stdcall ";
5782 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5784 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
5785 fprintf(fout, "noreturn ");
5788 static void output_pp(FILE *fout, const struct parsed_proto *pp,
5793 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5797 output_pp_attrs(fout, pp, flags);
5800 fprintf(fout, "%s", pp->name);
5805 for (i = 0; i < pp->argc; i++) {
5807 fprintf(fout, ", ");
5808 if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
5809 && !(flags & OPP_SIMPLE_ARGS))
5812 output_pp(fout, pp->arg[i].pp, 0);
5814 else if (pp->arg[i].type.is_retreg) {
5815 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
5818 fprintf(fout, "%s", pp->arg[i].type.name);
5820 fprintf(fout, " a%d", i + 1);
5823 if (pp->arg[i].type.is_64bit)
5826 if (pp->is_vararg) {
5828 fprintf(fout, ", ");
5829 fprintf(fout, "...");
5834 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
5840 snprintf(buf1, sizeof(buf1), "%d", grp);
5841 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
5846 static void gen_x_cleanup(int opcnt);
5848 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
5850 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
5851 struct parsed_opr *last_arith_dst = NULL;
5852 char buf1[256], buf2[256], buf3[256], cast[64];
5853 struct parsed_proto *pp, *pp_tmp;
5854 struct parsed_data *pd;
5855 int save_arg_vars[MAX_ARG_GRP] = { 0, };
5856 unsigned char cbits[MAX_OPS / 8];
5857 const char *float_type;
5858 const char *float_st0;
5859 const char *float_st1;
5860 int need_float_stack = 0;
5861 int need_float_sw = 0; // status word
5862 int need_tmp_var = 0;
5866 int label_pending = 0;
5867 int need_double = 0;
5868 int stack_align = 0;
5869 int stack_fsz_adj = 0;
5870 int regmask_save = 0; // used regs saved/restored in this func
5871 int regmask_arg; // regs from this function args (fastcall, etc)
5872 int regmask_ret; // regs needed on ret
5873 int regmask_now; // temp
5874 int regmask_init = 0; // regs that need zero initialization
5875 int regmask_pp = 0; // regs used in complex push-pop graph
5876 int regmask_ffca = 0; // float function call args
5877 int regmask = 0; // used regs
5887 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
5888 g_stack_frame_used = 0;
5890 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
5891 regmask_init = g_regmask_init;
5893 g_func_pp = proto_parse(fhdr, funcn, 0);
5894 if (g_func_pp == NULL)
5895 ferr(ops, "proto_parse failed for '%s'\n", funcn);
5897 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
5898 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
5901 // - resolve all branches
5902 // - parse calls with labels
5903 resolve_branches_parse_calls(opcnt);
5906 // - handle ebp/esp frame, remove ops related to it
5907 scan_prologue_epilogue(opcnt, &stack_align);
5909 // handle a case where sf size is unalignment, but is
5910 // placed in a way that elements are still aligned
5911 if (g_stack_fsz & 4) {
5912 for (i = 0; i < g_eqcnt; i++) {
5913 if (g_eqs[i].lmod != OPLM_QWORD)
5915 if (!(g_eqs[i].offset & 4)) {
5924 // - remove dead labels
5925 // - set regs needed at ret
5926 for (i = 0; i < opcnt; i++)
5928 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
5933 if (ops[i].op == OP_RET)
5934 ops[i].regmask_src |= regmask_ret;
5938 // - process trivial calls
5939 for (i = 0; i < opcnt; i++)
5942 if (po->flags & (OPF_RMD|OPF_DONE))
5945 if (po->op == OP_CALL)
5947 pp = process_call_early(i, opcnt, &j);
5949 if (!(po->flags & OPF_ATAIL)) {
5950 // since we know the args, try to collect them
5951 ret = collect_call_args_early(i, pp, ®mask, ®mask_ffca);
5959 // commit esp adjust
5960 if (ops[j].op != OP_POP)
5961 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5963 for (l = 0; l < pp->argc_stack; l++)
5964 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
5968 if (strstr(pp->ret_type.name, "int64"))
5971 po->flags |= OPF_DONE;
5977 // - process calls, stage 2
5978 // - handle some push/pop pairs
5979 // - scan for STD/CLD, propagate DF
5980 // - try to resolve needed x87 status word bits
5981 for (i = 0; i < opcnt; i++)
5986 if (po->flags & OPF_RMD)
5989 if (po->op == OP_CALL)
5991 if (!(po->flags & OPF_DONE)) {
5992 pp = process_call(i, opcnt);
5994 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
5995 // since we know the args, collect them
5996 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
5998 // for unresolved, collect after other passes
6002 ferr_assert(po, pp != NULL);
6004 po->regmask_src |= get_pp_arg_regmask_src(pp);
6005 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
6007 if (po->regmask_dst & mxST0)
6008 po->flags |= OPF_FPUSH;
6010 if (strstr(pp->ret_type.name, "int64"))
6016 if (po->flags & OPF_DONE)
6021 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
6022 && po->operand[0].type == OPT_CONST)
6024 scan_for_pop_const(i, opcnt, i + opcnt * 12);
6029 scan_pushes_for_pop(i, opcnt, ®mask_pp);
6033 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
6034 scan_propagate_df(i + 1, opcnt);
6039 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
6040 ferr(po, "TODO: fnstsw to mem\n");
6041 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
6043 ferr(po, "fnstsw resolve failed\n");
6044 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
6045 (void *)(long)(mask | (z_check << 16)));
6047 ferr(po, "failed to find fcom: %d\n", ret);
6056 // - find POPs for PUSHes, rm both
6057 // - scan for all used registers
6058 memset(cbits, 0, sizeof(cbits));
6059 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
6060 0, ®mask_save, ®mask_init, regmask_arg);
6062 need_float_stack = !!(regmask & mxST7_2);
6065 // - find flag set ops for their users
6066 // - do unresolved calls
6067 // - declare indirect functions
6068 // - other op specific processing
6069 for (i = 0; i < opcnt; i++)
6072 if (po->flags & (OPF_RMD|OPF_DONE))
6075 if (po->flags & OPF_CC)
6077 int setters[16], cnt = 0, branched = 0;
6079 ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
6080 &branched, setters, &cnt);
6081 if (ret < 0 || cnt <= 0)
6082 ferr(po, "unable to trace flag setter(s)\n");
6083 if (cnt > ARRAY_SIZE(setters))
6084 ferr(po, "too many flag setters\n");
6086 for (j = 0; j < cnt; j++)
6088 tmp_op = &ops[setters[j]]; // flag setter
6091 // to get nicer code, we try to delay test and cmp;
6092 // if we can't because of operand modification, or if we
6093 // have arith op, or branch, make it calculate flags explicitly
6094 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
6096 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
6097 pfomask = 1 << po->pfo;
6099 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
6100 pfomask = 1 << po->pfo;
6103 // see if we'll be able to handle based on op result
6104 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
6105 && po->pfo != PFO_Z && po->pfo != PFO_S
6106 && po->pfo != PFO_P)
6108 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
6110 pfomask = 1 << po->pfo;
6113 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
6114 propagate_lmod(tmp_op, &tmp_op->operand[0],
6115 &tmp_op->operand[1]);
6116 if (tmp_op->operand[0].lmod == OPLM_DWORD)
6121 tmp_op->pfomask |= pfomask;
6122 cond_vars |= pfomask;
6124 // note: may overwrite, currently not a problem
6128 if (po->op == OP_RCL || po->op == OP_RCR
6129 || po->op == OP_ADC || po->op == OP_SBB)
6130 cond_vars |= 1 << PFO_C;
6136 cond_vars |= 1 << PFO_Z;
6140 if (po->operand[0].lmod == OPLM_DWORD)
6145 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
6150 // note: resolved non-reg calls are OPF_DONE already
6152 ferr_assert(po, pp != NULL);
6154 if (pp->is_unresolved) {
6155 int regmask_stack = 0;
6156 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
6158 // this is pretty rough guess:
6159 // see ecx and edx were pushed (and not their saved versions)
6160 for (arg = 0; arg < pp->argc; arg++) {
6161 if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
6164 tmp_op = pp->arg[arg].datap;
6166 ferr(po, "parsed_op missing for arg%d\n", arg);
6167 if (tmp_op->operand[0].type == OPT_REG)
6168 regmask_stack |= 1 << tmp_op->operand[0].reg;
6171 if (!((regmask_stack & (1 << xCX))
6172 && (regmask_stack & (1 << xDX))))
6174 if (pp->argc_stack != 0
6175 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
6177 pp_insert_reg_arg(pp, "ecx");
6178 pp->is_fastcall = 1;
6179 regmask_init |= 1 << xCX;
6180 regmask |= 1 << xCX;
6182 if (pp->argc_stack != 0
6183 || ((regmask | regmask_arg) & (1 << xDX)))
6185 pp_insert_reg_arg(pp, "edx");
6186 regmask_init |= 1 << xDX;
6187 regmask |= 1 << xDX;
6191 // note: __cdecl doesn't fall into is_unresolved category
6192 if (pp->argc_stack > 0)
6198 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
6200 // <var> = offset <something>
6201 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
6202 && !IS_START(po->operand[1].name, "off_"))
6204 if (!po->operand[0].pp->is_fptr)
6205 ferr(po, "%s not declared as fptr when it should be\n",
6206 po->operand[0].name);
6207 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
6208 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
6209 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
6210 fnote(po, "var: %s\n", buf1);
6211 fnote(po, "func: %s\n", buf2);
6212 ferr(po, "^ mismatch\n");
6220 if (po->operand[0].lmod == OPLM_DWORD) {
6221 // 32bit division is common, look for it
6222 if (po->op == OP_DIV)
6223 ret = scan_for_reg_clear(i, xDX);
6225 ret = scan_for_cdq_edx(i);
6227 po->flags |= OPF_32BIT;
6236 po->flags |= OPF_RMD | OPF_DONE;
6246 if (po->operand[0].lmod == OPLM_QWORD)
6256 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
6258 find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
6260 po->flags |= OPF_32BIT;
6268 // this might need it's own pass...
6269 if (po->op != OP_FST && po->p_argnum > 0)
6270 save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
6272 // correct for "full stack" mode late enable
6273 if ((po->flags & (OPF_PPUSH|OPF_FPOP|OPF_FPOPP))
6274 && need_float_stack)
6275 po->flags |= OPF_FSHIFT;
6278 float_type = need_double ? "double" : "float";
6279 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
6280 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
6282 // output starts here
6285 fprintf(fout, "// had SEH\n");
6287 // define userstack size
6288 if (g_func_pp->is_userstack) {
6289 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
6290 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
6291 fprintf(fout, "#endif\n");
6294 // the function itself
6295 ferr_assert(ops, !g_func_pp->is_fptr);
6296 output_pp(fout, g_func_pp,
6297 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
6298 fprintf(fout, "\n{\n");
6300 // declare indirect functions
6301 for (i = 0; i < opcnt; i++) {
6303 if (po->flags & OPF_RMD)
6306 if (po->op == OP_CALL) {
6309 ferr(po, "NULL pp\n");
6311 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
6312 if (pp->name[0] != 0) {
6313 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
6314 memcpy(pp->name, "i_", 2);
6316 // might be declared already
6318 for (j = 0; j < i; j++) {
6319 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
6320 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
6330 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
6333 output_pp(fout, pp, OPP_SIMPLE_ARGS);
6334 fprintf(fout, ";\n");
6339 // output LUTs/jumptables
6340 for (i = 0; i < g_func_pd_cnt; i++) {
6342 fprintf(fout, " static const ");
6343 if (pd->type == OPT_OFFSET) {
6344 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
6346 for (j = 0; j < pd->count; j++) {
6348 fprintf(fout, ", ");
6349 fprintf(fout, "&&%s", pd->d[j].u.label);
6353 fprintf(fout, "%s %s[] =\n { ",
6354 lmod_type_u(ops, pd->lmod), pd->label);
6356 for (j = 0; j < pd->count; j++) {
6358 fprintf(fout, ", ");
6359 fprintf(fout, "%u", pd->d[j].u.val);
6362 fprintf(fout, " };\n");
6366 // declare stack frame, va_arg
6369 fprintf(fout, " // stack_fsz_adj %d\n", stack_fsz_adj);
6371 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
6372 if (g_func_lmods & (1 << OPLM_WORD))
6373 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
6374 if (g_func_lmods & (1 << OPLM_BYTE))
6375 fprintf(fout, " u8 b[%d];", g_stack_fsz);
6376 if (g_func_lmods & (1 << OPLM_QWORD))
6377 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
6379 if (stack_align > 8)
6380 ferr(ops, "unhandled stack align of %d\n", stack_align);
6381 else if (stack_align == 8)
6382 fprintf(fout, " u64 align;");
6383 fprintf(fout, " } sf;\n");
6387 if (g_func_pp->is_userstack) {
6388 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
6389 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
6393 if (g_func_pp->is_vararg) {
6394 fprintf(fout, " va_list ap;\n");
6398 // declare arg-registers
6399 for (i = 0; i < g_func_pp->argc; i++) {
6400 if (g_func_pp->arg[i].reg != NULL) {
6401 reg = char_array_i(regs_r32,
6402 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
6403 if (regmask & (1 << reg)) {
6404 if (g_func_pp->arg[i].type.is_retreg)
6405 fprintf(fout, " u32 %s = *r_%s;\n",
6406 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
6408 fprintf(fout, " u32 %s = (u32)a%d;\n",
6409 g_func_pp->arg[i].reg, i + 1);
6412 if (g_func_pp->arg[i].type.is_retreg)
6413 ferr(ops, "retreg '%s' is unused?\n",
6414 g_func_pp->arg[i].reg);
6415 fprintf(fout, " // %s = a%d; // unused\n",
6416 g_func_pp->arg[i].reg, i + 1);
6422 // declare normal registers
6423 regmask_now = regmask & ~regmask_arg;
6424 regmask_now &= ~(1 << xSP);
6425 if (regmask_now & 0x00ff) {
6426 for (reg = 0; reg < 8; reg++) {
6427 if (regmask_now & (1 << reg)) {
6428 fprintf(fout, " u32 %s", regs_r32[reg]);
6429 if (regmask_init & (1 << reg))
6430 fprintf(fout, " = 0");
6431 fprintf(fout, ";\n");
6437 if (regmask_now & 0xff00) {
6438 for (reg = 8; reg < 16; reg++) {
6439 if (regmask_now & (1 << reg)) {
6440 fprintf(fout, " mmxr %s", regs_r32[reg]);
6441 if (regmask_init & (1 << reg))
6442 fprintf(fout, " = { 0, }");
6443 fprintf(fout, ";\n");
6449 if (need_float_stack) {
6450 fprintf(fout, " %s f_st[8];\n", float_type);
6451 fprintf(fout, " int f_stp = 0;\n");
6455 if (regmask_now & 0xff0000) {
6456 for (reg = 16; reg < 24; reg++) {
6457 if (regmask_now & (1 << reg)) {
6458 fprintf(fout, " %s f_st%d", float_type, reg - 16);
6459 if (regmask_init & (1 << reg))
6460 fprintf(fout, " = 0");
6461 fprintf(fout, ";\n");
6468 if (need_float_sw) {
6469 fprintf(fout, " u16 f_sw;\n");
6474 for (reg = 0; reg < 8; reg++) {
6475 if (regmask_save & (1 << reg)) {
6476 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
6482 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6483 if (save_arg_vars[i] == 0)
6485 for (reg = 0; reg < 32; reg++) {
6486 if (save_arg_vars[i] & (1 << reg)) {
6487 fprintf(fout, " u32 %s;\n",
6488 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
6495 for (reg = 0; reg < 32; reg++) {
6496 if (regmask_ffca & (1 << reg)) {
6497 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
6503 // declare push-pop temporaries
6505 for (reg = 0; reg < 8; reg++) {
6506 if (regmask_pp & (1 << reg)) {
6507 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
6514 for (i = 0; i < 8; i++) {
6515 if (cond_vars & (1 << i)) {
6516 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
6523 fprintf(fout, " u32 tmp;\n");
6528 fprintf(fout, " u64 tmp64;\n");
6533 fprintf(fout, "\n");
6535 // do stack clear, if needed
6536 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6538 if (g_stack_clear_len != 0) {
6539 if (g_stack_clear_len <= 4) {
6540 for (i = 0; i < g_stack_clear_len; i++)
6541 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6542 fprintf(fout, "0;\n");
6545 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6546 g_stack_clear_start, g_stack_clear_len * 4);
6550 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6553 if (g_func_pp->is_vararg) {
6554 if (g_func_pp->argc_stack == 0)
6555 ferr(ops, "vararg func without stack args?\n");
6556 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
6560 for (i = 0; i < opcnt; i++)
6562 if (g_labels[i] != NULL) {
6563 fprintf(fout, "\n%s:\n", g_labels[i]);
6566 delayed_flag_op = NULL;
6567 last_arith_dst = NULL;
6571 if (po->flags & OPF_RMD)
6576 #define assert_operand_cnt(n_) \
6577 if (po->operand_cnt != n_) \
6578 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6580 // conditional/flag using op?
6581 if (po->flags & OPF_CC)
6587 // we go through all this trouble to avoid using parsed_flag_op,
6588 // which makes generated code much nicer
6589 if (delayed_flag_op != NULL)
6591 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6592 po->pfo, po->pfo_inv);
6595 else if (last_arith_dst != NULL
6596 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6597 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6600 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6601 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6602 last_arith_dst->lmod, buf3);
6605 else if (tmp_op != NULL) {
6606 // use preprocessed flag calc results
6607 if (!(tmp_op->pfomask & (1 << po->pfo)))
6608 ferr(po, "not prepared for pfo %d\n", po->pfo);
6610 // note: pfo_inv was not yet applied
6611 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6612 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6615 ferr(po, "all methods of finding comparison failed\n");
6618 if (po->flags & OPF_JMP) {
6619 fprintf(fout, " if %s", buf1);
6621 else if (po->op == OP_RCL || po->op == OP_RCR
6622 || po->op == OP_ADC || po->op == OP_SBB)
6625 fprintf(fout, " cond_%s = %s;\n",
6626 parsed_flag_op_names[po->pfo], buf1);
6628 else if (po->flags & OPF_DATA) { // SETcc
6629 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6630 fprintf(fout, " %s = %s;", buf2, buf1);
6633 ferr(po, "unhandled conditional op\n");
6637 pfomask = po->pfomask;
6642 assert_operand_cnt(2);
6643 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6644 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6645 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
6646 fprintf(fout, " %s = %s;", buf1,
6647 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6652 assert_operand_cnt(2);
6653 po->operand[1].lmod = OPLM_DWORD; // always
6654 fprintf(fout, " %s = %s;",
6655 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6656 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6661 assert_operand_cnt(2);
6662 fprintf(fout, " %s = %s;",
6663 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6664 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6668 assert_operand_cnt(2);
6669 switch (po->operand[1].lmod) {
6671 strcpy(buf3, "(s8)");
6674 strcpy(buf3, "(s16)");
6677 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6679 fprintf(fout, " %s = %s;",
6680 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6681 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6686 assert_operand_cnt(2);
6687 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6688 fprintf(fout, " tmp = %s;",
6689 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6690 fprintf(fout, " %s = %s;",
6691 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6692 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6693 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6694 fprintf(fout, " %s = %stmp;",
6695 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6696 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
6697 snprintf(g_comment, sizeof(g_comment), "xchg");
6701 assert_operand_cnt(1);
6702 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6703 fprintf(fout, " %s = ~%s;", buf1, buf1);
6707 assert_operand_cnt(2);
6708 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6709 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6710 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6711 strcpy(g_comment, "xlat");
6715 assert_operand_cnt(2);
6716 fprintf(fout, " %s = (s32)%s >> 31;",
6717 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6718 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6719 strcpy(g_comment, "cdq");
6723 assert_operand_cnt(1);
6724 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6725 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
6729 if (po->flags & OPF_REP) {
6730 assert_operand_cnt(3);
6735 assert_operand_cnt(2);
6736 fprintf(fout, " %s = %sesi; esi %c= %d;",
6737 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6738 lmod_cast_u_ptr(po, po->operand[1].lmod),
6739 (po->flags & OPF_DF) ? '-' : '+',
6740 lmod_bytes(po, po->operand[1].lmod));
6741 strcpy(g_comment, "lods");
6746 if (po->flags & OPF_REP) {
6747 assert_operand_cnt(3);
6748 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
6749 (po->flags & OPF_DF) ? '-' : '+',
6750 lmod_bytes(po, po->operand[1].lmod));
6751 fprintf(fout, " %sedi = eax;",
6752 lmod_cast_u_ptr(po, po->operand[1].lmod));
6753 strcpy(g_comment, "rep stos");
6756 assert_operand_cnt(2);
6757 fprintf(fout, " %sedi = eax; edi %c= %d;",
6758 lmod_cast_u_ptr(po, po->operand[1].lmod),
6759 (po->flags & OPF_DF) ? '-' : '+',
6760 lmod_bytes(po, po->operand[1].lmod));
6761 strcpy(g_comment, "stos");
6766 j = lmod_bytes(po, po->operand[0].lmod);
6767 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6768 l = (po->flags & OPF_DF) ? '-' : '+';
6769 if (po->flags & OPF_REP) {
6770 assert_operand_cnt(3);
6772 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
6775 " %sedi = %sesi;", buf1, buf1);
6776 strcpy(g_comment, "rep movs");
6779 assert_operand_cnt(2);
6780 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
6781 buf1, buf1, l, j, l, j);
6782 strcpy(g_comment, "movs");
6787 // repe ~ repeat while ZF=1
6788 j = lmod_bytes(po, po->operand[0].lmod);
6789 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6790 l = (po->flags & OPF_DF) ? '-' : '+';
6791 if (po->flags & OPF_REP) {
6792 assert_operand_cnt(3);
6794 " while (ecx != 0) {\n");
6795 if (pfomask & (1 << PFO_C)) {
6798 " cond_c = %sesi < %sedi;\n", buf1, buf1);
6799 pfomask &= ~(1 << PFO_C);
6802 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
6803 buf1, buf1, l, j, l, j);
6806 " if (cond_z %s 0) break;\n",
6807 (po->flags & OPF_REPZ) ? "==" : "!=");
6810 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
6811 (po->flags & OPF_REPZ) ? "e" : "ne");
6814 assert_operand_cnt(2);
6816 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
6817 buf1, buf1, l, j, l, j);
6818 strcpy(g_comment, "cmps");
6820 pfomask &= ~(1 << PFO_Z);
6821 last_arith_dst = NULL;
6822 delayed_flag_op = NULL;
6826 // only does ZF (for now)
6827 // repe ~ repeat while ZF=1
6828 j = lmod_bytes(po, po->operand[1].lmod);
6829 l = (po->flags & OPF_DF) ? '-' : '+';
6830 if (po->flags & OPF_REP) {
6831 assert_operand_cnt(3);
6833 " while (ecx != 0) {\n");
6835 " cond_z = (%seax == %sedi); edi %c= %d;\n",
6836 lmod_cast_u(po, po->operand[1].lmod),
6837 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6840 " if (cond_z %s 0) break;\n",
6841 (po->flags & OPF_REPZ) ? "==" : "!=");
6844 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
6845 (po->flags & OPF_REPZ) ? "e" : "ne");
6848 assert_operand_cnt(2);
6849 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
6850 lmod_cast_u(po, po->operand[1].lmod),
6851 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6852 strcpy(g_comment, "scas");
6854 pfomask &= ~(1 << PFO_Z);
6855 last_arith_dst = NULL;
6856 delayed_flag_op = NULL;
6859 // arithmetic w/flags
6861 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
6862 goto dualop_arith_const;
6863 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6867 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6868 if (po->operand[1].type == OPT_CONST) {
6869 j = lmod_bytes(po, po->operand[0].lmod);
6870 if (((1ull << j * 8) - 1) == po->operand[1].val)
6871 goto dualop_arith_const;
6876 assert_operand_cnt(2);
6877 fprintf(fout, " %s %s= %s;",
6878 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6880 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6881 output_std_flags(fout, po, &pfomask, buf1);
6882 last_arith_dst = &po->operand[0];
6883 delayed_flag_op = NULL;
6887 // and 0, or ~0 used instead mov
6888 assert_operand_cnt(2);
6889 fprintf(fout, " %s = %s;",
6890 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6891 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6892 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6893 output_std_flags(fout, po, &pfomask, buf1);
6894 last_arith_dst = &po->operand[0];
6895 delayed_flag_op = NULL;
6900 assert_operand_cnt(2);
6901 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6902 if (pfomask & (1 << PFO_C)) {
6903 if (po->operand[1].type == OPT_CONST) {
6904 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6905 j = po->operand[1].val;
6908 if (po->op == OP_SHL)
6912 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
6916 ferr(po, "zero shift?\n");
6920 pfomask &= ~(1 << PFO_C);
6922 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
6923 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6924 if (po->operand[1].type != OPT_CONST)
6925 fprintf(fout, " & 0x1f");
6927 output_std_flags(fout, po, &pfomask, buf1);
6928 last_arith_dst = &po->operand[0];
6929 delayed_flag_op = NULL;
6933 assert_operand_cnt(2);
6934 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6935 fprintf(fout, " %s = %s%s >> %s;", buf1,
6936 lmod_cast_s(po, po->operand[0].lmod), buf1,
6937 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6938 output_std_flags(fout, po, &pfomask, buf1);
6939 last_arith_dst = &po->operand[0];
6940 delayed_flag_op = NULL;
6945 assert_operand_cnt(3);
6946 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6947 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6948 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
6949 if (po->operand[2].type != OPT_CONST) {
6950 // no handling for "undefined" case, hopefully not needed
6951 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
6954 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6955 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6956 if (po->op == OP_SHLD) {
6957 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
6958 buf1, buf3, buf1, buf2, l, buf3);
6959 strcpy(g_comment, "shld");
6962 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
6963 buf1, buf3, buf1, buf2, l, buf3);
6964 strcpy(g_comment, "shrd");
6966 output_std_flags(fout, po, &pfomask, buf1);
6967 last_arith_dst = &po->operand[0];
6968 delayed_flag_op = NULL;
6973 assert_operand_cnt(2);
6974 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6975 if (po->operand[1].type == OPT_CONST) {
6976 j = po->operand[1].val;
6977 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
6978 fprintf(fout, po->op == OP_ROL ?
6979 " %s = (%s << %d) | (%s >> %d);" :
6980 " %s = (%s >> %d) | (%s << %d);",
6981 buf1, buf1, j, buf1,
6982 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
6986 output_std_flags(fout, po, &pfomask, buf1);
6987 last_arith_dst = &po->operand[0];
6988 delayed_flag_op = NULL;
6993 assert_operand_cnt(2);
6994 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6995 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6996 if (po->operand[1].type == OPT_CONST) {
6997 j = po->operand[1].val % l;
6999 ferr(po, "zero rotate\n");
7000 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
7001 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
7002 if (po->op == OP_RCL) {
7004 " %s = (%s << %d) | (cond_c << %d)",
7005 buf1, buf1, j, j - 1);
7007 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
7011 " %s = (%s >> %d) | (cond_c << %d)",
7012 buf1, buf1, j, l - j);
7014 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
7016 fprintf(fout, ";\n");
7017 fprintf(fout, " cond_c = tmp;");
7021 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
7022 output_std_flags(fout, po, &pfomask, buf1);
7023 last_arith_dst = &po->operand[0];
7024 delayed_flag_op = NULL;
7028 assert_operand_cnt(2);
7029 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7030 if (IS(opr_name(po, 0), opr_name(po, 1))) {
7031 // special case for XOR
7032 int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
7033 for (j = 0; j <= PFO_LE; j++) {
7034 if (pfomask & (1 << j)) {
7035 fprintf(fout, " cond_%s = %d;\n",
7036 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
7037 pfomask &= ~(1 << j);
7040 fprintf(fout, " %s = 0;",
7041 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7042 last_arith_dst = &po->operand[0];
7043 delayed_flag_op = NULL;
7049 assert_operand_cnt(2);
7050 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7051 if (pfomask & (1 << PFO_C)) {
7052 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7053 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7054 if (po->operand[0].lmod == OPLM_DWORD) {
7055 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
7056 fprintf(fout, " cond_c = tmp64 >> 32;\n");
7057 fprintf(fout, " %s = (u32)tmp64;",
7058 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7059 strcat(g_comment, " add64");
7062 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
7063 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
7064 fprintf(fout, " %s += %s;",
7065 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7068 pfomask &= ~(1 << PFO_C);
7069 output_std_flags(fout, po, &pfomask, buf1);
7070 last_arith_dst = &po->operand[0];
7071 delayed_flag_op = NULL;
7074 if (pfomask & (1 << PFO_LE)) {
7075 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
7076 fprintf(fout, " cond_%s = %s;\n",
7077 parsed_flag_op_names[PFO_LE], buf1);
7078 pfomask &= ~(1 << PFO_LE);
7083 assert_operand_cnt(2);
7084 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7085 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
7086 for (j = 0; j <= PFO_LE; j++) {
7087 if (!(pfomask & (1 << j)))
7089 if (j == PFO_Z || j == PFO_S)
7092 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7093 fprintf(fout, " cond_%s = %s;\n",
7094 parsed_flag_op_names[j], buf1);
7095 pfomask &= ~(1 << j);
7102 assert_operand_cnt(2);
7103 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7104 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7105 if (po->op == OP_SBB
7106 && IS(po->operand[0].name, po->operand[1].name))
7108 // avoid use of unitialized var
7109 fprintf(fout, " %s = -cond_c;", buf1);
7110 // carry remains what it was
7111 pfomask &= ~(1 << PFO_C);
7114 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
7115 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7117 output_std_flags(fout, po, &pfomask, buf1);
7118 last_arith_dst = &po->operand[0];
7119 delayed_flag_op = NULL;
7124 // on SKL, if src is 0, dst is left unchanged
7125 assert_operand_cnt(2);
7126 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7127 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7128 output_std_flag_z(fout, po, &pfomask, buf2);
7129 if (po->op == OP_BSF)
7130 snprintf(buf3, sizeof(buf3), "__builtin_ffs(%s) - 1", buf2);
7132 snprintf(buf3, sizeof(buf3), "31 - __builtin_clz(%s)", buf2);
7133 fprintf(fout, " if (%s) %s = %s;", buf2, buf1, buf3);
7134 last_arith_dst = &po->operand[0];
7135 delayed_flag_op = NULL;
7136 strcat(g_comment, po->op == OP_BSF ? " bsf" : " bsr");
7140 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
7141 for (j = 0; j <= PFO_LE; j++) {
7142 if (!(pfomask & (1 << j)))
7144 if (j == PFO_Z || j == PFO_S || j == PFO_C)
7147 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7148 fprintf(fout, " cond_%s = %s;\n",
7149 parsed_flag_op_names[j], buf1);
7150 pfomask &= ~(1 << j);
7156 if (pfomask & (1 << PFO_C))
7157 // carry is unaffected by inc/dec.. wtf?
7158 ferr(po, "carry propagation needed\n");
7160 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7161 if (po->operand[0].type == OPT_REG) {
7162 strcpy(buf2, po->op == OP_INC ? "++" : "--");
7163 fprintf(fout, " %s%s;", buf1, buf2);
7166 strcpy(buf2, po->op == OP_INC ? "+" : "-");
7167 fprintf(fout, " %s %s= 1;", buf1, buf2);
7169 output_std_flags(fout, po, &pfomask, buf1);
7170 last_arith_dst = &po->operand[0];
7171 delayed_flag_op = NULL;
7175 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7176 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
7177 fprintf(fout, " %s = -%s%s;", buf1,
7178 lmod_cast_s(po, po->operand[0].lmod), buf2);
7179 last_arith_dst = &po->operand[0];
7180 delayed_flag_op = NULL;
7181 if (pfomask & PFOB_C) {
7182 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
7185 output_std_flags(fout, po, &pfomask, buf1);
7189 if (po->operand_cnt == 2) {
7190 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7193 if (po->operand_cnt == 3)
7194 ferr(po, "TODO imul3\n");
7197 assert_operand_cnt(1);
7198 switch (po->operand[0].lmod) {
7200 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
7201 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
7202 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
7203 fprintf(fout, " edx = tmp64 >> 32;\n");
7204 fprintf(fout, " eax = tmp64;");
7207 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
7208 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
7209 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
7213 ferr(po, "TODO: unhandled mul type\n");
7216 last_arith_dst = NULL;
7217 delayed_flag_op = NULL;
7222 assert_operand_cnt(1);
7223 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7224 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
7225 po->op == OP_IDIV));
7226 switch (po->operand[0].lmod) {
7228 if (po->flags & OPF_32BIT)
7229 snprintf(buf2, sizeof(buf2), "%seax", cast);
7231 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7232 snprintf(buf2, sizeof(buf2), "%stmp64",
7233 (po->op == OP_IDIV) ? "(s64)" : "");
7235 if (po->operand[0].type == OPT_REG
7236 && po->operand[0].reg == xDX)
7238 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
7239 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
7242 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
7243 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
7247 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
7248 snprintf(buf2, sizeof(buf2), "%stmp",
7249 (po->op == OP_IDIV) ? "(s32)" : "");
7250 if (po->operand[0].type == OPT_REG
7251 && po->operand[0].reg == xDX)
7253 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
7255 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
7259 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
7261 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
7264 strcat(g_comment, " div16");
7267 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
7269 last_arith_dst = NULL;
7270 delayed_flag_op = NULL;
7275 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7277 for (j = 0; j < 8; j++) {
7278 if (pfomask & (1 << j)) {
7279 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
7280 fprintf(fout, " cond_%s = %s;",
7281 parsed_flag_op_names[j], buf1);
7288 last_arith_dst = NULL;
7289 delayed_flag_op = po;
7293 // SETcc - should already be handled
7296 // note: we reuse OP_Jcc for SETcc, only flags differ
7298 fprintf(fout, "\n goto %s;", po->operand[0].name);
7302 fprintf(fout, " if (ecx == 0)\n");
7303 fprintf(fout, " goto %s;", po->operand[0].name);
7304 strcat(g_comment, " jecxz");
7308 fprintf(fout, " if (--ecx != 0)\n");
7309 fprintf(fout, " goto %s;", po->operand[0].name);
7310 strcat(g_comment, " loop");
7314 assert_operand_cnt(1);
7315 last_arith_dst = NULL;
7316 delayed_flag_op = NULL;
7318 if (po->operand[0].type == OPT_REGMEM) {
7319 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
7322 ferr(po, "parse failure for jmp '%s'\n",
7323 po->operand[0].name);
7324 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
7327 else if (po->operand[0].type != OPT_LABEL)
7328 ferr(po, "unhandled jmp type\n");
7330 fprintf(fout, " goto %s;", po->operand[0].name);
7334 assert_operand_cnt(1);
7336 my_assert_not(pp, NULL);
7339 if (po->flags & OPF_CC) {
7340 // we treat conditional branch to another func
7341 // (yes such code exists..) as conditional tailcall
7343 fprintf(fout, " {\n");
7346 if (pp->is_fptr && !pp->is_arg) {
7347 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
7348 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7350 if (pp->is_unresolved || IS_START(pp->name, "i_guess"))
7351 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
7352 buf3, asmfn, po->asmln, pp->name);
7355 fprintf(fout, "%s", buf3);
7356 if (strstr(pp->ret_type.name, "int64")) {
7357 if (po->flags & OPF_TAIL)
7358 ferr(po, "int64 and tail?\n");
7359 fprintf(fout, "tmp64 = ");
7361 else if (!IS(pp->ret_type.name, "void")) {
7362 if (po->flags & OPF_TAIL) {
7363 if (regmask_ret & mxAX) {
7364 fprintf(fout, "return ");
7365 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
7366 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
7368 else if (regmask_ret & mxST0)
7369 ferr(po, "float tailcall\n");
7371 else if (po->regmask_dst & mxAX) {
7372 fprintf(fout, "eax = ");
7373 if (pp->ret_type.is_ptr)
7374 fprintf(fout, "(u32)");
7376 else if (po->regmask_dst & mxST0) {
7377 ferr_assert(po, po->flags & OPF_FPUSH);
7378 if (need_float_stack)
7379 fprintf(fout, "f_st[--f_stp & 7] = ");
7381 fprintf(fout, "f_st0 = ");
7385 if (pp->name[0] == 0)
7386 ferr(po, "missing pp->name\n");
7387 fprintf(fout, "%s%s(", pp->name,
7388 pp->has_structarg ? "_sa" : "");
7390 if (po->flags & OPF_ATAIL) {
7392 g_func_pp->is_stdcall && g_func_pp->argc_stack > 0;
7393 check_compat |= pp->argc_stack > 0;
7395 && (pp->argc_stack != g_func_pp->argc_stack
7396 || pp->is_stdcall != g_func_pp->is_stdcall))
7397 ferr(po, "incompatible arg-reuse tailcall\n");
7398 if (g_func_pp->has_retreg)
7399 ferr(po, "TODO: retreg+tailcall\n");
7401 for (arg = j = 0; arg < pp->argc; arg++) {
7403 fprintf(fout, ", ");
7406 if (pp->arg[arg].type.is_ptr)
7407 snprintf(cast, sizeof(cast), "(%s)",
7408 pp->arg[arg].type.name);
7410 if (pp->arg[arg].reg != NULL) {
7411 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7415 for (; j < g_func_pp->argc; j++)
7416 if (g_func_pp->arg[j].reg == NULL)
7418 fprintf(fout, "%sa%d", cast, j + 1);
7423 for (arg = 0; arg < pp->argc; arg++) {
7425 fprintf(fout, ", ");
7428 if (pp->arg[arg].type.is_ptr)
7429 snprintf(cast, sizeof(cast), "(%s)",
7430 pp->arg[arg].type.name);
7432 if (pp->arg[arg].reg != NULL) {
7433 if (pp->arg[arg].type.is_retreg)
7434 fprintf(fout, "&%s", pp->arg[arg].reg);
7435 else if (IS(pp->arg[arg].reg, "ebp")
7436 && g_bp_frame && !(po->flags & OPF_EBP_S))
7438 // rare special case
7439 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
7440 strcat(g_comment, " bp_ref");
7443 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7448 tmp_op = pp->arg[arg].datap;
7450 ferr(po, "parsed_op missing for arg%d\n", arg);
7452 if (tmp_op->flags & OPF_VAPUSH) {
7453 fprintf(fout, "ap");
7455 else if (tmp_op->op == OP_FST) {
7456 fprintf(fout, "fs_%d", tmp_op->p_argnum);
7457 if (tmp_op->operand[0].lmod == OPLM_QWORD)
7460 else if (pp->arg[arg].type.is_64bit) {
7461 ferr_assert(po, tmp_op->p_argpass == 0);
7462 ferr_assert(po, !pp->arg[arg].is_saved);
7463 ferr_assert(po, !pp->arg[arg].type.is_float);
7464 ferr_assert(po, cast[0] == 0);
7465 out_src_opr(buf1, sizeof(buf1),
7466 tmp_op, &tmp_op->operand[0], cast, 0);
7467 tmp_op = pp->arg[++arg].datap;
7468 ferr_assert(po, tmp_op != NULL);
7469 out_src_opr(buf2, sizeof(buf2),
7470 tmp_op, &tmp_op->operand[0], cast, 0);
7471 fprintf(fout, "((u64)(%s) << 32) | (%s)",
7474 else if (tmp_op->p_argpass != 0) {
7475 ferr_assert(po, !pp->arg[arg].type.is_float);
7476 fprintf(fout, "a%d", tmp_op->p_argpass);
7478 else if (pp->arg[arg].is_saved) {
7479 ferr_assert(po, tmp_op->p_argnum > 0);
7480 ferr_assert(po, !pp->arg[arg].type.is_float);
7481 fprintf(fout, "%s%s", cast,
7482 saved_arg_name(buf1, sizeof(buf1),
7483 tmp_op->p_arggrp, tmp_op->p_argnum));
7485 else if (pp->arg[arg].type.is_float) {
7486 ferr_assert(po, !pp->arg[arg].type.is_64bit);
7488 out_src_opr_float(buf1, sizeof(buf1),
7489 tmp_op, &tmp_op->operand[0], need_float_stack));
7493 out_src_opr(buf1, sizeof(buf1),
7494 tmp_op, &tmp_op->operand[0], cast, 0));
7498 fprintf(fout, ");");
7500 if (strstr(pp->ret_type.name, "int64")) {
7501 fprintf(fout, "\n");
7502 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7503 fprintf(fout, "%seax = tmp64;", buf3);
7506 if (pp->is_unresolved) {
7507 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
7509 strcat(g_comment, buf2);
7512 if (po->flags & OPF_TAIL) {
7514 if (i == opcnt - 1 || pp->is_noreturn)
7516 else if (IS(pp->ret_type.name, "void"))
7518 else if (!(regmask_ret & (1 << xAX)))
7520 // else already handled as 'return f()'
7523 fprintf(fout, "\n%sreturn;", buf3);
7524 strcat(g_comment, " ^ tailcall");
7527 strcat(g_comment, " tailcall");
7529 if ((regmask_ret & (1 << xAX))
7530 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7532 ferr(po, "int func -> void func tailcall?\n");
7535 if (pp->is_noreturn)
7536 strcat(g_comment, " noreturn");
7537 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7538 strcat(g_comment, " argframe");
7539 if (po->flags & OPF_CC)
7540 strcat(g_comment, " cond");
7542 if (po->flags & OPF_CC)
7543 fprintf(fout, "\n }");
7545 delayed_flag_op = NULL;
7546 last_arith_dst = NULL;
7550 if (g_func_pp->is_vararg)
7551 fprintf(fout, " va_end(ap);\n");
7552 if (g_func_pp->has_retreg) {
7553 for (arg = 0; arg < g_func_pp->argc; arg++)
7554 if (g_func_pp->arg[arg].type.is_retreg)
7555 fprintf(fout, " *r_%s = %s;\n",
7556 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7559 if (regmask_ret & mxST0) {
7560 fprintf(fout, " return %s;", float_st0);
7562 else if (!(regmask_ret & mxAX)) {
7563 if (i != opcnt - 1 || label_pending)
7564 fprintf(fout, " return;");
7566 else if (g_func_pp->ret_type.is_ptr) {
7567 fprintf(fout, " return (%s)eax;",
7568 g_func_pp->ret_type.name);
7570 else if (IS(g_func_pp->ret_type.name, "__int64"))
7571 fprintf(fout, " return ((u64)edx << 32) | eax;");
7573 fprintf(fout, " return eax;");
7575 last_arith_dst = NULL;
7576 delayed_flag_op = NULL;
7580 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7581 if (po->p_argnum != 0) {
7582 // special case - saved func arg
7583 fprintf(fout, " %s = %s;",
7584 saved_arg_name(buf2, sizeof(buf2),
7585 po->p_arggrp, po->p_argnum), buf1);
7588 else if (po->flags & OPF_RSAVE) {
7589 fprintf(fout, " s_%s = %s;", buf1, buf1);
7592 else if (po->flags & OPF_PPUSH) {
7594 ferr_assert(po, tmp_op != NULL);
7595 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7596 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7599 else if (g_func_pp->is_userstack) {
7600 fprintf(fout, " *(--esp) = %s;", buf1);
7603 if (!(g_ida_func_attr & IDAFA_NORETURN))
7604 ferr(po, "stray push encountered\n");
7609 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7610 if (po->flags & OPF_RSAVE) {
7611 fprintf(fout, " %s = s_%s;", buf1, buf1);
7614 else if (po->flags & OPF_PPUSH) {
7615 // push/pop graph / non-const
7616 ferr_assert(po, po->datap == NULL);
7617 fprintf(fout, " %s = pp_%s;", buf1, buf1);
7620 else if (po->datap != NULL) {
7623 fprintf(fout, " %s = %s;", buf1,
7624 out_src_opr(buf2, sizeof(buf2),
7625 tmp_op, &tmp_op->operand[0],
7626 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7629 else if (g_func_pp->is_userstack) {
7630 fprintf(fout, " %s = *esp++;", buf1);
7634 ferr(po, "stray pop encountered\n");
7644 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7645 fprintf(fout, " tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
7646 po->op == OPP_ALLSHL ? "<<" : ">>");
7647 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
7648 strcat(g_comment, po->op == OPP_ALLSHL
7649 ? " allshl" : " allshr");
7654 if (need_float_stack) {
7655 out_src_opr_float(buf1, sizeof(buf1),
7656 po, &po->operand[0], 1);
7657 if (po->regmask_src & mxSTa) {
7658 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7662 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
7665 if (po->flags & OPF_FSHIFT)
7666 fprintf(fout, " f_st1 = f_st0;");
7667 if (po->operand[0].type == OPT_REG
7668 && po->operand[0].reg == xST0)
7670 strcat(g_comment, " fld st");
7673 fprintf(fout, " f_st0 = %s;",
7674 out_src_opr_float(buf1, sizeof(buf1),
7675 po, &po->operand[0], 0));
7677 strcat(g_comment, " fld");
7681 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7682 lmod_cast(po, po->operand[0].lmod, 1), 0);
7683 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7684 if (need_float_stack) {
7685 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
7688 if (po->flags & OPF_FSHIFT)
7689 fprintf(fout, " f_st1 = f_st0;");
7690 fprintf(fout, " f_st0 = %s;", buf2);
7692 strcat(g_comment, " fild");
7696 if (need_float_stack)
7697 fprintf(fout, " f_st[--f_stp & 7] = ");
7699 if (po->flags & OPF_FSHIFT)
7700 fprintf(fout, " f_st1 = f_st0;");
7701 fprintf(fout, " f_st0 = ");
7703 switch (po->operand[0].val) {
7704 case X87_CONST_1: fprintf(fout, "1.0;"); break;
7705 case X87_CONST_L2T: fprintf(fout, "3.321928094887362;"); break;
7706 case X87_CONST_L2E: fprintf(fout, "M_LOG2E;"); break;
7707 case X87_CONST_PI: fprintf(fout, "M_PI;"); break;
7708 case X87_CONST_LG2: fprintf(fout, "0.301029995663981;"); break;
7709 case X87_CONST_LN2: fprintf(fout, "M_LN2;"); break;
7710 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
7711 default: ferr_assert(po, 0); break;
7716 if (po->flags & OPF_FARG) {
7717 // store to stack as func arg
7718 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7722 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7724 dead_dst = po->operand[0].type == OPT_REG
7725 && po->operand[0].reg == xST0;
7728 fprintf(fout, " %s = %s;", buf1, float_st0);
7729 if (po->flags & OPF_FSHIFT) {
7730 if (need_float_stack)
7731 fprintf(fout, " f_stp++;");
7733 fprintf(fout, " f_st0 = f_st1;");
7735 if (dead_dst && !(po->flags & OPF_FSHIFT))
7738 strcat(g_comment, " fst");
7742 fprintf(fout, " %s = %s%s;",
7743 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7744 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7745 if (po->flags & OPF_FSHIFT) {
7746 if (need_float_stack)
7747 fprintf(fout, " f_stp++;");
7749 fprintf(fout, " f_st0 = f_st1;");
7751 strcat(g_comment, " fist");
7758 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7760 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7762 dead_dst = (po->flags & OPF_FPOP)
7763 && po->operand[0].type == OPT_REG
7764 && po->operand[0].reg == xST0;
7766 case OP_FADD: j = '+'; break;
7767 case OP_FDIV: j = '/'; break;
7768 case OP_FMUL: j = '*'; break;
7769 case OP_FSUB: j = '-'; break;
7770 default: j = 'x'; break;
7772 if (need_float_stack) {
7774 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7775 if (po->flags & OPF_FSHIFT)
7776 fprintf(fout, " f_stp++;");
7779 if (po->flags & OPF_FSHIFT) {
7780 // note: assumes only 2 regs handled
7782 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
7784 fprintf(fout, " f_st0 = f_st1;");
7787 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7789 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7794 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7796 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7798 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
7800 dead_dst = (po->flags & OPF_FPOP)
7801 && po->operand[0].type == OPT_REG
7802 && po->operand[0].reg == xST0;
7803 j = po->op == OP_FDIVR ? '/' : '-';
7804 if (need_float_stack) {
7806 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7807 if (po->flags & OPF_FSHIFT)
7808 fprintf(fout, " f_stp++;");
7811 if (po->flags & OPF_FSHIFT) {
7813 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
7815 fprintf(fout, " f_st0 = f_st1;");
7818 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7820 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7828 case OP_FIADD: j = '+'; break;
7829 case OP_FIDIV: j = '/'; break;
7830 case OP_FIMUL: j = '*'; break;
7831 case OP_FISUB: j = '-'; break;
7832 default: j = 'x'; break;
7834 fprintf(fout, " %s %c= (%s)%s;", float_st0,
7836 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7837 lmod_cast(po, po->operand[0].lmod, 1), 0));
7842 fprintf(fout, " %s = %s %c %s;", float_st0,
7843 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7845 po->op == OP_FIDIVR ? '/' : '-', float_st0);
7850 ferr_assert(po, po->datap != NULL);
7851 mask = (long)po->datap & 0xffff;
7852 z_check = ((long)po->datap >> 16) & 1;
7853 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7855 if (mask == 0x0100 || mask == 0x0500) { // C0 -> <
7856 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
7859 else if (mask == 0x4000 || mask == 0x4400) { // C3 -> =
7860 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
7863 else if (mask == 0x4100) { // C3, C0
7865 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
7867 strcat(g_comment, " z_chk_det");
7870 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
7871 "(%s < %s ? 0x0100 : 0);",
7872 float_st0, buf1, float_st0, buf1);
7876 ferr(po, "unhandled sw mask: %x\n", mask);
7877 if (po->flags & OPF_FSHIFT) {
7878 if (need_float_stack) {
7879 if (po->flags & OPF_FPOPP)
7880 fprintf(fout, " f_stp += 2;");
7882 fprintf(fout, " f_stp++;");
7885 ferr_assert(po, !(po->flags & OPF_FPOPP));
7886 fprintf(fout, " f_st0 = f_st1;");
7893 fprintf(fout, " %s = f_sw;",
7894 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7898 fprintf(fout, " %s = -%s;", float_st0, float_st0);
7902 fprintf(fout, " %s = cos%s(%s);", float_st0,
7903 need_double ? "" : "f", float_st0);
7907 if (need_float_stack) {
7908 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
7909 need_double ? "" : "f", float_st1, float_st0);
7910 fprintf(fout, " f_stp++;");
7913 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
7914 need_double ? "" : "f");
7919 if (need_float_stack) {
7920 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
7921 float_st1, need_double ? "" : "f", float_st0);
7922 fprintf(fout, " f_stp++;");
7925 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
7926 need_double ? "" : "f");
7928 strcat(g_comment, " fyl2x");
7932 fprintf(fout, " %s = sin%s(%s);", float_st0,
7933 need_double ? "" : "f", float_st0);
7937 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
7938 need_double ? "" : "f", float_st0);
7942 dead_dst = po->operand[0].type == OPT_REG
7943 && po->operand[0].reg == xST0;
7945 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7947 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
7948 float_st0, float_st0, buf1, buf1);
7949 strcat(g_comment, " fxch");
7956 ferr_assert(po, po->flags & OPF_32BIT);
7957 fprintf(fout, " eax = (s32)%s;", float_st0);
7958 if (po->flags & OPF_FSHIFT) {
7959 if (need_float_stack)
7960 fprintf(fout, " f_stp++;");
7962 fprintf(fout, " f_st0 = f_st1;");
7964 strcat(g_comment, " ftol");
7968 if (need_float_stack) {
7969 fprintf(fout, " %s = pow%s(%s, %s);", float_st1,
7970 need_double ? "" : "f", float_st1, float_st0);
7971 fprintf(fout, " f_stp++;");
7974 fprintf(fout, " f_st0 = pow%s(f_st1, f_st0);",
7975 need_double ? "" : "f");
7977 strcat(g_comment, " CIpow");
7981 fprintf(fout, " do_skip_code_abort();");
7986 fprintf(fout, " do_emms();");
7991 ferr(po, "unhandled op type %d, flags %x\n",
7996 if (g_comment[0] != 0) {
7997 char *p = g_comment;
7998 while (my_isblank(*p))
8000 fprintf(fout, " // %s", p);
8005 fprintf(fout, "\n");
8007 // some sanity checking
8008 if (po->flags & OPF_REP) {
8009 if (po->op != OP_STOS && po->op != OP_MOVS
8010 && po->op != OP_CMPS && po->op != OP_SCAS)
8011 ferr(po, "unexpected rep\n");
8012 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
8013 && (po->op == OP_CMPS || po->op == OP_SCAS))
8014 ferr(po, "cmps/scas with plain rep\n");
8016 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
8017 && po->op != OP_CMPS && po->op != OP_SCAS)
8018 ferr(po, "unexpected repz/repnz\n");
8021 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
8023 // see is delayed flag stuff is still valid
8024 if (delayed_flag_op != NULL && delayed_flag_op != po) {
8025 if (is_any_opr_modified(delayed_flag_op, po, 0))
8026 delayed_flag_op = NULL;
8029 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
8030 if (is_opr_modified(last_arith_dst, po))
8031 last_arith_dst = NULL;
8038 if (g_stack_fsz && !g_stack_frame_used)
8039 fprintf(fout, " (void)sf;\n");
8041 fprintf(fout, "}\n\n");
8043 gen_x_cleanup(opcnt);
8046 static void gen_x_cleanup(int opcnt)
8050 for (i = 0; i < opcnt; i++) {
8051 struct label_ref *lr, *lr_del;
8053 lr = g_label_refs[i].next;
8054 while (lr != NULL) {
8059 g_label_refs[i].i = -1;
8060 g_label_refs[i].next = NULL;
8062 if (ops[i].op == OP_CALL) {
8064 proto_release(ops[i].pp);
8070 struct func_proto_dep;
8072 struct func_prototype {
8077 int has_ret:3; // -1, 0, 1: unresolved, no, yes
8078 unsigned int dep_resolved:1;
8079 unsigned int is_stdcall:1;
8080 struct func_proto_dep *dep_func;
8082 const struct parsed_proto *pp; // seed pp, if any
8085 struct func_proto_dep {
8087 struct func_prototype *proto;
8088 int regmask_live; // .. at the time of call
8089 unsigned int ret_dep:1; // return from this is caller's return
8092 static struct func_prototype *hg_fp;
8093 static int hg_fp_cnt;
8095 static struct scanned_var {
8097 enum opr_lenmod lmod;
8098 unsigned int is_seeded:1;
8099 unsigned int is_c_str:1;
8100 const struct parsed_proto *pp; // seed pp, if any
8102 static int hg_var_cnt;
8104 static char **hg_refs;
8105 static int hg_ref_cnt;
8107 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8110 static struct func_prototype *hg_fp_add(const char *funcn)
8112 struct func_prototype *fp;
8114 if ((hg_fp_cnt & 0xff) == 0) {
8115 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
8116 my_assert_not(hg_fp, NULL);
8117 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
8120 fp = &hg_fp[hg_fp_cnt];
8121 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
8123 fp->argc_stack = -1;
8129 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
8134 for (i = 0; i < fp->dep_func_cnt; i++)
8135 if (IS(fp->dep_func[i].name, name))
8136 return &fp->dep_func[i];
8141 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
8144 if (hg_fp_find_dep(fp, name))
8147 if ((fp->dep_func_cnt & 0xff) == 0) {
8148 fp->dep_func = realloc(fp->dep_func,
8149 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
8150 my_assert_not(fp->dep_func, NULL);
8151 memset(&fp->dep_func[fp->dep_func_cnt], 0,
8152 sizeof(fp->dep_func[0]) * 0x100);
8154 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
8158 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
8160 const struct func_prototype *p1 = p1_, *p2 = p2_;
8161 return strcmp(p1->name, p2->name);
8165 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
8167 const struct func_prototype *p1 = p1_, *p2 = p2_;
8168 return p1->id - p2->id;
8172 static void hg_ref_add(const char *name)
8174 if ((hg_ref_cnt & 0xff) == 0) {
8175 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
8176 my_assert_not(hg_refs, NULL);
8177 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
8180 hg_refs[hg_ref_cnt] = strdup(name);
8181 my_assert_not(hg_refs[hg_ref_cnt], NULL);
8185 // recursive register dep pass
8186 // - track saved regs (part 2)
8187 // - try to figure out arg-regs
8188 // - calculate reg deps
8189 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
8190 struct func_prototype *fp, int regmask_save, int regmask_dst,
8191 int *regmask_dep, int *has_ret)
8193 struct func_proto_dep *dep;
8194 struct parsed_op *po;
8195 int from_caller = 0;
8200 for (; i < opcnt; i++)
8202 if (cbits[i >> 3] & (1 << (i & 7)))
8204 cbits[i >> 3] |= (1 << (i & 7));
8208 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
8209 if (po->flags & OPF_RMD)
8212 if (po->btj != NULL) {
8214 for (j = 0; j < po->btj->count; j++) {
8215 check_i(po, po->btj->d[j].bt_i);
8216 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
8217 regmask_save, regmask_dst, regmask_dep, has_ret);
8222 check_i(po, po->bt_i);
8223 if (po->flags & OPF_CJMP) {
8224 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
8225 regmask_save, regmask_dst, regmask_dep, has_ret);
8233 if (po->flags & OPF_FARG)
8234 /* (just calculate register deps) */;
8235 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
8237 reg = po->operand[0].reg;
8238 ferr_assert(po, reg >= 0);
8240 if (po->flags & OPF_RSAVE) {
8241 regmask_save |= 1 << reg;
8244 if (po->flags & OPF_DONE)
8247 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0, 0);
8249 regmask_save |= 1 << reg;
8250 po->flags |= OPF_RMD;
8251 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, OPF_RMD);
8255 else if (po->flags & OPF_RMD)
8257 else if (po->op == OP_CALL) {
8258 po->regmask_dst |= 1 << xAX;
8260 dep = hg_fp_find_dep(fp, po->operand[0].name);
8262 dep->regmask_live = regmask_save | regmask_dst;
8263 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8264 dep->regmask_live |= 1 << xBP;
8267 else if (po->op == OP_RET) {
8268 if (po->operand_cnt > 0) {
8270 if (fp->argc_stack >= 0
8271 && fp->argc_stack != po->operand[0].val / 4)
8272 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
8273 fp->argc_stack = po->operand[0].val / 4;
8277 // if has_ret is 0, there is uninitialized eax path,
8278 // which means it's most likely void func
8279 if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
8280 if (po->op == OP_CALL) {
8285 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
8288 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
8291 if (ret != 1 && from_caller) {
8292 // unresolved eax - probably void func
8296 if (j >= 0 && ops[j].op == OP_CALL) {
8297 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
8308 l = regmask_save | regmask_dst;
8309 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8312 l = po->regmask_src & ~l;
8315 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
8316 l, regmask_dst, regmask_save, po->flags);
8319 regmask_dst |= po->regmask_dst;
8321 if (po->flags & OPF_TAIL)
8326 static void gen_hdr(const char *funcn, int opcnt)
8328 unsigned char cbits[MAX_OPS / 8];
8329 const struct parsed_proto *pp_c;
8330 struct parsed_proto *pp;
8331 struct func_prototype *fp;
8332 struct parsed_op *po;
8333 int regmask_dummy = 0;
8335 int max_bp_offset = 0;
8340 pp_c = proto_parse(g_fhdr, funcn, 1);
8342 // already in seed, will add to hg_fp later
8345 fp = hg_fp_add(funcn);
8347 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
8348 g_stack_frame_used = 0;
8352 // - resolve all branches
8353 // - parse calls with labels
8354 resolve_branches_parse_calls(opcnt);
8357 // - handle ebp/esp frame, remove ops related to it
8358 scan_prologue_epilogue(opcnt, NULL);
8361 // - remove dead labels
8363 for (i = 0; i < opcnt; i++)
8365 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8371 if (po->flags & (OPF_RMD|OPF_DONE))
8374 if (po->op == OP_CALL) {
8375 if (po->operand[0].type == OPT_LABEL)
8376 hg_fp_add_dep(fp, opr_name(po, 0));
8377 else if (po->pp != NULL)
8378 hg_fp_add_dep(fp, po->pp->name);
8383 // - remove dead labels
8384 // - handle push <const>/pop pairs
8385 for (i = 0; i < opcnt; i++)
8387 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8393 if (po->flags & (OPF_RMD|OPF_DONE))
8396 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
8397 scan_for_pop_const(i, opcnt, i + opcnt * 13);
8401 // - process trivial calls
8402 for (i = 0; i < opcnt; i++)
8405 if (po->flags & (OPF_RMD|OPF_DONE))
8408 if (po->op == OP_CALL)
8410 pp = process_call_early(i, opcnt, &j);
8412 if (!(po->flags & OPF_ATAIL))
8413 // since we know the args, try to collect them
8414 if (collect_call_args_early(i, pp, NULL, NULL) != 0)
8420 // commit esp adjust
8421 if (ops[j].op != OP_POP)
8422 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
8424 for (l = 0; l < pp->argc_stack; l++)
8425 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
8429 po->flags |= OPF_DONE;
8435 // - track saved regs (simple)
8437 for (i = 0; i < opcnt; i++)
8440 if (po->flags & (OPF_RMD|OPF_DONE))
8443 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
8444 && po->operand[0].reg != xCX)
8446 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
8448 // regmask_save |= 1 << po->operand[0].reg; // do it later
8449 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
8450 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
8453 else if (po->op == OP_CALL)
8455 pp = process_call(i, opcnt);
8457 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
8458 // since we know the args, collect them
8459 ret = collect_call_args(po, i, pp, ®mask_dummy,
8466 memset(cbits, 0, sizeof(cbits));
8470 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, ®mask_dep, &has_ret);
8472 // find unreachable code - must be fixed in IDA
8473 for (i = 0; i < opcnt; i++)
8475 if (cbits[i >> 3] & (1 << (i & 7)))
8478 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
8479 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
8481 // the compiler sometimes still generates code after
8482 // noreturn OS functions
8485 if (!(ops[i].flags & OPF_RMD)
8486 && ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
8488 ferr(&ops[i], "unreachable code\n");
8492 for (i = 0; i < g_eqcnt; i++) {
8493 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
8494 max_bp_offset = g_eqs[i].offset;
8497 if (fp->argc_stack < 0) {
8498 max_bp_offset = (max_bp_offset + 3) & ~3;
8499 fp->argc_stack = max_bp_offset / 4;
8500 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
8504 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
8505 fp->has_ret = has_ret;
8507 printf("// has_ret %d, regmask_dep %x\n",
8508 fp->has_ret, fp->regmask_dep);
8509 output_hdr_fp(stdout, fp, 1);
8510 if (IS(funcn, "sub_10007F72")) exit(1);
8513 gen_x_cleanup(opcnt);
8516 static void hg_fp_resolve_deps(struct func_prototype *fp)
8518 struct func_prototype fp_s;
8522 // this thing is recursive, so mark first..
8523 fp->dep_resolved = 1;
8525 for (i = 0; i < fp->dep_func_cnt; i++) {
8526 strcpy(fp_s.name, fp->dep_func[i].name);
8527 fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8528 sizeof(hg_fp[0]), hg_fp_cmp_name);
8529 if (fp->dep_func[i].proto != NULL) {
8530 if (!fp->dep_func[i].proto->dep_resolved)
8531 hg_fp_resolve_deps(fp->dep_func[i].proto);
8533 dep = ~fp->dep_func[i].regmask_live
8534 & fp->dep_func[i].proto->regmask_dep;
8535 fp->regmask_dep |= dep;
8536 // printf("dep %s %s |= %x\n", fp->name,
8537 // fp->dep_func[i].name, dep);
8539 if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
8540 fp->has_ret = fp->dep_func[i].proto->has_ret;
8545 // make all thiscall/edx arg functions referenced from .data fastcall
8546 static void do_func_refs_from_data(void)
8548 struct func_prototype *fp, fp_s;
8551 for (i = 0; i < hg_ref_cnt; i++) {
8552 strcpy(fp_s.name, hg_refs[i]);
8553 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8554 sizeof(hg_fp[0]), hg_fp_cmp_name);
8558 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
8559 fp->regmask_dep |= mxCX | mxDX;
8563 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8566 const struct parsed_proto *pp;
8567 char *p, namebuf[NAMELEN];
8573 for (; count > 0; count--, fp++) {
8574 if (fp->has_ret == -1)
8575 fprintf(fout, "// ret unresolved\n");
8577 fprintf(fout, "// dep:");
8578 for (j = 0; j < fp->dep_func_cnt; j++) {
8579 fprintf(fout, " %s/", fp->dep_func[j].name);
8580 if (fp->dep_func[j].proto != NULL)
8581 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8582 fp->dep_func[j].proto->has_ret);
8584 fprintf(fout, "\n");
8587 p = strchr(fp->name, '@');
8589 memcpy(namebuf, fp->name, p - fp->name);
8590 namebuf[p - fp->name] = 0;
8598 pp = proto_parse(g_fhdr, name, 1);
8599 if (pp != NULL && pp->is_include)
8602 if (fp->pp != NULL) {
8603 // part of seed, output later
8607 regmask_dep = fp->regmask_dep;
8608 argc_normal = fp->argc_stack;
8610 fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
8611 (fp->has_ret ? "int" : "void"));
8612 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
8613 && (regmask_dep & ~mxCX) == 0)
8615 fprintf(fout, "/*__thiscall*/ ");
8619 else if (regmask_dep && (fp->is_stdcall || fp->argc_stack == 0)
8620 && (regmask_dep & ~(mxCX | mxDX)) == 0)
8622 fprintf(fout, " __fastcall ");
8623 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8629 else if (regmask_dep && !fp->is_stdcall) {
8630 fprintf(fout, "/*__usercall*/ ");
8632 else if (regmask_dep) {
8633 fprintf(fout, "/*__userpurge*/ ");
8635 else if (fp->is_stdcall)
8636 fprintf(fout, " __stdcall ");
8638 fprintf(fout, " __cdecl ");
8640 fprintf(fout, "%s(", name);
8643 for (j = 0; j < xSP; j++) {
8644 if (regmask_dep & (1 << j)) {
8647 fprintf(fout, ", ");
8649 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8651 fprintf(fout, "int");
8652 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
8656 for (j = 0; j < argc_normal; j++) {
8659 fprintf(fout, ", ");
8660 if (fp->pp != NULL) {
8661 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8662 if (!fp->pp->arg[arg - 1].type.is_ptr)
8666 fprintf(fout, "int ");
8667 fprintf(fout, "a%d", arg);
8670 fprintf(fout, ");\n");
8674 static void output_hdr(FILE *fout)
8676 static const char *lmod_c_names[] = {
8677 [OPLM_UNSPEC] = "???",
8678 [OPLM_BYTE] = "uint8_t",
8679 [OPLM_WORD] = "uint16_t",
8680 [OPLM_DWORD] = "uint32_t",
8681 [OPLM_QWORD] = "uint64_t",
8683 const struct scanned_var *var;
8684 struct func_prototype *fp;
8685 char line[256] = { 0, };
8689 // add stuff from headers
8690 for (i = 0; i < pp_cache_size; i++) {
8691 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
8692 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
8694 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
8695 fp = hg_fp_add(name);
8696 fp->pp = &pp_cache[i];
8697 fp->argc_stack = fp->pp->argc_stack;
8698 fp->is_stdcall = fp->pp->is_stdcall;
8699 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
8700 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
8704 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
8705 for (i = 0; i < hg_fp_cnt; i++)
8706 hg_fp_resolve_deps(&hg_fp[i]);
8708 // adjust functions referenced from data segment
8709 do_func_refs_from_data();
8711 // note: messes up .proto ptr, don't use
8712 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
8715 for (i = 0; i < hg_var_cnt; i++) {
8718 if (var->pp != NULL)
8721 else if (var->is_c_str)
8722 fprintf(fout, "extern %-8s %s[];", "char", var->name);
8724 fprintf(fout, "extern %-8s %s;",
8725 lmod_c_names[var->lmod], var->name);
8728 fprintf(fout, " // seeded");
8729 fprintf(fout, "\n");
8732 fprintf(fout, "\n");
8734 // output function prototypes
8735 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
8738 fprintf(fout, "\n// - seed -\n");
8741 while (fgets(line, sizeof(line), g_fhdr))
8742 fwrite(line, 1, strlen(line), fout);
8745 // '=' needs special treatment
8747 static char *next_word_s(char *w, size_t wsize, char *s)
8754 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
8756 for (i = 1; i < wsize - 1; i++) {
8758 printf("warning: missing closing quote: \"%s\"\n", s);
8767 for (; i < wsize - 1; i++) {
8768 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
8774 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
8775 printf("warning: '%s' truncated\n", w);
8780 static int cmpstringp(const void *p1, const void *p2)
8782 return strcmp(*(char * const *)p1, *(char * const *)p2);
8785 static int is_xref_needed(char *p, char **rlist, int rlist_len)
8790 if (strstr(p, "..."))
8791 // unable to determine, assume needed
8794 if (*p == '.') // .text, .data, ...
8795 // ref from other data or non-function -> no
8798 p2 = strpbrk(p, "+:\r\n\x18");
8801 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8802 // referenced from removed code
8808 static int ida_xrefs_show_need(FILE *fasm, char *p,
8809 char **rlist, int rlist_len)
8815 p = strrchr(p, ';');
8816 if (p != NULL && *p == ';') {
8817 if (IS_START(p + 2, "sctref"))
8819 if (IS_START(p + 2, "DATA XREF: ")) {
8821 if (is_xref_needed(p, rlist, rlist_len))
8829 if (!my_fgets(line, sizeof(line), fasm))
8831 // non-first line is always indented
8832 if (!my_isblank(line[0]))
8835 // should be no content, just comment
8840 p = strrchr(p, ';');
8843 if (IS_START(p, "sctref")) {
8848 // it's printed once, but no harm to check again
8849 if (IS_START(p, "DATA XREF: "))
8852 if (is_xref_needed(p, rlist, rlist_len)) {
8857 fseek(fasm, pos, SEEK_SET);
8861 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
8863 struct scanned_var *var;
8864 char line[256] = { 0, };
8873 // skip to next data section
8874 while (my_fgets(line, sizeof(line), fasm))
8879 if (*p == 0 || *p == ';')
8882 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
8883 if (*p == 0 || *p == ';')
8886 if (*p != 's' || !IS_START(p, "segment para public"))
8892 if (p == NULL || !IS_START(p, "segment para public"))
8896 if (!IS_START(p, "'DATA'"))
8900 while (my_fgets(line, sizeof(line), fasm))
8905 no_identifier = my_isblank(*p);
8908 if (*p == 0 || *p == ';')
8911 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8912 words[wordc][0] = 0;
8913 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8914 if (*p == 0 || *p == ';') {
8920 if (wordc == 2 && IS(words[1], "ends"))
8925 if (no_identifier) {
8926 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
8927 hg_ref_add(words[2]);
8931 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
8932 // when this starts, we don't need anything from this section
8936 // check refs comment(s)
8937 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
8940 if ((hg_var_cnt & 0xff) == 0) {
8941 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
8942 * (hg_var_cnt + 0x100));
8943 my_assert_not(hg_vars, NULL);
8944 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
8947 var = &hg_vars[hg_var_cnt++];
8948 snprintf(var->name, sizeof(var->name), "%s", words[0]);
8950 // maybe already in seed header?
8951 var->pp = proto_parse(g_fhdr, var->name, 1);
8952 if (var->pp != NULL) {
8953 if (var->pp->is_fptr) {
8954 var->lmod = OPLM_DWORD;
8957 else if (var->pp->is_func)
8959 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
8960 aerr("unhandled C type '%s' for '%s'\n",
8961 var->pp->type.name, var->name);
8967 if (IS(words[1], "dd")) {
8968 var->lmod = OPLM_DWORD;
8969 if (wordc >= 4 && IS(words[2], "offset"))
8970 hg_ref_add(words[3]);
8972 else if (IS(words[1], "dw"))
8973 var->lmod = OPLM_WORD;
8974 else if (IS(words[1], "db")) {
8975 var->lmod = OPLM_BYTE;
8976 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
8977 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
8981 else if (IS(words[1], "dq"))
8982 var->lmod = OPLM_QWORD;
8983 //else if (IS(words[1], "dt"))
8985 aerr("type '%s' not known\n", words[1]);
8993 static void set_label(int i, const char *name)
8999 p = strchr(name, ':');
9003 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
9004 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
9005 g_labels[i] = realloc(g_labels[i], len + 1);
9006 my_assert_not(g_labels[i], NULL);
9007 memcpy(g_labels[i], name, len);
9008 g_labels[i][len] = 0;
9017 static struct chunk_item *func_chunks;
9018 static int func_chunk_cnt;
9019 static int func_chunk_alloc;
9021 static void add_func_chunk(FILE *fasm, const char *name, int line)
9023 if (func_chunk_cnt >= func_chunk_alloc) {
9024 func_chunk_alloc *= 2;
9025 func_chunks = realloc(func_chunks,
9026 func_chunk_alloc * sizeof(func_chunks[0]));
9027 my_assert_not(func_chunks, NULL);
9029 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
9030 func_chunks[func_chunk_cnt].name = strdup(name);
9031 func_chunks[func_chunk_cnt].asmln = line;
9035 static int cmp_chunks(const void *p1, const void *p2)
9037 const struct chunk_item *c1 = p1, *c2 = p2;
9038 return strcmp(c1->name, c2->name);
9041 static void scan_ahead_for_chunks(FILE *fasm)
9051 oldpos = ftell(fasm);
9054 while (my_fgets(line, sizeof(line), fasm))
9065 // get rid of random tabs
9066 for (i = 0; line[i] != 0; i++)
9067 if (line[i] == '\t')
9070 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9073 next_word(words[0], sizeof(words[0]), p);
9074 if (words[0][0] == 0)
9075 aerr("missing name for func chunk?\n");
9077 add_func_chunk(fasm, words[0], asmln);
9079 else if (IS_START(p, "; sctend"))
9085 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9086 words[wordc][0] = 0;
9087 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9088 if (*p == 0 || *p == ';') {
9094 if (wordc == 2 && IS(words[1], "ends"))
9098 fseek(fasm, oldpos, SEEK_SET);
9102 int main(int argc, char *argv[])
9104 FILE *fout, *fasm, *frlist;
9105 struct parsed_data *pd = NULL;
9107 char **rlist = NULL;
9109 int rlist_alloc = 0;
9110 int func_chunks_used = 0;
9111 int func_chunks_sorted = 0;
9112 int func_chunk_i = -1;
9113 long func_chunk_ret = 0;
9114 int func_chunk_ret_ln = 0;
9115 int scanned_ahead = 0;
9117 char words[20][256];
9118 enum opr_lenmod lmod;
9119 char *sctproto = NULL;
9121 int pending_endp = 0;
9123 int skip_code_end = 0;
9124 int skip_warned = 0;
9137 for (arg = 1; arg < argc; arg++) {
9138 if (IS(argv[arg], "-v"))
9140 else if (IS(argv[arg], "-rf"))
9141 g_allow_regfunc = 1;
9142 else if (IS(argv[arg], "-uc"))
9143 g_allow_user_icall = 1;
9144 else if (IS(argv[arg], "-m"))
9146 else if (IS(argv[arg], "-hdr"))
9147 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
9152 if (argc < arg + 3) {
9153 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
9154 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
9156 " -hdr - header generation mode\n"
9157 " -rf - allow unannotated indirect calls\n"
9158 " -uc - allow ind. calls/refs to __usercall\n"
9159 " -m - allow multiple .text sections\n"
9160 "[rlist] is a file with function names to skip,"
9168 asmfn = argv[arg++];
9169 fasm = fopen(asmfn, "r");
9170 my_assert_not(fasm, NULL);
9172 hdrfn = argv[arg++];
9173 g_fhdr = fopen(hdrfn, "r");
9174 my_assert_not(g_fhdr, NULL);
9177 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
9178 my_assert_not(rlist, NULL);
9179 // needs special handling..
9180 rlist[rlist_len++] = "__alloca_probe";
9182 func_chunk_alloc = 32;
9183 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
9184 my_assert_not(func_chunks, NULL);
9186 memset(words, 0, sizeof(words));
9188 for (; arg < argc; arg++) {
9191 frlist = fopen(argv[arg], "r");
9192 my_assert_not(frlist, NULL);
9194 while (my_fgets(line, sizeof(line), frlist)) {
9196 if (*p == 0 || *p == ';')
9199 if (IS_START(p, "#if 0")
9200 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
9204 else if (IS_START(p, "#endif"))
9211 p = next_word(words[0], sizeof(words[0]), p);
9212 if (words[0][0] == 0)
9215 if (rlist_len >= rlist_alloc) {
9216 rlist_alloc = rlist_alloc * 2 + 64;
9217 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
9218 my_assert_not(rlist, NULL);
9220 rlist[rlist_len++] = strdup(words[0]);
9228 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
9230 fout = fopen(argv[arg_out], "w");
9231 my_assert_not(fout, NULL);
9234 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
9235 my_assert_not(g_eqs, NULL);
9237 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
9238 g_label_refs[i].i = -1;
9239 g_label_refs[i].next = NULL;
9243 scan_variables(fasm, rlist, rlist_len);
9245 while (my_fgets(line, sizeof(line), fasm))
9254 // get rid of random tabs
9255 for (i = 0; line[i] != 0; i++)
9256 if (line[i] == '\t')
9261 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
9262 goto do_pending_endp; // eww..
9264 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
9266 static const char *attrs[] = {
9275 // parse IDA's attribute-list comment
9276 g_ida_func_attr = 0;
9279 for (; *p != 0; p = sskip(p)) {
9280 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9281 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9282 g_ida_func_attr |= 1 << i;
9283 p += strlen(attrs[i]);
9287 if (i == ARRAY_SIZE(attrs)) {
9288 anote("unparsed IDA attr: %s\n", p);
9291 if (IS(attrs[i], "fpd=")) {
9292 p = next_word(words[0], sizeof(words[0]), p);
9297 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
9299 static const char *attrs[] = {
9304 // parse manual attribute-list comment
9305 g_sct_func_attr = 0;
9308 for (; *p != 0; p = sskip(p)) {
9309 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9310 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9311 g_sct_func_attr |= 1 << i;
9312 p += strlen(attrs[i]);
9319 // clear_sf=start,len (in dwords)
9320 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
9321 &g_stack_clear_len, &j);
9323 // clear_regmask=<mask>
9324 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
9326 anote("unparsed attr value: %s\n", p);
9331 else if (i == ARRAY_SIZE(attrs)) {
9332 anote("unparsed sct attr: %s\n", p);
9337 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9340 next_word(words[0], sizeof(words[0]), p);
9341 if (words[0][0] == 0)
9342 aerr("missing name for func chunk?\n");
9344 if (!scanned_ahead) {
9345 add_func_chunk(fasm, words[0], asmln);
9346 func_chunks_sorted = 0;
9349 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
9351 if (func_chunk_i >= 0) {
9352 if (func_chunk_i < func_chunk_cnt
9353 && IS(func_chunks[func_chunk_i].name, g_func))
9355 // move on to next chunk
9356 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9358 aerr("seek failed for '%s' chunk #%d\n",
9359 g_func, func_chunk_i);
9360 asmln = func_chunks[func_chunk_i].asmln;
9364 if (func_chunk_ret == 0)
9365 aerr("no return from chunk?\n");
9366 fseek(fasm, func_chunk_ret, SEEK_SET);
9367 asmln = func_chunk_ret_ln;
9373 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
9374 func_chunks_used = 1;
9376 if (IS_START(g_func, "sub_")) {
9377 unsigned long addr = strtoul(p, NULL, 16);
9378 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
9379 if (addr > f_addr && !scanned_ahead) {
9380 //anote("scan_ahead caused by '%s', addr %lx\n",
9382 scan_ahead_for_chunks(fasm);
9384 func_chunks_sorted = 0;
9392 for (i = wordc; i < ARRAY_SIZE(words); i++)
9394 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9395 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9396 if (*p == 0 || *p == ';') {
9401 if (*p != 0 && *p != ';')
9402 aerr("too many words\n");
9404 if (skip_code_end) {
9409 // allow asm patches in comments
9411 if (IS_START(p, "; sctpatch:")) {
9413 if (*p == 0 || *p == ';')
9415 goto parse_words; // lame
9417 if (IS_START(p, "; sctproto:")) {
9418 sctproto = strdup(p + 11);
9420 else if (IS_START(p, "; sctend")) {
9425 else if (IS_START(p, "; sctskip_start")) {
9426 if (in_func && !g_skip_func) {
9428 ops[pi].op = OPP_ABORT;
9429 ops[pi].asmln = asmln;
9435 else if (IS_START(p, "; sctskip_end")) {
9443 awarn("wordc == 0?\n");
9447 // don't care about this:
9448 if (words[0][0] == '.'
9449 || IS(words[0], "include")
9450 || IS(words[0], "assume") || IS(words[1], "segment")
9451 || IS(words[0], "align"))
9457 // do delayed endp processing to collect switch jumptables
9459 if (in_func && !g_skip_func && !end && wordc >= 2
9460 && ((words[0][0] == 'd' && words[0][2] == 0)
9461 || (words[1][0] == 'd' && words[1][2] == 0)))
9464 if (words[1][0] == 'd' && words[1][2] == 0) {
9466 if (g_func_pd_cnt >= pd_alloc) {
9467 pd_alloc = pd_alloc * 2 + 16;
9468 g_func_pd = realloc(g_func_pd,
9469 sizeof(g_func_pd[0]) * pd_alloc);
9470 my_assert_not(g_func_pd, NULL);
9472 pd = &g_func_pd[g_func_pd_cnt];
9474 memset(pd, 0, sizeof(*pd));
9475 strcpy(pd->label, words[0]);
9476 pd->type = OPT_CONST;
9477 pd->lmod = lmod_from_directive(words[1]);
9483 anote("skipping alignment byte?\n");
9486 lmod = lmod_from_directive(words[0]);
9487 if (lmod != pd->lmod)
9488 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
9491 if (pd->count_alloc < pd->count + wordc) {
9492 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
9493 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
9494 my_assert_not(pd->d, NULL);
9496 for (; i < wordc; i++) {
9497 if (IS(words[i], "offset")) {
9498 pd->type = OPT_OFFSET;
9501 p = strchr(words[i], ',');
9504 if (pd->type == OPT_OFFSET)
9505 pd->d[pd->count].u.label = strdup(words[i]);
9507 pd->d[pd->count].u.val = parse_number(words[i], 0);
9508 pd->d[pd->count].bt_i = -1;
9514 if (in_func && !g_skip_func) {
9516 gen_hdr(g_func, pi);
9518 gen_func(fout, g_fhdr, g_func, pi);
9523 g_ida_func_attr = 0;
9524 g_sct_func_attr = 0;
9525 g_stack_clear_start = 0;
9526 g_stack_clear_len = 0;
9532 func_chunks_used = 0;
9535 memset(&ops, 0, pi * sizeof(ops[0]));
9540 for (i = 0; i < g_func_pd_cnt; i++) {
9542 if (pd->type == OPT_OFFSET) {
9543 for (j = 0; j < pd->count; j++)
9544 free(pd->d[j].u.label);
9559 if (IS(words[1], "proc")) {
9561 aerr("proc '%s' while in_func '%s'?\n",
9564 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9566 strcpy(g_func, words[0]);
9567 set_label(0, words[0]);
9572 if (IS(words[1], "endp"))
9575 aerr("endp '%s' while not in_func?\n", words[0]);
9576 if (!IS(g_func, words[0]))
9577 aerr("endp '%s' while in_func '%s'?\n",
9580 aerr("endp '%s' while skipping code\n", words[0]);
9582 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
9583 && ops[0].op == OP_JMP && ops[0].operand[0].segment)
9589 if (!g_skip_func && func_chunks_used) {
9590 // start processing chunks
9591 struct chunk_item *ci, key = { g_func, 0 };
9593 func_chunk_ret = ftell(fasm);
9594 func_chunk_ret_ln = asmln;
9595 if (!func_chunks_sorted) {
9596 qsort(func_chunks, func_chunk_cnt,
9597 sizeof(func_chunks[0]), cmp_chunks);
9598 func_chunks_sorted = 1;
9600 ci = bsearch(&key, func_chunks, func_chunk_cnt,
9601 sizeof(func_chunks[0]), cmp_chunks);
9603 aerr("'%s' needs chunks, but none found\n", g_func);
9604 func_chunk_i = ci - func_chunks;
9605 for (; func_chunk_i > 0; func_chunk_i--)
9606 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
9609 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9611 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
9612 asmln = func_chunks[func_chunk_i].asmln;
9620 if (wordc == 2 && IS(words[1], "ends")) {
9624 goto do_pending_endp;
9628 // scan for next text segment
9629 while (my_fgets(line, sizeof(line), fasm)) {
9632 if (*p == 0 || *p == ';')
9635 if (strstr(p, "segment para public 'CODE' use32"))
9642 p = strchr(words[0], ':');
9644 set_label(pi, words[0]);
9648 if (!in_func || g_skip_func || skip_code) {
9649 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
9651 anote("skipping from '%s'\n", g_labels[pi]);
9655 g_labels[pi] = NULL;
9659 if (wordc > 1 && IS(words[1], "="))
9662 aerr("unhandled equ, wc=%d\n", wordc);
9663 if (g_eqcnt >= eq_alloc) {
9665 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
9666 my_assert_not(g_eqs, NULL);
9669 len = strlen(words[0]);
9670 if (len > sizeof(g_eqs[0].name) - 1)
9671 aerr("equ name too long: %d\n", len);
9672 strcpy(g_eqs[g_eqcnt].name, words[0]);
9674 if (!IS(words[3], "ptr"))
9675 aerr("unhandled equ\n");
9676 if (IS(words[2], "dword"))
9677 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
9678 else if (IS(words[2], "word"))
9679 g_eqs[g_eqcnt].lmod = OPLM_WORD;
9680 else if (IS(words[2], "byte"))
9681 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
9682 else if (IS(words[2], "qword"))
9683 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
9685 aerr("bad lmod: '%s'\n", words[2]);
9687 g_eqs[g_eqcnt].offset = parse_number(words[4], 0);
9692 if (pi >= ARRAY_SIZE(ops))
9693 aerr("too many ops\n");
9695 parse_op(&ops[pi], words, wordc);
9697 ops[pi].datap = sctproto;
9712 // vim:ts=2:shiftwidth=2:expandtab