5 * This work is licensed under the terms of 3-clause BSD license.
6 * See COPYING file in the top-level directory.
14 #include "my_assert.h"
18 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
19 #define IS(w, y) !strcmp(w, y)
20 #define IS_START(w, y) !strncmp(w, y, strlen(y))
22 #include "protoparse.h"
24 static const char *asmfn;
28 #define anote(fmt, ...) \
29 printf("%s:%d: note: " fmt, asmfn, asmln, ##__VA_ARGS__)
30 #define awarn(fmt, ...) \
31 printf("%s:%d: warning: " fmt, asmfn, asmln, ##__VA_ARGS__)
32 #define aerr(fmt, ...) do { \
33 printf("%s:%d: error: " fmt, asmfn, asmln, ##__VA_ARGS__); \
38 #include "masm_tools.h"
41 OPF_RMD = (1 << 0), /* removed from code generation */
42 OPF_DATA = (1 << 1), /* data processing - writes to dst opr */
43 OPF_FLAGS = (1 << 2), /* sets flags */
44 OPF_JMP = (1 << 3), /* branch, call */
45 OPF_CJMP = (1 << 4), /* cond. branch (cc or jecxz/loop) */
46 OPF_CC = (1 << 5), /* uses flags */
47 OPF_TAIL = (1 << 6), /* ret or tail call */
48 OPF_RSAVE = (1 << 7), /* push/pop is local reg save/load */
49 OPF_REP = (1 << 8), /* prefixed by rep */
50 OPF_REPZ = (1 << 9), /* rep is repe/repz */
51 OPF_REPNZ = (1 << 10), /* rep is repne/repnz */
52 OPF_FARG = (1 << 11), /* push collected as func arg */
53 OPF_FARGNR = (1 << 12), /* push collected as func arg (no reuse) */
54 OPF_EBP_S = (1 << 13), /* ebp used as scratch here, not BP */
55 OPF_DF = (1 << 14), /* DF flag set */
56 OPF_ATAIL = (1 << 15), /* tail call with reused arg frame */
57 OPF_32BIT = (1 << 16), /* 32bit division */
58 OPF_LOCK = (1 << 17), /* op has lock prefix */
59 OPF_VAPUSH = (1 << 18), /* vararg ptr push (as call arg) */
60 OPF_DONE = (1 << 19), /* already fully handled by analysis */
61 OPF_PPUSH = (1 << 20), /* part of complex push-pop graph */
62 OPF_NOREGS = (1 << 21), /* don't track regs of this op */
63 OPF_FPUSH = (1 << 22), /* pushes x87 stack */
64 OPF_FPOP = (1 << 23), /* pops x87 stack */
65 OPF_FSHIFT = (1 << 24), /* x87 stack shift is actually needed */
146 // pseudo-ops for lib calls
161 // must be sorted (larger len must be further in enum)
170 #define MAX_EXITS 128
172 #define MAX_OPERANDS 3
175 #define OPR_INIT(type_, lmod_, reg_) \
176 { type_, lmod_, reg_, }
180 enum opr_lenmod lmod;
182 unsigned int is_ptr:1; // pointer in C
183 unsigned int is_array:1; // array in C
184 unsigned int type_from_var:1; // .. in header, sometimes wrong
185 unsigned int size_mismatch:1; // type override differs from C
186 unsigned int size_lt:1; // type override is larger than C
187 unsigned int had_ds:1; // had ds: prefix
188 const struct parsed_proto *pp; // for OPT_LABEL
195 struct parsed_opr operand[MAX_OPERANDS];
198 unsigned char pfo_inv;
199 unsigned char operand_cnt;
200 unsigned char p_argnum; // arg push: altered before call arg #
201 unsigned char p_arggrp; // arg push: arg group # for above
202 unsigned char p_argpass;// arg push: arg of host func
203 short p_argnext;// arg push: same arg pushed elsewhere or -1
204 int regmask_src; // all referensed regs
206 int pfomask; // flagop: parsed_flag_op that can't be delayed
207 int cc_scratch; // scratch storage during analysis
208 int bt_i; // branch target for branches
209 struct parsed_data *btj;// branch targets for jumptables
210 struct parsed_proto *pp;// parsed_proto for OP_CALL
216 // on start: function/data type hint (sctproto)
218 // (OPF_CC) - points to one of (OPF_FLAGS) that affects cc op
219 // OP_PUSH - points to OP_POP in complex push/pop graph
220 // OP_POP - points to OP_PUSH in simple push/pop pair
224 enum opr_lenmod lmod;
231 enum opr_lenmod lmod;
245 struct label_ref *next;
249 IDAFA_BP_FRAME = (1 << 0),
250 IDAFA_LIB_FUNC = (1 << 1),
251 IDAFA_STATIC = (1 << 2),
252 IDAFA_NORETURN = (1 << 3),
253 IDAFA_THUNK = (1 << 4),
254 IDAFA_FPD = (1 << 5),
258 SCTFA_CLEAR_SF = (1 << 0), // clear stack frame
259 SCTFA_CLEAR_REGS = (1 << 1), // clear registers (mask)
272 // note: limited to 32k due to p_argnext
274 #define MAX_ARG_GRP 2
276 static struct parsed_op ops[MAX_OPS];
277 static struct parsed_equ *g_eqs;
279 static char *g_labels[MAX_OPS];
280 static struct label_ref g_label_refs[MAX_OPS];
281 static const struct parsed_proto *g_func_pp;
282 static struct parsed_data *g_func_pd;
283 static int g_func_pd_cnt;
284 static int g_func_lmods;
285 static char g_func[256];
286 static char g_comment[256];
287 static int g_bp_frame;
288 static int g_sp_frame;
289 static int g_stack_frame_used;
290 static int g_stack_fsz;
291 static int g_ida_func_attr;
292 static int g_sct_func_attr;
293 static int g_stack_clear_start; // in dwords
294 static int g_stack_clear_len;
295 static int g_regmask_init;
296 static int g_skip_func;
297 static int g_allow_regfunc;
298 static int g_quiet_pp;
299 static int g_header_mode;
301 #define ferr(op_, fmt, ...) do { \
302 printf("%s:%d: error %u: [%s] '%s': " fmt, asmfn, (op_)->asmln, \
303 __LINE__, g_func, dump_op(op_), ##__VA_ARGS__); \
307 #define fnote(op_, fmt, ...) \
308 printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
309 dump_op(op_), ##__VA_ARGS__)
311 #define ferr_assert(op_, cond) do { \
312 if (!(cond)) ferr(op_, "assertion '%s' failed\n", #cond); \
315 const char *regs_r32[] = {
316 "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
317 // not r32, but list here for easy parsing and printing
318 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
319 "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"
321 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
322 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
323 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
329 xMM0, xMM1, xMM2, xMM3, // mmx
330 xMM4, xMM5, xMM6, xMM7,
331 xST0, xST1, xST2, xST3, // x87
332 xST4, xST5, xST6, xST7,
335 #define mxAX (1 << xAX)
336 #define mxCX (1 << xCX)
337 #define mxDX (1 << xDX)
338 #define mxST0 (1 << xST0)
339 #define mxST1 (1 << xST1)
341 // possible basic comparison types (without inversion)
342 enum parsed_flag_op {
346 PFO_BE, // 6 CF=1||ZF=1
350 PFO_LE, // e ZF=1||SF!=OF
353 #define PFOB_O (1 << PFO_O)
354 #define PFOB_C (1 << PFO_C)
355 #define PFOB_Z (1 << PFO_Z)
356 #define PFOB_S (1 << PFO_S)
358 static const char *parsed_flag_op_names[] = {
359 "o", "c", "z", "be", "s", "p", "l", "le"
362 static int char_array_i(const char *array[], size_t len, const char *s)
366 for (i = 0; i < len; i++)
373 static void printf_number(char *buf, size_t buf_size,
374 unsigned long number)
376 // output in C-friendly form
377 snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
380 static int check_segment_prefix(const char *s)
382 if (s[0] == 0 || s[1] != 's' || s[2] != ':')
396 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
400 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
402 *reg_lmod = OPLM_QWORD;
406 *reg_lmod = OPLM_DWORD;
409 reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
411 *reg_lmod = OPLM_WORD;
414 reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
416 *reg_lmod = OPLM_BYTE;
419 reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
421 *reg_lmod = OPLM_BYTE;
428 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
430 enum opr_lenmod lmod;
443 while (my_isblank(*s))
445 for (; my_issep(*s); d++, s++)
447 while (my_isblank(*s))
451 // skip '?s:' prefixes
452 if (check_segment_prefix(s))
455 s = next_idt(w, sizeof(w), s);
460 reg = parse_reg(&lmod, w);
462 *regmask |= 1 << reg;
466 if ('0' <= w[0] && w[0] <= '9') {
467 number = parse_number(w);
468 printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
472 // probably some label/identifier - pass
475 snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
479 strcpy(name, cvtbuf);
484 static int is_reg_in_str(const char *s)
488 if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
491 for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
492 if (!strncmp(s, regs_r32[i], 3))
498 static const char *parse_stack_el(const char *name, char *extra_reg,
501 const char *p, *p2, *s;
507 if (g_bp_frame || early_try)
510 if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
512 if (extra_reg != NULL) {
513 strncpy(extra_reg, name, 3);
518 if (IS_START(p, "ebp+")) {
522 if (p2 != NULL && is_reg_in_str(p)) {
523 if (extra_reg != NULL) {
524 strncpy(extra_reg, p, p2 - p);
525 extra_reg[p2 - p] = 0;
530 if (!('0' <= *p && *p <= '9'))
537 if (!IS_START(name, "esp+"))
543 if (is_reg_in_str(s)) {
544 if (extra_reg != NULL) {
545 strncpy(extra_reg, s, p - s);
546 extra_reg[p - s] = 0;
551 aerr("%s IDA stackvar not set?\n", __func__);
553 if (!('0' <= *s && *s <= '9')) {
554 aerr("%s IDA stackvar offset not set?\n", __func__);
557 if (s[0] == '0' && s[1] == 'x')
560 if (len < sizeof(buf) - 1) {
561 strncpy(buf, s, len);
563 val = strtol(buf, &endp, 16);
564 if (val == 0 || *endp != 0) {
565 aerr("%s num parse fail for '%s'\n", __func__, buf);
574 if ('0' <= *p && *p <= '9')
580 static int guess_lmod_from_name(struct parsed_opr *opr)
582 if (IS_START(opr->name, "dword_") || IS_START(opr->name, "off_")) {
583 opr->lmod = OPLM_DWORD;
586 if (IS_START(opr->name, "word_")) {
587 opr->lmod = OPLM_WORD;
590 if (IS_START(opr->name, "byte_")) {
591 opr->lmod = OPLM_BYTE;
594 if (IS_START(opr->name, "qword_")) {
595 opr->lmod = OPLM_QWORD;
601 static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
602 const struct parsed_type *c_type)
604 static const char *dword_types[] = {
605 "uint32_t", "int", "_DWORD", "UINT_PTR", "DWORD",
606 "WPARAM", "LPARAM", "UINT", "__int32",
607 "LONG", "HIMC", "BOOL", "size_t",
610 static const char *word_types[] = {
611 "uint16_t", "int16_t", "_WORD", "WORD",
612 "unsigned __int16", "__int16",
614 static const char *byte_types[] = {
615 "uint8_t", "int8_t", "char",
616 "unsigned __int8", "__int8", "BYTE", "_BYTE",
618 // structures.. deal the same as with _UNKNOWN for now
624 if (c_type->is_ptr) {
629 n = skip_type_mod(c_type->name);
631 for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
632 if (IS(n, dword_types[i])) {
638 for (i = 0; i < ARRAY_SIZE(word_types); i++) {
639 if (IS(n, word_types[i])) {
645 for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
646 if (IS(n, byte_types[i])) {
655 static char *default_cast_to(char *buf, size_t buf_size,
656 struct parsed_opr *opr)
660 if (!opr->is_ptr || strchr(opr->name, '['))
662 if (opr->pp == NULL || opr->pp->type.name == NULL
665 snprintf(buf, buf_size, "%s", "(void *)");
669 snprintf(buf, buf_size, "(%s)", opr->pp->type.name);
673 static enum opr_type lmod_from_directive(const char *d)
677 else if (IS(d, "dw"))
679 else if (IS(d, "db"))
682 aerr("unhandled directive: '%s'\n", d);
686 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
692 *regmask |= 1 << reg;
695 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
698 static int parse_operand(struct parsed_opr *opr,
699 int *regmask, int *regmask_indirect,
700 char words[16][256], int wordc, int w, unsigned int op_flags)
702 const struct parsed_proto *pp = NULL;
703 enum opr_lenmod tmplmod;
704 unsigned long number;
712 aerr("parse_operand w %d, wordc %d\n", w, wordc);
716 for (i = w; i < wordc; i++) {
717 len = strlen(words[i]);
718 if (words[i][len - 1] == ',') {
719 words[i][len - 1] = 0;
725 wordc_in = wordc - w;
727 if ((op_flags & OPF_JMP) && wordc_in > 0
728 && !('0' <= words[w][0] && words[w][0] <= '9'))
730 const char *label = NULL;
732 if (wordc_in == 3 && !strncmp(words[w], "near", 4)
733 && IS(words[w + 1], "ptr"))
734 label = words[w + 2];
735 else if (wordc_in == 2 && IS(words[w], "short"))
736 label = words[w + 1];
737 else if (wordc_in == 1
738 && strchr(words[w], '[') == NULL
739 && parse_reg(&tmplmod, words[w]) < 0)
743 opr->type = OPT_LABEL;
744 ret = check_segment_prefix(label);
747 aerr("fs/gs used\n");
751 strcpy(opr->name, label);
757 if (IS(words[w + 1], "ptr")) {
758 if (IS(words[w], "dword"))
759 opr->lmod = OPLM_DWORD;
760 else if (IS(words[w], "word"))
761 opr->lmod = OPLM_WORD;
762 else if (IS(words[w], "byte"))
763 opr->lmod = OPLM_BYTE;
764 else if (IS(words[w], "qword"))
765 opr->lmod = OPLM_QWORD;
767 aerr("type parsing failed\n");
769 wordc_in = wordc - w;
774 if (IS(words[w], "offset")) {
775 opr->type = OPT_OFFSET;
776 opr->lmod = OPLM_DWORD;
777 strcpy(opr->name, words[w + 1]);
778 pp = proto_parse(g_fhdr, opr->name, 1);
781 if (IS(words[w], "(offset")) {
782 p = strchr(words[w + 1], ')');
784 aerr("parse of bracketed offset failed\n");
786 opr->type = OPT_OFFSET;
787 strcpy(opr->name, words[w + 1]);
793 aerr("parse_operand 1 word expected\n");
795 ret = check_segment_prefix(words[w]);
798 aerr("fs/gs used\n");
800 memmove(words[w], words[w] + 3, strlen(words[w]) - 2);
802 strcpy(opr->name, words[w]);
804 if (words[w][0] == '[') {
805 opr->type = OPT_REGMEM;
806 ret = sscanf(words[w], "[%[^]]]", opr->name);
808 aerr("[] parse failure\n");
810 parse_indmode(opr->name, regmask_indirect, 1);
811 if (opr->lmod == OPLM_UNSPEC && parse_stack_el(opr->name, NULL, 1))
814 struct parsed_equ *eq =
815 equ_find(NULL, parse_stack_el(opr->name, NULL, 1), &i);
817 opr->lmod = eq->lmod;
819 // might be unaligned access
820 g_func_lmods |= 1 << OPLM_BYTE;
824 else if (strchr(words[w], '[')) {
826 p = strchr(words[w], '[');
827 opr->type = OPT_REGMEM;
828 parse_indmode(p, regmask_indirect, 0);
829 strncpy(buf, words[w], p - words[w]);
830 buf[p - words[w]] = 0;
831 pp = proto_parse(g_fhdr, buf, 1);
834 else if (('0' <= words[w][0] && words[w][0] <= '9')
835 || words[w][0] == '-')
837 number = parse_number(words[w]);
838 opr->type = OPT_CONST;
840 printf_number(opr->name, sizeof(opr->name), number);
844 ret = parse_reg(&tmplmod, opr->name);
846 setup_reg_opr(opr, ret, tmplmod, regmask);
850 // most likely var in data segment
851 opr->type = OPT_LABEL;
852 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
856 if (pp->is_fptr || pp->is_func) {
857 opr->lmod = OPLM_DWORD;
861 tmplmod = OPLM_UNSPEC;
862 if (!guess_lmod_from_c_type(&tmplmod, &pp->type))
863 anote("unhandled C type '%s' for '%s'\n",
864 pp->type.name, opr->name);
866 if (opr->lmod == OPLM_UNSPEC) {
868 opr->type_from_var = 1;
870 else if (opr->lmod != tmplmod) {
871 opr->size_mismatch = 1;
872 if (tmplmod < opr->lmod)
875 opr->is_ptr = pp->type.is_ptr;
877 opr->is_array = pp->type.is_array;
881 if (opr->lmod == OPLM_UNSPEC)
882 guess_lmod_from_name(opr);
886 static const struct {
891 { "repe", OPF_REP|OPF_REPZ },
892 { "repz", OPF_REP|OPF_REPZ },
893 { "repne", OPF_REP|OPF_REPNZ },
894 { "repnz", OPF_REP|OPF_REPNZ },
895 { "lock", OPF_LOCK }, // ignored for now..
898 #define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
900 static const struct {
903 unsigned short minopr;
904 unsigned short maxopr;
907 unsigned char pfo_inv;
909 { "nop", OP_NOP, 0, 0, 0 },
910 { "push", OP_PUSH, 1, 1, 0 },
911 { "pop", OP_POP, 1, 1, OPF_DATA },
912 { "leave",OP_LEAVE, 0, 0, OPF_DATA },
913 { "mov" , OP_MOV, 2, 2, OPF_DATA },
914 { "lea", OP_LEA, 2, 2, OPF_DATA },
915 { "movzx",OP_MOVZX, 2, 2, OPF_DATA },
916 { "movsx",OP_MOVSX, 2, 2, OPF_DATA },
917 { "xchg", OP_XCHG, 2, 2, OPF_DATA },
918 { "not", OP_NOT, 1, 1, OPF_DATA },
919 { "xlat", OP_XLAT, 0, 0, OPF_DATA },
920 { "cdq", OP_CDQ, 0, 0, OPF_DATA },
921 { "lodsb",OP_LODS, 0, 0, OPF_DATA },
922 { "lodsw",OP_LODS, 0, 0, OPF_DATA },
923 { "lodsd",OP_LODS, 0, 0, OPF_DATA },
924 { "stosb",OP_STOS, 0, 0, OPF_DATA },
925 { "stosw",OP_STOS, 0, 0, OPF_DATA },
926 { "stosd",OP_STOS, 0, 0, OPF_DATA },
927 { "movsb",OP_MOVS, 0, 0, OPF_DATA },
928 { "movsw",OP_MOVS, 0, 0, OPF_DATA },
929 { "movsd",OP_MOVS, 0, 0, OPF_DATA },
930 { "cmpsb",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
931 { "cmpsw",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
932 { "cmpsd",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
933 { "scasb",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
934 { "scasw",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
935 { "scasd",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
936 { "std", OP_STD, 0, 0, OPF_DATA }, // special flag
937 { "cld", OP_CLD, 0, 0, OPF_DATA },
938 { "add", OP_ADD, 2, 2, OPF_DATA|OPF_FLAGS },
939 { "sub", OP_SUB, 2, 2, OPF_DATA|OPF_FLAGS },
940 { "and", OP_AND, 2, 2, OPF_DATA|OPF_FLAGS },
941 { "or", OP_OR, 2, 2, OPF_DATA|OPF_FLAGS },
942 { "xor", OP_XOR, 2, 2, OPF_DATA|OPF_FLAGS },
943 { "shl", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
944 { "shr", OP_SHR, 2, 2, OPF_DATA|OPF_FLAGS },
945 { "sal", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
946 { "sar", OP_SAR, 2, 2, OPF_DATA|OPF_FLAGS },
947 { "shld", OP_SHLD, 3, 3, OPF_DATA|OPF_FLAGS },
948 { "shrd", OP_SHRD, 3, 3, OPF_DATA|OPF_FLAGS },
949 { "rol", OP_ROL, 2, 2, OPF_DATA|OPF_FLAGS },
950 { "ror", OP_ROR, 2, 2, OPF_DATA|OPF_FLAGS },
951 { "rcl", OP_RCL, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
952 { "rcr", OP_RCR, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
953 { "adc", OP_ADC, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
954 { "sbb", OP_SBB, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
955 { "bsf", OP_BSF, 2, 2, OPF_DATA|OPF_FLAGS },
956 { "inc", OP_INC, 1, 1, OPF_DATA|OPF_FLAGS },
957 { "dec", OP_DEC, 1, 1, OPF_DATA|OPF_FLAGS },
958 { "neg", OP_NEG, 1, 1, OPF_DATA|OPF_FLAGS },
959 { "mul", OP_MUL, 1, 1, OPF_DATA|OPF_FLAGS },
960 { "imul", OP_IMUL, 1, 3, OPF_DATA|OPF_FLAGS },
961 { "div", OP_DIV, 1, 1, OPF_DATA|OPF_FLAGS },
962 { "idiv", OP_IDIV, 1, 1, OPF_DATA|OPF_FLAGS },
963 { "test", OP_TEST, 2, 2, OPF_FLAGS },
964 { "cmp", OP_CMP, 2, 2, OPF_FLAGS },
965 { "retn", OP_RET, 0, 1, OPF_TAIL },
966 { "call", OP_CALL, 1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
967 { "jmp", OP_JMP, 1, 1, OPF_JMP },
968 { "jecxz",OP_JECXZ, 1, 1, OPF_JMP|OPF_CJMP },
969 { "loop", OP_LOOP, 1, 1, OPF_JMP|OPF_CJMP|OPF_DATA },
970 { "jo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 0 }, // 70 OF=1
971 { "jno", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 1 }, // 71 OF=0
972 { "jc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72 CF=1
973 { "jb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72
974 { "jnc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73 CF=0
975 { "jnb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
976 { "jae", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
977 { "jz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74 ZF=1
978 { "je", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74
979 { "jnz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75 ZF=0
980 { "jne", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75
981 { "jbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76 CF=1||ZF=1
982 { "jna", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76
983 { "ja", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77 CF=0&&ZF=0
984 { "jnbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77
985 { "js", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 0 }, // 78 SF=1
986 { "jns", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 1 }, // 79 SF=0
987 { "jp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a PF=1
988 { "jpe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a
989 { "jnp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b PF=0
990 { "jpo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b
991 { "jl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c SF!=OF
992 { "jnge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c
993 { "jge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d SF=OF
994 { "jnl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d
995 { "jle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e ZF=1||SF!=OF
996 { "jng", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e
997 { "jg", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f ZF=0&&SF=OF
998 { "jnle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f
999 { "seto", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 0 },
1000 { "setno", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 1 },
1001 { "setc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1002 { "setb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1003 { "setnc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1004 { "setae", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1005 { "setnb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1006 { "setz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1007 { "sete", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1008 { "setnz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1009 { "setne", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1010 { "setbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1011 { "setna", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1012 { "seta", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1013 { "setnbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1014 { "sets", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 0 },
1015 { "setns", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 1 },
1016 { "setp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1017 { "setpe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1018 { "setnp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1019 { "setpo", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1020 { "setl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1021 { "setnge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1022 { "setge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1023 { "setnl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1024 { "setle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1025 { "setng", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1026 { "setg", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1027 { "setnle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1029 { "fld", OP_FLD, 1, 1, OPF_FPUSH },
1030 { "fild", OP_FILD, 1, 1, OPF_FPUSH },
1031 { "fld1", OP_FLDc, 0, 0, OPF_FPUSH },
1032 { "fldz", OP_FLDc, 0, 0, OPF_FPUSH },
1033 { "fstp", OP_FST, 1, 1, OPF_FPOP },
1034 { "fst", OP_FST, 1, 1, 0 },
1035 { "fadd", OP_FADD, 0, 2, 0 },
1036 { "faddp", OP_FADD, 0, 2, OPF_FPOP },
1037 { "fdiv", OP_FDIV, 0, 2, 0 },
1038 { "fdivp", OP_FDIV, 0, 2, OPF_FPOP },
1039 { "fmul", OP_FMUL, 0, 2, 0 },
1040 { "fmulp", OP_FMUL, 0, 2, OPF_FPOP },
1041 { "fsub", OP_FSUB, 0, 2, 0 },
1042 { "fsubp", OP_FSUB, 0, 2, OPF_FPOP },
1043 { "fdivr", OP_FDIVR, 0, 2, 0 },
1044 { "fdivrp", OP_FDIVR, 0, 2, OPF_FPOP },
1045 { "fsubr", OP_FSUBR, 0, 2, 0 },
1046 { "fsubrp", OP_FSUBR, 0, 2, OPF_FPOP },
1047 { "fiadd", OP_FIADD, 1, 1, 0 },
1048 { "fidiv", OP_FIDIV, 1, 1, 0 },
1049 { "fimul", OP_FIMUL, 1, 1, 0 },
1050 { "fisub", OP_FISUB, 1, 1, 0 },
1051 { "fidivr", OP_FIDIVR, 1, 1, 0 },
1052 { "fisubr", OP_FISUBR, 1, 1, 0 },
1053 { "fcos", OP_FCOS, 0, 0, 0 },
1054 { "fpatan", OP_FPATAN, 0, 0, OPF_FPOP },
1055 { "fptan", OP_FPTAN, 0, 0, OPF_FPUSH },
1056 { "fsin", OP_FSIN, 0, 0, 0 },
1057 { "fsqrt", OP_FSQRT, 0, 0, 0 },
1059 { "emms", OP_EMMS, 0, 0, OPF_DATA },
1060 { "movq", OP_MOV, 2, 2, OPF_DATA },
1061 // pseudo-ops for lib calls
1062 { "_ftol", OPP_FTOL },
1067 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
1069 enum opr_lenmod lmod = OPLM_UNSPEC;
1070 int prefix_flags = 0;
1078 for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
1079 if (IS(words[w], pref_table[i].name)) {
1080 prefix_flags = pref_table[i].flags;
1087 aerr("lone prefix: '%s'\n", words[0]);
1092 for (i = 0; i < ARRAY_SIZE(op_table); i++) {
1093 if (IS(words[w], op_table[i].name))
1097 if (i == ARRAY_SIZE(op_table)) {
1099 aerr("unhandled op: '%s'\n", words[0]);
1104 op->op = op_table[i].op;
1105 op->flags = op_table[i].flags | prefix_flags;
1106 op->pfo = op_table[i].pfo;
1107 op->pfo_inv = op_table[i].pfo_inv;
1108 op->regmask_src = op->regmask_dst = 0;
1111 if (op->op == OP_UD2)
1114 for (opr = 0; opr < op_table[i].maxopr; opr++) {
1115 if (opr >= op_table[i].minopr && w >= wordc)
1118 regmask = regmask_ind = 0;
1119 w = parse_operand(&op->operand[opr], ®mask, ®mask_ind,
1120 words, wordc, w, op->flags);
1122 if (opr == 0 && (op->flags & OPF_DATA))
1123 op->regmask_dst = regmask;
1125 op->regmask_src |= regmask;
1126 op->regmask_src |= regmask_ind;
1128 if (op->operand[opr].lmod != OPLM_UNSPEC)
1129 g_func_lmods |= 1 << op->operand[opr].lmod;
1133 aerr("parse_op %s incomplete: %d/%d\n",
1134 words[0], w, wordc);
1137 op->operand_cnt = opr;
1138 if (!strncmp(op_table[i].name, "set", 3))
1139 op->operand[0].lmod = OPLM_BYTE;
1142 // first operand is not dst
1145 op->regmask_src |= op->regmask_dst;
1146 op->regmask_dst = 0;
1149 // first operand is src too
1161 op->regmask_src |= op->regmask_dst;
1166 op->regmask_src |= op->regmask_dst;
1167 op->regmask_dst |= op->regmask_src;
1173 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1174 && op->operand[0].lmod == op->operand[1].lmod
1175 && op->operand[0].reg == op->operand[1].reg
1176 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1178 op->regmask_src = 0;
1181 op->regmask_src |= op->regmask_dst;
1184 // ops with implicit argumets
1186 op->operand_cnt = 2;
1187 setup_reg_opr(&op->operand[0], xAX, OPLM_BYTE, &op->regmask_src);
1188 op->regmask_dst = op->regmask_src;
1189 setup_reg_opr(&op->operand[1], xBX, OPLM_DWORD, &op->regmask_src);
1193 op->operand_cnt = 2;
1194 setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
1195 setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
1201 if (words[op_w][4] == 'b')
1203 else if (words[op_w][4] == 'w')
1205 else if (words[op_w][4] == 'd')
1208 op->regmask_src = 0;
1209 setup_reg_opr(&op->operand[j++], op->op == OP_LODS ? xSI : xDI,
1210 OPLM_DWORD, &op->regmask_src);
1211 op->regmask_dst = op->regmask_src;
1212 setup_reg_opr(&op->operand[j++], xAX, lmod,
1213 op->op == OP_LODS ? &op->regmask_dst : &op->regmask_src);
1214 if (op->flags & OPF_REP) {
1215 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1216 op->regmask_dst |= 1 << xCX;
1218 op->operand_cnt = j;
1223 if (words[op_w][4] == 'b')
1225 else if (words[op_w][4] == 'w')
1227 else if (words[op_w][4] == 'd')
1230 op->regmask_src = 0;
1231 // note: lmod is not correct, don't have where to place it
1232 setup_reg_opr(&op->operand[j++], xDI, lmod, &op->regmask_src);
1233 setup_reg_opr(&op->operand[j++], xSI, OPLM_DWORD, &op->regmask_src);
1234 if (op->flags & OPF_REP)
1235 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1236 op->operand_cnt = j;
1237 op->regmask_dst = op->regmask_src;
1241 op->regmask_dst = 1 << xCX;
1244 op->operand_cnt = 2;
1245 op->regmask_src = 1 << xCX;
1246 op->operand[1].type = OPT_REG;
1247 op->operand[1].reg = xCX;
1248 op->operand[1].lmod = OPLM_DWORD;
1252 if (op->operand_cnt == 2) {
1253 if (op->operand[0].type != OPT_REG)
1254 aerr("reg expected\n");
1255 op->regmask_src |= 1 << op->operand[0].reg;
1257 if (op->operand_cnt != 1)
1262 op->regmask_src |= op->regmask_dst;
1263 op->regmask_dst = (1 << xDX) | (1 << xAX);
1264 if (op->operand[0].lmod == OPLM_UNSPEC)
1265 op->operand[0].lmod = OPLM_DWORD;
1270 // we could set up operands for edx:eax, but there is no real need to
1271 // (see is_opr_modified())
1272 op->regmask_src |= op->regmask_dst;
1273 op->regmask_dst = (1 << xDX) | (1 << xAX);
1274 if (op->operand[0].lmod == OPLM_UNSPEC)
1275 op->operand[0].lmod = OPLM_DWORD;
1283 op->regmask_src |= op->regmask_dst;
1284 if (op->operand[1].lmod == OPLM_UNSPEC)
1285 op->operand[1].lmod = OPLM_BYTE;
1290 op->regmask_src |= op->regmask_dst;
1291 if (op->operand[2].lmod == OPLM_UNSPEC)
1292 op->operand[2].lmod = OPLM_BYTE;
1296 op->regmask_src |= op->regmask_dst;
1297 op->regmask_dst = 0;
1298 if (op->operand[0].lmod == OPLM_UNSPEC
1299 && (op->operand[0].type == OPT_CONST
1300 || op->operand[0].type == OPT_OFFSET
1301 || op->operand[0].type == OPT_LABEL))
1302 op->operand[0].lmod = OPLM_DWORD;
1308 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1309 && op->operand[0].lmod == op->operand[1].lmod
1310 && op->operand[0].reg == op->operand[1].reg
1311 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1313 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1314 op->regmask_src = op->regmask_dst = 0;
1319 if (op->operand[0].type == OPT_REG
1320 && op->operand[1].type == OPT_REGMEM)
1323 snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1324 if (IS(buf, op->operand[1].name))
1325 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1330 // trashed regs must be explicitly detected later
1331 op->regmask_dst = 0;
1335 op->regmask_dst = (1 << xBP) | (1 << xSP);
1336 op->regmask_src = 1 << xBP;
1341 op->regmask_dst |= mxST0;
1345 op->regmask_dst |= mxST0;
1346 if (IS(words[op_w] + 3, "1"))
1347 op->operand[0].val = X87_CONST_1;
1348 else if (IS(words[op_w] + 3, "z"))
1349 op->operand[0].val = X87_CONST_Z;
1355 op->regmask_src |= mxST0;
1364 op->regmask_src |= mxST0;
1365 if (op->operand_cnt == 2)
1366 op->regmask_src |= op->regmask_dst;
1367 else if (op->operand_cnt == 1) {
1368 memcpy(&op->operand[1], &op->operand[0], sizeof(op->operand[1]));
1369 op->operand[0].type = OPT_REG;
1370 op->operand[0].lmod = OPLM_QWORD;
1371 op->operand[0].reg = xST0;
1372 op->regmask_dst |= mxST0;
1375 // IDA doesn't use this
1376 aerr("no operands?\n");
1388 op->regmask_src |= mxST0;
1389 op->regmask_dst |= mxST0;
1393 op->regmask_src |= mxST0 | mxST1;
1394 op->regmask_dst |= mxST0;
1405 if (op->operand[0].type == OPT_REG
1406 && op->operand[1].type == OPT_CONST)
1408 struct parsed_opr *op1 = &op->operand[1];
1409 if ((op->op == OP_AND && op1->val == 0)
1412 || (op->operand[0].lmod == OPLM_WORD && op1->val == 0xffff)
1413 || (op->operand[0].lmod == OPLM_BYTE && op1->val == 0xff))))
1415 op->regmask_src = 0;
1420 static const char *op_name(struct parsed_op *po)
1422 static char buf[16];
1426 if (po->op == OP_JCC || po->op == OP_SCC) {
1428 *p++ = (po->op == OP_JCC) ? 'j' : 's';
1431 strcpy(p, parsed_flag_op_names[po->pfo]);
1435 for (i = 0; i < ARRAY_SIZE(op_table); i++)
1436 if (op_table[i].op == po->op)
1437 return op_table[i].name;
1443 static const char *dump_op(struct parsed_op *po)
1445 static char out[128];
1452 snprintf(out, sizeof(out), "%s", op_name(po));
1453 for (i = 0; i < po->operand_cnt; i++) {
1457 snprintf(p, sizeof(out) - (p - out),
1458 po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1459 po->operand[i].name);
1465 static const char *lmod_type_u(struct parsed_op *po,
1466 enum opr_lenmod lmod)
1478 ferr(po, "invalid lmod: %d\n", lmod);
1479 return "(_invalid_)";
1483 static const char *lmod_cast_u(struct parsed_op *po,
1484 enum opr_lenmod lmod)
1496 ferr(po, "invalid lmod: %d\n", lmod);
1497 return "(_invalid_)";
1501 static const char *lmod_cast_u_ptr(struct parsed_op *po,
1502 enum opr_lenmod lmod)
1514 ferr(po, "invalid lmod: %d\n", lmod);
1515 return "(_invalid_)";
1519 static const char *lmod_cast_s(struct parsed_op *po,
1520 enum opr_lenmod lmod)
1532 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1533 return "(_invalid_)";
1537 static const char *lmod_cast(struct parsed_op *po,
1538 enum opr_lenmod lmod, int is_signed)
1541 lmod_cast_s(po, lmod) :
1542 lmod_cast_u(po, lmod);
1545 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1557 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1562 static const char *opr_name(struct parsed_op *po, int opr_num)
1564 if (opr_num >= po->operand_cnt)
1565 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1566 return po->operand[opr_num].name;
1569 static unsigned int opr_const(struct parsed_op *po, int opr_num)
1571 if (opr_num >= po->operand_cnt)
1572 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1573 if (po->operand[opr_num].type != OPT_CONST)
1574 ferr(po, "opr %d: const expected\n", opr_num);
1575 return po->operand[opr_num].val;
1578 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1580 if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
1581 ferr(po, "invalid reg: %d\n", popr->reg);
1582 return regs_r32[popr->reg];
1585 static int check_simple_cast(const char *cast, int *bits, int *is_signed)
1587 if (IS_START(cast, "(s8)") || IS_START(cast, "(u8)"))
1589 else if (IS_START(cast, "(s16)") || IS_START(cast, "(u16)"))
1591 else if (IS_START(cast, "(s32)") || IS_START(cast, "(u32)"))
1593 else if (IS_START(cast, "(s64)") || IS_START(cast, "(u64)"))
1598 *is_signed = cast[1] == 's' ? 1 : 0;
1602 static int check_deref_cast(const char *cast, int *bits)
1604 if (IS_START(cast, "*(u8 *)"))
1606 else if (IS_START(cast, "*(u16 *)"))
1608 else if (IS_START(cast, "*(u32 *)"))
1610 else if (IS_START(cast, "*(u64 *)"))
1618 // cast1 is the "final" cast
1619 static const char *simplify_cast(const char *cast1, const char *cast2)
1621 static char buf[256];
1629 if (IS(cast1, cast2))
1632 if (check_simple_cast(cast1, &bits1, &s1) == 0
1633 && check_simple_cast(cast2, &bits2, &s2) == 0)
1638 if (check_simple_cast(cast1, &bits1, &s1) == 0
1639 && check_deref_cast(cast2, &bits2) == 0)
1641 if (bits1 == bits2) {
1642 snprintf(buf, sizeof(buf), "*(%c%d *)", s1 ? 's' : 'u', bits1);
1647 if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1650 snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1654 static const char *simplify_cast_num(const char *cast, unsigned int val)
1656 if (IS(cast, "(u8)") && val < 0x100)
1658 if (IS(cast, "(s8)") && val < 0x80)
1660 if (IS(cast, "(u16)") && val < 0x10000)
1662 if (IS(cast, "(s16)") && val < 0x8000)
1664 if (IS(cast, "(s32)") && val < 0x80000000)
1670 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1679 namelen = strlen(name);
1681 p = strchr(name, '+');
1685 ferr(po, "equ parse failed for '%s'\n", name);
1687 if (IS_START(p, "0x"))
1689 *extra_offs = strtol(p, &endp, 16);
1691 ferr(po, "equ parse failed for '%s'\n", name);
1694 for (i = 0; i < g_eqcnt; i++)
1695 if (strncmp(g_eqs[i].name, name, namelen) == 0
1696 && g_eqs[i].name[namelen] == 0)
1700 ferr(po, "unresolved equ name: '%s'\n", name);
1707 static int is_stack_access(struct parsed_op *po,
1708 const struct parsed_opr *popr)
1710 return (parse_stack_el(popr->name, NULL, 0)
1711 || (g_bp_frame && !(po->flags & OPF_EBP_S)
1712 && IS_START(popr->name, "ebp")));
1715 static void parse_stack_access(struct parsed_op *po,
1716 const char *name, char *ofs_reg, int *offset_out,
1717 int *stack_ra_out, const char **bp_arg_out, int is_lea)
1719 const char *bp_arg = "";
1720 const char *p = NULL;
1721 struct parsed_equ *eq;
1728 if (IS_START(name, "ebp-")
1729 || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1732 if (IS_START(p, "0x"))
1734 offset = strtoul(p, &endp, 16);
1738 ferr(po, "ebp- parse of '%s' failed\n", name);
1741 bp_arg = parse_stack_el(name, ofs_reg, 0);
1742 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1743 eq = equ_find(po, bp_arg, &offset);
1745 ferr(po, "detected but missing eq\n");
1746 offset += eq->offset;
1749 if (!strncmp(name, "ebp", 3))
1752 // yes it sometimes LEAs ra for compares..
1753 if (!is_lea && ofs_reg[0] == 0
1754 && stack_ra <= offset && offset < stack_ra + 4)
1756 ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1759 *offset_out = offset;
1760 *stack_ra_out = stack_ra;
1762 *bp_arg_out = bp_arg;
1765 static int stack_frame_access(struct parsed_op *po,
1766 struct parsed_opr *popr, char *buf, size_t buf_size,
1767 const char *name, const char *cast, int is_src, int is_lea)
1769 enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1770 const char *prefix = "";
1771 const char *bp_arg = NULL;
1772 char ofs_reg[16] = { 0, };
1773 int i, arg_i, arg_s;
1781 if (po->flags & OPF_EBP_S)
1782 ferr(po, "stack_frame_access while ebp is scratch\n");
1784 parse_stack_access(po, name, ofs_reg, &offset,
1785 &stack_ra, &bp_arg, is_lea);
1787 if (offset > stack_ra)
1789 arg_i = (offset - stack_ra - 4) / 4;
1790 if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1792 if (g_func_pp->is_vararg
1793 && arg_i == g_func_pp->argc_stack && is_lea)
1795 // should be va_list
1798 snprintf(buf, buf_size, "%sap", cast);
1801 ferr(po, "offset %d (%s,%d) doesn't map to any arg\n",
1802 offset, bp_arg, arg_i);
1804 if (ofs_reg[0] != 0)
1805 ferr(po, "offset reg on arg access?\n");
1807 for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1808 if (g_func_pp->arg[i].reg != NULL)
1814 if (i == g_func_pp->argc)
1815 ferr(po, "arg %d not in prototype?\n", arg_i);
1817 popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
1824 ferr(po, "lea/byte to arg?\n");
1825 if (is_src && (offset & 3) == 0)
1826 snprintf(buf, buf_size, "%sa%d",
1827 simplify_cast(cast, "(u8)"), i + 1);
1829 snprintf(buf, buf_size, "%sBYTE%d(a%d)",
1830 cast, offset & 3, i + 1);
1835 ferr(po, "lea/word to arg?\n");
1840 ferr(po, "problematic arg store\n");
1841 snprintf(buf, buf_size, "%s((char *)&a%d + 1)",
1842 simplify_cast(cast, "*(u16 *)"), i + 1);
1845 ferr(po, "unaligned arg word load\n");
1847 else if (is_src && (offset & 2) == 0)
1848 snprintf(buf, buf_size, "%sa%d",
1849 simplify_cast(cast, "(u16)"), i + 1);
1851 snprintf(buf, buf_size, "%s%sWORD(a%d)",
1852 cast, (offset & 2) ? "HI" : "LO", i + 1);
1864 snprintf(buf, buf_size, "(u32)&a%d + %d",
1867 ferr(po, "unaligned arg store\n");
1869 // mov edx, [ebp+arg_4+2]; movsx ecx, dx
1870 snprintf(buf, buf_size, "%s(a%d >> %d)",
1871 prefix, i + 1, (offset & 3) * 8);
1875 snprintf(buf, buf_size, "%s%sa%d",
1876 prefix, is_lea ? "&" : "", i + 1);
1881 ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
1885 snprintf(g_comment, sizeof(g_comment), "%s unaligned", bp_arg);
1888 guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
1889 if (tmp_lmod != OPLM_DWORD
1890 && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
1891 < lmod_bytes(po, popr->lmod) + (offset & 3))))
1893 ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
1894 i + 1, offset, g_func_pp->arg[i].type.name);
1896 // can't check this because msvc likes to reuse
1897 // arg space for scratch..
1898 //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
1899 // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
1903 if (g_stack_fsz == 0)
1904 ferr(po, "stack var access without stackframe\n");
1905 g_stack_frame_used = 1;
1907 sf_ofs = g_stack_fsz + offset;
1908 lim = (ofs_reg[0] != 0) ? -4 : 0;
1909 if (offset > 0 || sf_ofs < lim)
1910 ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
1920 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1921 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1925 if ((sf_ofs & 1) || ofs_reg[0] != 0) {
1926 // known unaligned or possibly unaligned
1927 strcat(g_comment, " unaligned");
1929 prefix = "*(u16 *)&";
1930 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1931 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1934 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
1938 if ((sf_ofs & 3) || ofs_reg[0] != 0) {
1939 // known unaligned or possibly unaligned
1940 strcat(g_comment, " unaligned");
1942 prefix = "*(u32 *)&";
1943 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1944 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1947 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
1951 ferr_assert(po, !(sf_ofs & 7));
1952 ferr_assert(po, ofs_reg[0] == 0);
1953 // float callers set is_lea
1954 ferr_assert(po, is_lea);
1955 snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
1959 ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
1966 static void check_func_pp(struct parsed_op *po,
1967 const struct parsed_proto *pp, const char *pfx)
1969 enum opr_lenmod tmp_lmod;
1973 if (pp->argc_reg != 0) {
1974 if (/*!g_allow_regfunc &&*/ !pp->is_fastcall) {
1975 pp_print(buf, sizeof(buf), pp);
1976 ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
1978 if (pp->argc_stack > 0 && pp->argc_reg != 2)
1979 ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
1980 pfx, pp->argc_reg, pp->argc_stack);
1983 // fptrs must use 32bit args, callsite might have no information and
1984 // lack a cast to smaller types, which results in incorrectly masked
1985 // args passed (callee may assume masked args, it does on ARM)
1986 if (!pp->is_osinc) {
1987 for (i = 0; i < pp->argc; i++) {
1988 ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
1989 if (ret && tmp_lmod != OPLM_DWORD)
1990 ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
1991 i + 1, pp->arg[i].type.name);
1996 static const char *check_label_read_ref(struct parsed_op *po,
1999 const struct parsed_proto *pp;
2001 pp = proto_parse(g_fhdr, name, 0);
2003 ferr(po, "proto_parse failed for ref '%s'\n", name);
2006 check_func_pp(po, pp, "ref");
2011 static char *out_src_opr(char *buf, size_t buf_size,
2012 struct parsed_op *po, struct parsed_opr *popr, const char *cast,
2015 char tmp1[256], tmp2[256];
2024 switch (popr->type) {
2027 ferr(po, "lea from reg?\n");
2029 switch (popr->lmod) {
2031 snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2034 snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2037 snprintf(buf, buf_size, "%s%s",
2038 simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2041 if (popr->name[1] == 'h') // XXX..
2042 snprintf(buf, buf_size, "%s(%s >> 8)",
2043 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2045 snprintf(buf, buf_size, "%s%s",
2046 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2049 ferr(po, "invalid src lmod: %d\n", popr->lmod);
2054 if (is_stack_access(po, popr)) {
2055 stack_frame_access(po, popr, buf, buf_size,
2056 popr->name, cast, 1, is_lea);
2060 strcpy(expr, popr->name);
2061 if (strchr(expr, '[')) {
2062 // special case: '[' can only be left for label[reg] form
2063 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2065 ferr(po, "parse failure for '%s'\n", expr);
2066 if (tmp1[0] == '(') {
2067 // (off_4FFF50+3)[eax]
2068 p = strchr(tmp1 + 1, ')');
2069 if (p == NULL || p[1] != 0)
2070 ferr(po, "parse failure (2) for '%s'\n", expr);
2072 memmove(tmp1, tmp1 + 1, strlen(tmp1));
2074 snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2077 // XXX: do we need more parsing?
2079 snprintf(buf, buf_size, "%s", expr);
2083 snprintf(buf, buf_size, "%s(%s)",
2084 simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2088 name = check_label_read_ref(po, popr->name);
2089 if (cast[0] == 0 && popr->is_ptr)
2093 snprintf(buf, buf_size, "(u32)&%s", name);
2094 else if (popr->size_lt)
2095 snprintf(buf, buf_size, "%s%s%s%s", cast,
2096 lmod_cast_u_ptr(po, popr->lmod),
2097 popr->is_array ? "" : "&", name);
2099 snprintf(buf, buf_size, "%s%s%s", cast, name,
2100 popr->is_array ? "[0]" : "");
2104 name = check_label_read_ref(po, popr->name);
2108 ferr(po, "lea an offset?\n");
2109 snprintf(buf, buf_size, "%s&%s", cast, name);
2114 ferr(po, "lea from const?\n");
2116 printf_number(tmp1, sizeof(tmp1), popr->val);
2117 if (popr->val == 0 && strchr(cast, '*'))
2118 snprintf(buf, buf_size, "NULL");
2120 snprintf(buf, buf_size, "%s%s",
2121 simplify_cast_num(cast, popr->val), tmp1);
2125 ferr(po, "invalid src type: %d\n", popr->type);
2131 // note: may set is_ptr (we find that out late for ebp frame..)
2132 static char *out_dst_opr(char *buf, size_t buf_size,
2133 struct parsed_op *po, struct parsed_opr *popr)
2135 switch (popr->type) {
2137 switch (popr->lmod) {
2139 snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2142 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2146 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2150 if (popr->name[1] == 'h') // XXX..
2151 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2153 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2156 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2161 if (is_stack_access(po, popr)) {
2162 stack_frame_access(po, popr, buf, buf_size,
2163 popr->name, "", 0, 0);
2167 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2170 if (popr->size_mismatch)
2171 snprintf(buf, buf_size, "%s%s%s",
2172 lmod_cast_u_ptr(po, popr->lmod),
2173 popr->is_array ? "" : "&", popr->name);
2175 snprintf(buf, buf_size, "%s%s", popr->name,
2176 popr->is_array ? "[0]" : "");
2180 ferr(po, "invalid dst type: %d\n", popr->type);
2186 static char *out_src_opr_u32(char *buf, size_t buf_size,
2187 struct parsed_op *po, struct parsed_opr *popr)
2189 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2192 static char *out_src_opr_float(char *buf, size_t buf_size,
2193 struct parsed_op *po, struct parsed_opr *popr)
2195 const char *cast = NULL;
2198 switch (popr->type) {
2200 if (popr->reg < xST0 || popr->reg > xST7)
2201 ferr(po, "bad reg: %d\n", popr->reg);
2203 snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2209 switch (popr->lmod) {
2217 ferr(po, "unhandled lmod: %d\n", popr->lmod);
2220 out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2221 snprintf(buf, buf_size, "*((%s *)%s)", cast, tmp);
2225 ferr(po, "invalid float type: %d\n", popr->type);
2231 static char *out_dst_opr_float(char *buf, size_t buf_size,
2232 struct parsed_op *po, struct parsed_opr *popr)
2235 return out_src_opr_float(buf, buf_size, po, popr);
2238 static void out_test_for_cc(char *buf, size_t buf_size,
2239 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2240 enum opr_lenmod lmod, const char *expr)
2242 const char *cast, *scast;
2244 cast = lmod_cast_u(po, lmod);
2245 scast = lmod_cast_s(po, lmod);
2249 case PFO_BE: // CF=1||ZF=1; CF=0
2250 snprintf(buf, buf_size, "(%s%s %s 0)",
2251 cast, expr, is_inv ? "!=" : "==");
2255 case PFO_L: // SF!=OF; OF=0
2256 snprintf(buf, buf_size, "(%s%s %s 0)",
2257 scast, expr, is_inv ? ">=" : "<");
2260 case PFO_LE: // ZF=1||SF!=OF; OF=0
2261 snprintf(buf, buf_size, "(%s%s %s 0)",
2262 scast, expr, is_inv ? ">" : "<=");
2266 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2270 static void out_cmp_for_cc(char *buf, size_t buf_size,
2271 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2273 const char *cast, *scast, *cast_use;
2274 char buf1[256], buf2[256];
2275 enum opr_lenmod lmod;
2277 if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2278 ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2279 po->operand[0].lmod, po->operand[1].lmod);
2280 lmod = po->operand[0].lmod;
2282 cast = lmod_cast_u(po, lmod);
2283 scast = lmod_cast_s(po, lmod);
2299 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2302 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2303 if (po->op == OP_DEC)
2304 snprintf(buf2, sizeof(buf2), "1");
2306 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_use, 0);
2310 // note: must be unsigned compare
2311 snprintf(buf, buf_size, "(%s %s %s)",
2312 buf1, is_inv ? ">=" : "<", buf2);
2316 snprintf(buf, buf_size, "(%s %s %s)",
2317 buf1, is_inv ? "!=" : "==", buf2);
2321 // note: must be unsigned compare
2322 snprintf(buf, buf_size, "(%s %s %s)",
2323 buf1, is_inv ? ">" : "<=", buf2);
2326 if (is_inv && lmod == OPLM_BYTE
2327 && po->operand[1].type == OPT_CONST
2328 && po->operand[1].val == 0xff)
2330 snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2331 snprintf(buf, buf_size, "(0)");
2335 // note: must be signed compare
2337 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2338 scast, buf1, buf2, is_inv ? ">=" : "<");
2342 snprintf(buf, buf_size, "(%s %s %s)",
2343 buf1, is_inv ? ">=" : "<", buf2);
2347 snprintf(buf, buf_size, "(%s %s %s)",
2348 buf1, is_inv ? ">" : "<=", buf2);
2356 static void out_cmp_test(char *buf, size_t buf_size,
2357 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2359 char buf1[256], buf2[256], buf3[256];
2361 if (po->op == OP_TEST) {
2362 if (IS(opr_name(po, 0), opr_name(po, 1))) {
2363 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2366 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2367 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2368 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2370 out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2371 po->operand[0].lmod, buf3);
2373 else if (po->op == OP_CMP) {
2374 out_cmp_for_cc(buf, buf_size, po, pfo, is_inv);
2377 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2380 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2381 struct parsed_opr *popr2)
2383 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2384 ferr(po, "missing lmod for both operands\n");
2386 if (popr1->lmod == OPLM_UNSPEC)
2387 popr1->lmod = popr2->lmod;
2388 else if (popr2->lmod == OPLM_UNSPEC)
2389 popr2->lmod = popr1->lmod;
2390 else if (popr1->lmod != popr2->lmod) {
2391 if (popr1->type_from_var) {
2392 popr1->size_mismatch = 1;
2393 if (popr1->lmod < popr2->lmod)
2395 popr1->lmod = popr2->lmod;
2397 else if (popr2->type_from_var) {
2398 popr2->size_mismatch = 1;
2399 if (popr2->lmod < popr1->lmod)
2401 popr2->lmod = popr1->lmod;
2404 ferr(po, "conflicting lmods: %d vs %d\n",
2405 popr1->lmod, popr2->lmod);
2409 static const char *op_to_c(struct parsed_op *po)
2433 ferr(po, "op_to_c was supplied with %d\n", po->op);
2437 // last op in stream - unconditional branch or ret
2438 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2439 || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2440 && ops[_i].op != OP_CALL))
2442 #define check_i(po, i) \
2444 ferr(po, "bad " #i ": %d\n", i)
2446 // note: this skips over calls and rm'd stuff assuming they're handled
2447 // so it's intended to use at one of final passes
2448 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2449 int depth, int flags_set)
2451 struct parsed_op *po;
2456 for (; i < opcnt; i++) {
2458 if (po->cc_scratch == magic)
2459 return ret; // already checked
2460 po->cc_scratch = magic;
2462 if (po->flags & OPF_TAIL) {
2463 if (po->op == OP_CALL) {
2464 if (po->pp != NULL && po->pp->is_noreturn)
2465 // assume no stack cleanup for noreturn
2468 return -1; // deadend
2471 if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
2474 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2475 if (po->btj != NULL) {
2477 for (j = 0; j < po->btj->count; j++) {
2478 check_i(po, po->btj->d[j].bt_i);
2479 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2482 return ret; // dead end
2487 check_i(po, po->bt_i);
2488 if (po->flags & OPF_CJMP) {
2489 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2492 return ret; // dead end
2501 if ((po->op == OP_POP || po->op == OP_PUSH)
2502 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2507 if (po->op == OP_PUSH) {
2510 else if (po->op == OP_POP) {
2511 if (relevant && depth == 0) {
2512 po->flags |= flags_set;
2522 // scan for 'reg' pop backwards starting from i
2523 // intended to use for register restore search, so other reg
2524 // references are considered an error
2525 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2527 struct parsed_op *po;
2528 struct label_ref *lr;
2531 ops[i].cc_scratch = magic;
2535 if (g_labels[i] != NULL) {
2536 lr = &g_label_refs[i];
2537 for (; lr != NULL; lr = lr->next) {
2538 check_i(&ops[i], lr->i);
2539 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2543 if (i > 0 && LAST_OP(i - 1))
2551 if (ops[i].cc_scratch == magic)
2553 ops[i].cc_scratch = magic;
2556 if (po->op == OP_POP && po->operand[0].reg == reg) {
2557 if (po->flags & (OPF_RMD|OPF_DONE))
2560 po->flags |= set_flags;
2564 // this also covers the case where we reach corresponding push
2565 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2569 // nothing interesting on this path
2573 static void find_reachable_exits(int i, int opcnt, int magic,
2574 int *exits, int *exit_count)
2576 struct parsed_op *po;
2579 for (; i < opcnt; i++)
2582 if (po->cc_scratch == magic)
2584 po->cc_scratch = magic;
2586 if (po->flags & OPF_TAIL) {
2587 ferr_assert(po, *exit_count < MAX_EXITS);
2588 exits[*exit_count] = i;
2593 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2594 if (po->flags & OPF_RMD)
2597 if (po->btj != NULL) {
2598 for (j = 0; j < po->btj->count; j++) {
2599 check_i(po, po->btj->d[j].bt_i);
2600 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2606 check_i(po, po->bt_i);
2607 if (po->flags & OPF_CJMP)
2608 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2616 // scan for 'reg' pop backwards starting from exits (all paths)
2617 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2619 static int exits[MAX_EXITS];
2620 static int exit_count;
2625 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2627 ferr_assert(&ops[i], exit_count > 0);
2630 for (j = 0; j < exit_count; j++) {
2631 ret = scan_for_rsave_pop_reg(exits[j], i + opcnt * 16 + set_flags,
2640 // scan for one or more pop of push <const>
2641 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2642 int push_i, int is_probe)
2644 struct parsed_op *po;
2645 struct label_ref *lr;
2649 for (; i < opcnt; i++)
2652 if (po->cc_scratch == magic)
2653 return ret; // already checked
2654 po->cc_scratch = magic;
2656 if (po->flags & OPF_JMP) {
2657 if (po->flags & OPF_RMD)
2659 if (po->op == OP_CALL)
2662 if (po->btj != NULL) {
2663 for (j = 0; j < po->btj->count; j++) {
2664 check_i(po, po->btj->d[j].bt_i);
2665 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2673 check_i(po, po->bt_i);
2674 if (po->flags & OPF_CJMP) {
2675 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2686 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2689 if (g_labels[i] != NULL) {
2690 // all refs must be visited
2691 lr = &g_label_refs[i];
2692 for (; lr != NULL; lr = lr->next) {
2694 if (ops[lr->i].cc_scratch != magic)
2697 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2701 if (po->op == OP_POP)
2703 if (po->flags & (OPF_RMD|OPF_DONE))
2707 po->flags |= OPF_DONE;
2708 po->datap = &ops[push_i];
2717 static void scan_for_pop_const(int i, int opcnt, int magic)
2721 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
2723 ops[i].flags |= OPF_RMD | OPF_DONE;
2724 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
2728 // check if all branch targets within a marked path are also marked
2729 // note: the path checked must not be empty or end with a branch
2730 static int check_path_branches(int opcnt, int magic)
2732 struct parsed_op *po;
2735 for (i = 0; i < opcnt; i++) {
2737 if (po->cc_scratch != magic)
2740 if (po->flags & OPF_JMP) {
2741 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
2744 if (po->btj != NULL) {
2745 for (j = 0; j < po->btj->count; j++) {
2746 check_i(po, po->btj->d[j].bt_i);
2747 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
2752 check_i(po, po->bt_i);
2753 if (ops[po->bt_i].cc_scratch != magic)
2755 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
2763 // scan for multiple pushes for given pop
2764 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
2767 int reg = ops[pop_i].operand[0].reg;
2768 struct parsed_op *po;
2769 struct label_ref *lr;
2772 ops[i].cc_scratch = magic;
2776 if (g_labels[i] != NULL) {
2777 lr = &g_label_refs[i];
2778 for (; lr != NULL; lr = lr->next) {
2779 check_i(&ops[i], lr->i);
2780 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
2784 if (i > 0 && LAST_OP(i - 1))
2792 if (ops[i].cc_scratch == magic)
2794 ops[i].cc_scratch = magic;
2797 if (po->op == OP_CALL)
2799 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
2802 if (po->op == OP_PUSH)
2804 if (po->datap != NULL)
2806 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2807 // leave this case for reg save/restore handlers
2811 po->flags |= OPF_PPUSH | OPF_DONE;
2812 po->datap = &ops[pop_i];
2821 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
2823 int magic = i + opcnt * 14;
2826 ret = scan_pushes_for_pop_r(i, magic, i, 1);
2828 ret = check_path_branches(opcnt, magic);
2830 ops[i].flags |= OPF_PPUSH | OPF_DONE;
2831 *regmask_pp |= 1 << ops[i].operand[0].reg;
2832 scan_pushes_for_pop_r(i, magic + 1, i, 0);
2837 static void scan_propagate_df(int i, int opcnt)
2839 struct parsed_op *po = &ops[i];
2842 for (; i < opcnt; i++) {
2844 if (po->flags & OPF_DF)
2845 return; // already resolved
2846 po->flags |= OPF_DF;
2848 if (po->op == OP_CALL)
2849 ferr(po, "call with DF set?\n");
2851 if (po->flags & OPF_JMP) {
2852 if (po->btj != NULL) {
2854 for (j = 0; j < po->btj->count; j++) {
2855 check_i(po, po->btj->d[j].bt_i);
2856 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
2861 if (po->flags & OPF_RMD)
2863 check_i(po, po->bt_i);
2864 if (po->flags & OPF_CJMP)
2865 scan_propagate_df(po->bt_i, opcnt);
2871 if (po->flags & OPF_TAIL)
2874 if (po->op == OP_CLD) {
2875 po->flags |= OPF_RMD | OPF_DONE;
2880 ferr(po, "missing DF clear?\n");
2883 // is operand 'opr' referenced by parsed_op 'po'?
2884 static int is_opr_referenced(const struct parsed_opr *opr,
2885 const struct parsed_op *po)
2889 if (opr->type == OPT_REG) {
2890 mask = po->regmask_dst | po->regmask_src;
2891 if (po->op == OP_CALL)
2892 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
2893 if ((1 << opr->reg) & mask)
2899 for (i = 0; i < po->operand_cnt; i++)
2900 if (IS(po->operand[0].name, opr->name))
2906 // is operand 'opr' read by parsed_op 'po'?
2907 static int is_opr_read(const struct parsed_opr *opr,
2908 const struct parsed_op *po)
2910 if (opr->type == OPT_REG) {
2911 if (po->regmask_src & (1 << opr->reg))
2921 // is operand 'opr' modified by parsed_op 'po'?
2922 static int is_opr_modified(const struct parsed_opr *opr,
2923 const struct parsed_op *po)
2927 if (opr->type == OPT_REG) {
2928 if (po->op == OP_CALL) {
2929 mask = po->regmask_dst;
2930 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
2931 if (mask & (1 << opr->reg))
2937 if (po->regmask_dst & (1 << opr->reg))
2943 return IS(po->operand[0].name, opr->name);
2946 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
2947 static int is_any_opr_modified(const struct parsed_op *po_test,
2948 const struct parsed_op *po, int c_mode)
2953 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
2956 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
2959 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
2962 // in reality, it can wreck any register, but in decompiled C
2963 // version it can only overwrite eax or edx:eax
2964 mask = (1 << xAX) | (1 << xDX);
2968 if (po->op == OP_CALL
2969 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
2972 for (i = 0; i < po_test->operand_cnt; i++)
2973 if (IS(po_test->operand[i].name, po->operand[0].name))
2979 // scan for any po_test operand modification in range given
2980 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
2983 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
2986 for (; i < opcnt; i++) {
2987 if (is_any_opr_modified(po_test, &ops[i], c_mode))
2994 // scan for po_test operand[0] modification in range given
2995 static int scan_for_mod_opr0(struct parsed_op *po_test,
2998 for (; i < opcnt; i++) {
2999 if (is_opr_modified(&po_test->operand[0], &ops[i]))
3006 static int scan_for_flag_set(int i, int magic, int *branched,
3007 int *setters, int *setter_cnt)
3009 struct label_ref *lr;
3013 if (ops[i].cc_scratch == magic) {
3014 // is this a problem?
3015 //ferr(&ops[i], "%s looped\n", __func__);
3018 ops[i].cc_scratch = magic;
3020 if (g_labels[i] != NULL) {
3023 lr = &g_label_refs[i];
3024 for (; lr->next; lr = lr->next) {
3025 check_i(&ops[i], lr->i);
3026 ret = scan_for_flag_set(lr->i, magic,
3027 branched, setters, setter_cnt);
3032 check_i(&ops[i], lr->i);
3033 if (i > 0 && LAST_OP(i - 1)) {
3037 ret = scan_for_flag_set(lr->i, magic,
3038 branched, setters, setter_cnt);
3044 if (ops[i].flags & OPF_FLAGS) {
3045 setters[*setter_cnt] = i;
3050 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3057 // scan back for cdq, if anything modifies edx, fail
3058 static int scan_for_cdq_edx(int i)
3061 if (g_labels[i] != NULL) {
3062 if (g_label_refs[i].next != NULL)
3064 if (i > 0 && LAST_OP(i - 1)) {
3065 i = g_label_refs[i].i;
3072 if (ops[i].op == OP_CDQ)
3075 if (ops[i].regmask_dst & (1 << xDX))
3082 static int scan_for_reg_clear(int i, int reg)
3085 if (g_labels[i] != NULL) {
3086 if (g_label_refs[i].next != NULL)
3088 if (i > 0 && LAST_OP(i - 1)) {
3089 i = g_label_refs[i].i;
3096 if (ops[i].op == OP_XOR
3097 && ops[i].operand[0].lmod == OPLM_DWORD
3098 && ops[i].operand[0].reg == ops[i].operand[1].reg
3099 && ops[i].operand[0].reg == reg)
3102 if (ops[i].regmask_dst & (1 << reg))
3109 static void patch_esp_adjust(struct parsed_op *po, int adj)
3111 ferr_assert(po, po->op == OP_ADD);
3112 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3113 ferr_assert(po, po->operand[1].type == OPT_CONST);
3115 // this is a bit of a hack, but deals with use of
3116 // single adj for multiple calls
3117 po->operand[1].val -= adj;
3118 po->flags |= OPF_RMD;
3119 if (po->operand[1].val == 0)
3120 po->flags |= OPF_DONE;
3121 ferr_assert(po, (int)po->operand[1].val >= 0);
3124 // scan for positive, constant esp adjust
3125 // multipath case is preliminary
3126 static int scan_for_esp_adjust(int i, int opcnt,
3127 int adj_expect, int *adj, int *is_multipath, int do_update)
3129 int adj_expect_unknown = 0;
3130 struct parsed_op *po;
3134 *adj = *is_multipath = 0;
3135 if (adj_expect < 0) {
3136 adj_expect_unknown = 1;
3137 adj_expect = 32 * 4; // enough?
3140 for (; i < opcnt && *adj < adj_expect; i++) {
3141 if (g_labels[i] != NULL)
3145 if (po->flags & OPF_DONE)
3148 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3149 if (po->operand[1].type != OPT_CONST)
3150 ferr(&ops[i], "non-const esp adjust?\n");
3151 *adj += po->operand[1].val;
3153 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3156 patch_esp_adjust(po, adj_expect);
3158 po->flags |= OPF_RMD;
3162 else if (po->op == OP_PUSH) {
3163 //if (first_pop == -1)
3164 // first_pop = -2; // none
3165 *adj -= lmod_bytes(po, po->operand[0].lmod);
3167 else if (po->op == OP_POP) {
3168 if (!(po->flags & OPF_DONE)) {
3169 // seems like msvc only uses 'pop ecx' for stack realignment..
3170 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3172 if (first_pop == -1 && *adj >= 0)
3175 if (do_update && *adj >= 0) {
3176 po->flags |= OPF_RMD;
3178 po->flags |= OPF_DONE | OPF_NOREGS;
3181 *adj += lmod_bytes(po, po->operand[0].lmod);
3182 if (*adj > adj_best)
3185 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3186 if (po->op == OP_JMP && po->btj == NULL) {
3192 if (po->op != OP_CALL)
3194 if (po->operand[0].type != OPT_LABEL)
3196 if (po->pp != NULL && po->pp->is_stdcall)
3198 if (adj_expect_unknown && first_pop >= 0)
3200 // assume it's another cdecl call
3204 if (first_pop >= 0) {
3205 // probably only 'pop ecx' was used
3213 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3215 struct parsed_op *po;
3219 ferr(ops, "%s: followed bad branch?\n", __func__);
3221 for (; i < opcnt; i++) {
3223 if (po->cc_scratch == magic)
3225 po->cc_scratch = magic;
3228 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3229 if (po->btj != NULL) {
3231 for (j = 0; j < po->btj->count; j++)
3232 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3236 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3237 if (!(po->flags & OPF_CJMP))
3240 if (po->flags & OPF_TAIL)
3245 static const struct parsed_proto *try_recover_pp(
3246 struct parsed_op *po, const struct parsed_opr *opr, int *search_instead)
3248 const struct parsed_proto *pp = NULL;
3252 // maybe an arg of g_func?
3253 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3255 char ofs_reg[16] = { 0, };
3256 int arg, arg_s, arg_i;
3263 parse_stack_access(po, opr->name, ofs_reg,
3264 &offset, &stack_ra, NULL, 0);
3265 if (ofs_reg[0] != 0)
3266 ferr(po, "offset reg on arg access?\n");
3267 if (offset <= stack_ra) {
3268 // search who set the stack var instead
3269 if (search_instead != NULL)
3270 *search_instead = 1;
3274 arg_i = (offset - stack_ra - 4) / 4;
3275 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3276 if (g_func_pp->arg[arg].reg != NULL)
3282 if (arg == g_func_pp->argc)
3283 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3285 pp = g_func_pp->arg[arg].fptr;
3287 ferr(po, "icall sa: arg%d is not a fptr?\n", arg + 1);
3288 check_func_pp(po, pp, "icall arg");
3290 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3292 p = strchr(opr->name + 1, '[');
3293 memcpy(buf, opr->name, p - opr->name);
3294 buf[p - opr->name] = 0;
3295 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3297 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3298 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3301 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3304 check_func_pp(po, pp, "reg-fptr ref");
3310 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3311 int magic, const struct parsed_proto **pp_found, int *pp_i,
3314 const struct parsed_proto *pp = NULL;
3315 struct parsed_op *po;
3316 struct label_ref *lr;
3318 ops[i].cc_scratch = magic;
3321 if (g_labels[i] != NULL) {
3322 lr = &g_label_refs[i];
3323 for (; lr != NULL; lr = lr->next) {
3324 check_i(&ops[i], lr->i);
3325 scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3327 if (i > 0 && LAST_OP(i - 1))
3335 if (ops[i].cc_scratch == magic)
3337 ops[i].cc_scratch = magic;
3339 if (!(ops[i].flags & OPF_DATA))
3341 if (!is_opr_modified(opr, &ops[i]))
3343 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3344 // most probably trashed by some processing
3349 opr = &ops[i].operand[1];
3350 if (opr->type != OPT_REG)
3354 po = (i >= 0) ? &ops[i] : ops;
3357 // reached the top - can only be an arg-reg
3358 if (opr->type != OPT_REG || g_func_pp == NULL)
3361 for (i = 0; i < g_func_pp->argc; i++) {
3362 if (g_func_pp->arg[i].reg == NULL)
3364 if (IS(opr->name, g_func_pp->arg[i].reg))
3367 if (i == g_func_pp->argc)
3369 pp = g_func_pp->arg[i].fptr;
3371 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3372 i + 1, g_func_pp->arg[i].reg);
3373 check_func_pp(po, pp, "icall reg-arg");
3376 pp = try_recover_pp(po, opr, NULL);
3378 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3379 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3380 || (*pp_found)->is_stdcall != pp->is_stdcall
3381 || (*pp_found)->is_fptr != pp->is_fptr
3382 || (*pp_found)->argc != pp->argc
3383 || (*pp_found)->argc_reg != pp->argc_reg
3384 || (*pp_found)->argc_stack != pp->argc_stack)
3386 ferr(po, "icall: parsed_proto mismatch\n");
3396 static void add_label_ref(struct label_ref *lr, int op_i)
3398 struct label_ref *lr_new;
3405 lr_new = calloc(1, sizeof(*lr_new));
3407 lr_new->next = lr->next;
3411 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3413 struct parsed_op *po = &ops[i];
3414 struct parsed_data *pd;
3415 char label[NAMELEN], *p;
3418 p = strchr(po->operand[0].name, '[');
3422 len = p - po->operand[0].name;
3423 strncpy(label, po->operand[0].name, len);
3426 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3427 if (IS(g_func_pd[j].label, label)) {
3433 //ferr(po, "label '%s' not parsed?\n", label);
3436 if (pd->type != OPT_OFFSET)
3437 ferr(po, "label '%s' with non-offset data?\n", label);
3439 // find all labels, link
3440 for (j = 0; j < pd->count; j++) {
3441 for (l = 0; l < opcnt; l++) {
3442 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3443 add_label_ref(&g_label_refs[l], i);
3453 static void clear_labels(int count)
3457 for (i = 0; i < count; i++) {
3458 if (g_labels[i] != NULL) {
3465 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3470 for (i = 0; i < pp->argc; i++) {
3471 if (pp->arg[i].reg != NULL) {
3472 reg = char_array_i(regs_r32,
3473 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3475 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3476 pp->arg[i].reg, pp->name);
3477 regmask |= 1 << reg;
3484 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3489 if (pp->has_retreg) {
3490 for (i = 0; i < pp->argc; i++) {
3491 if (pp->arg[i].type.is_retreg) {
3492 reg = char_array_i(regs_r32,
3493 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3494 ferr_assert(ops, reg >= 0);
3495 regmask |= 1 << reg;
3500 if (strstr(pp->ret_type.name, "int64"))
3501 return regmask | (1 << xAX) | (1 << xDX);
3502 if (IS(pp->ret_type.name, "float")
3503 || IS(pp->ret_type.name, "double"))
3505 return regmask | mxST0;
3507 if (strcasecmp(pp->ret_type.name, "void") == 0)
3510 return regmask | mxAX;
3513 static void resolve_branches_parse_calls(int opcnt)
3515 static const struct {
3519 unsigned int regmask_src;
3520 unsigned int regmask_dst;
3522 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3524 const struct parsed_proto *pp_c;
3525 struct parsed_proto *pp;
3526 struct parsed_data *pd;
3527 struct parsed_op *po;
3528 const char *tmpname;
3532 for (i = 0; i < opcnt; i++)
3538 if (po->datap != NULL) {
3539 pp = calloc(1, sizeof(*pp));
3540 my_assert_not(pp, NULL);
3542 ret = parse_protostr(po->datap, pp);
3544 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3550 if (po->op == OP_CALL) {
3555 else if (po->operand[0].type == OPT_LABEL)
3557 tmpname = opr_name(po, 0);
3558 if (IS_START(tmpname, "loc_"))
3559 ferr(po, "call to loc_*\n");
3561 // convert some calls to pseudo-ops
3562 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3563 if (!IS(tmpname, pseudo_ops[l].name))
3566 po->op = pseudo_ops[l].op;
3567 po->operand_cnt = 0;
3568 po->regmask_src = pseudo_ops[l].regmask_src;
3569 po->regmask_dst = pseudo_ops[l].regmask_dst;
3570 po->flags = pseudo_ops[l].flags;
3571 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3574 if (l < ARRAY_SIZE(pseudo_ops))
3577 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3578 if (!g_header_mode && pp_c == NULL)
3579 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3582 pp = proto_clone(pp_c);
3583 my_assert_not(pp, NULL);
3589 check_func_pp(po, pp, "fptr var call");
3590 if (pp->is_noreturn)
3591 po->flags |= OPF_TAIL;
3597 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3600 if (po->operand[0].type == OPT_REGMEM) {
3601 pd = try_resolve_jumptab(i, opcnt);
3609 for (l = 0; l < opcnt; l++) {
3610 if (g_labels[l] != NULL
3611 && IS(po->operand[0].name, g_labels[l]))
3613 if (l == i + 1 && po->op == OP_JMP) {
3614 // yet another alignment type..
3615 po->flags |= OPF_RMD|OPF_DONE;
3618 add_label_ref(&g_label_refs[l], i);
3624 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3627 if (po->operand[0].type == OPT_LABEL)
3631 ferr(po, "unhandled branch\n");
3635 po->flags |= OPF_TAIL;
3636 if (i > 0 && ops[i - 1].op == OP_POP)
3637 po->flags |= OPF_ATAIL;
3642 static void scan_prologue_epilogue(int opcnt)
3644 int ecx_push = 0, esp_sub = 0;
3648 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
3649 && ops[1].op == OP_MOV
3650 && IS(opr_name(&ops[1], 0), "ebp")
3651 && IS(opr_name(&ops[1], 1), "esp"))
3654 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3655 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3658 if (ops[2].op == OP_SUB && IS(opr_name(&ops[2], 0), "esp")) {
3659 g_stack_fsz = opr_const(&ops[2], 1);
3660 ops[2].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3664 // another way msvc builds stack frame..
3666 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3668 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3672 // and another way..
3673 if (i == 2 && ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3674 && ops[i].operand[1].type == OPT_CONST
3675 && ops[i + 1].op == OP_CALL
3676 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3678 g_stack_fsz += ops[i].operand[1].val;
3679 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3681 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3688 for (; i < opcnt; i++)
3689 if (ops[i].flags & OPF_TAIL)
3692 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3693 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3699 if ((ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
3700 || ops[j].op == OP_LEAVE)
3702 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3704 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
3705 && ops[i].pp->is_noreturn)
3707 // on noreturn, msvc sometimes cleans stack, sometimes not
3712 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3713 ferr(&ops[j], "'pop ebp' expected\n");
3715 if (g_stack_fsz != 0) {
3716 if (ops[j].op == OP_LEAVE)
3718 else if (ops[j].op == OP_POP
3719 && ops[j - 1].op == OP_MOV
3720 && IS(opr_name(&ops[j - 1], 0), "esp")
3721 && IS(opr_name(&ops[j - 1], 1), "ebp"))
3723 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3726 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3728 ferr(&ops[j], "esp restore expected\n");
3731 if (ecx_push && j >= 0 && ops[j].op == OP_POP
3732 && IS(opr_name(&ops[j], 0), "ecx"))
3734 ferr(&ops[j], "unexpected ecx pop\n");
3740 } while (i < opcnt);
3743 ferr(ops, "missing ebp epilogue\n");
3749 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3750 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3756 for (; i < opcnt; i++) {
3757 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
3759 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
3760 && ops[i].operand[1].type == OPT_CONST)
3762 g_stack_fsz = ops[i].operand[1].val;
3763 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3769 if (ecx_push && !esp_sub) {
3770 // could actually be args for a call..
3771 for (; i < opcnt; i++)
3772 if (ops[i].op != OP_PUSH)
3775 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
3776 const struct parsed_proto *pp;
3777 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
3778 j = pp ? pp->argc_stack : 0;
3779 while (i > 0 && j > 0) {
3781 if (ops[i].op == OP_PUSH) {
3782 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
3787 ferr(&ops[i], "unhandled prologue\n");
3790 i = g_stack_fsz = ecx_push = 0;
3791 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3792 if (!(ops[i].flags & OPF_RMD))
3802 if (ecx_push || esp_sub)
3808 for (; i < opcnt; i++)
3809 if (ops[i].flags & OPF_TAIL)
3812 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3813 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3820 for (l = 0; l < ecx_push; l++) {
3821 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
3823 else if (ops[j].op == OP_ADD
3824 && IS(opr_name(&ops[j], 0), "esp")
3825 && ops[j].operand[1].type == OPT_CONST)
3828 l += ops[j].operand[1].val / 4 - 1;
3831 ferr(&ops[j], "'pop ecx' expected\n");
3833 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3837 ferr(&ops[j], "epilogue scan failed\n");
3843 if (ops[j].op != OP_ADD
3844 || !IS(opr_name(&ops[j], 0), "esp")
3845 || ops[j].operand[1].type != OPT_CONST
3846 || ops[j].operand[1].val != g_stack_fsz)
3847 ferr(&ops[j], "'add esp' expected\n");
3849 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3850 ops[j].operand[1].val = 0; // hack for stack arg scanner
3855 } while (i < opcnt);
3858 ferr(ops, "missing esp epilogue\n");
3862 // find an instruction that changed opr before i op
3863 // *op_i must be set to -1 by the caller
3864 // *is_caller is set to 1 if one source is determined to be g_func arg
3865 // returns 1 if found, *op_i is then set to origin
3866 // returns -1 if multiple origins are found
3867 static int resolve_origin(int i, const struct parsed_opr *opr,
3868 int magic, int *op_i, int *is_caller)
3870 struct label_ref *lr;
3873 if (ops[i].cc_scratch == magic)
3875 ops[i].cc_scratch = magic;
3878 if (g_labels[i] != NULL) {
3879 lr = &g_label_refs[i];
3880 for (; lr != NULL; lr = lr->next) {
3881 check_i(&ops[i], lr->i);
3882 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
3884 if (i > 0 && LAST_OP(i - 1))
3890 if (is_caller != NULL)
3895 if (ops[i].cc_scratch == magic)
3897 ops[i].cc_scratch = magic;
3899 if (!(ops[i].flags & OPF_DATA))
3901 if (!is_opr_modified(opr, &ops[i]))
3908 // XXX: could check if the other op does the same
3917 // find an instruction that previously referenced opr
3918 // if multiple results are found - fail
3919 // *op_i must be set to -1 by the caller
3920 // returns 1 if found, *op_i is then set to referencer insn
3921 static int resolve_last_ref(int i, const struct parsed_opr *opr,
3922 int magic, int *op_i)
3924 struct label_ref *lr;
3927 if (ops[i].cc_scratch == magic)
3929 ops[i].cc_scratch = magic;
3932 if (g_labels[i] != NULL) {
3933 lr = &g_label_refs[i];
3934 for (; lr != NULL; lr = lr->next) {
3935 check_i(&ops[i], lr->i);
3936 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
3938 if (i > 0 && LAST_OP(i - 1))
3946 if (ops[i].cc_scratch == magic)
3948 ops[i].cc_scratch = magic;
3950 if (!is_opr_referenced(opr, &ops[i]))
3961 // find next instruction that reads opr
3962 // *op_i must be set to -1 by the caller
3963 // on return, *op_i is set to first referencer insn
3964 // returns 1 if exactly 1 referencer is found
3965 static int find_next_read(int i, int opcnt,
3966 const struct parsed_opr *opr, int magic, int *op_i)
3968 struct parsed_op *po;
3971 for (; i < opcnt; i++)
3973 if (ops[i].cc_scratch == magic)
3975 ops[i].cc_scratch = magic;
3978 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3979 if (po->btj != NULL) {
3981 for (j = 0; j < po->btj->count; j++) {
3982 check_i(po, po->btj->d[j].bt_i);
3983 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
3989 if (po->flags & OPF_RMD)
3991 check_i(po, po->bt_i);
3992 if (po->flags & OPF_CJMP) {
3993 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4002 if (!is_opr_read(opr, po)) {
4003 if (is_opr_modified(opr, po)
4004 && (po->op == OP_CALL
4005 || ((po->flags & OPF_DATA)
4006 && po->operand[0].lmod == OPLM_DWORD)))
4011 if (po->flags & OPF_TAIL)
4026 static int try_resolve_const(int i, const struct parsed_opr *opr,
4027 int magic, unsigned int *val)
4032 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4035 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4038 *val = ops[i].operand[1].val;
4045 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4046 int *pp_i, int *multi_src)
4048 const struct parsed_proto *pp = NULL;
4049 int search_advice = 0;
4059 switch (ops[i].operand[0].type) {
4061 // try to resolve struct member calls
4062 ret = sscanf(ops[i].operand[0].name, "%3s+%x%n",
4063 s_reg, &offset, &len);
4064 if (ret == 2 && len == strlen(ops[i].operand[0].name))
4066 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4068 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, reg);
4070 ret = resolve_origin(i, &opr, i + opcnt * 19, &j, NULL);
4073 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4074 && ops[j].operand[0].lmod == OPLM_DWORD
4075 && ops[j].pp == NULL) // no hint
4077 // allow one simple dereference (directx)
4078 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4079 ops[j].operand[1].name);
4082 struct parsed_opr opr2 = OPR_INIT(OPT_REG, OPLM_DWORD, reg);
4084 ret = resolve_origin(j, &opr2, j + opcnt * 19, &k, NULL);
4089 if (ops[j].op != OP_MOV)
4091 if (ops[j].operand[0].lmod != OPLM_DWORD)
4093 if (ops[j].pp != NULL) {
4097 else if (ops[j].operand[1].type == OPT_REGMEM) {
4098 // allow 'hello[ecx]' - assume array of same type items
4099 ret = sscanf(ops[j].operand[1].name, "%[^[][e%2s]",
4103 pp = proto_parse(g_fhdr, name, g_quiet_pp);
4105 else if (ops[j].operand[1].type == OPT_LABEL)
4106 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4111 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4115 pp = proto_lookup_struct(g_fhdr, pp->type.name, offset);
4122 pp = try_recover_pp(&ops[i], &ops[i].operand[0], &search_advice);
4127 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4135 static struct parsed_proto *process_call_early(int i, int opcnt,
4138 struct parsed_op *po = &ops[i];
4139 struct parsed_proto *pp;
4145 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4149 // look for and make use of esp adjust
4151 if (!pp->is_stdcall && pp->argc_stack > 0)
4152 ret = scan_for_esp_adjust(i + 1, opcnt,
4153 pp->argc_stack * 4, &adj, &multipath, 0);
4155 if (pp->argc_stack > adj / 4)
4159 if (ops[ret].op == OP_POP) {
4160 for (j = 1; j < adj / 4; j++) {
4161 if (ops[ret + j].op != OP_POP
4162 || ops[ret + j].operand[0].reg != xCX)
4174 static struct parsed_proto *process_call(int i, int opcnt)
4176 struct parsed_op *po = &ops[i];
4177 const struct parsed_proto *pp_c;
4178 struct parsed_proto *pp;
4179 const char *tmpname;
4180 int call_i = -1, ref_i = -1;
4181 int adj = 0, multipath = 0;
4184 tmpname = opr_name(po, 0);
4189 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4191 if (!pp_c->is_func && !pp_c->is_fptr)
4192 ferr(po, "call to non-func: %s\n", pp_c->name);
4193 pp = proto_clone(pp_c);
4194 my_assert_not(pp, NULL);
4196 // not resolved just to single func
4199 switch (po->operand[0].type) {
4201 // we resolved this call and no longer need the register
4202 po->regmask_src &= ~(1 << po->operand[0].reg);
4204 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4205 && ops[call_i].operand[1].type == OPT_LABEL)
4207 // no other source users?
4208 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4210 if (ret == 1 && call_i == ref_i) {
4211 // and nothing uses it after us?
4213 find_next_read(i + 1, opcnt, &po->operand[0],
4214 i + opcnt * 11, &ref_i);
4216 // then also don't need the source mov
4217 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4229 pp = calloc(1, sizeof(*pp));
4230 my_assert_not(pp, NULL);
4233 ret = scan_for_esp_adjust(i + 1, opcnt,
4234 -1, &adj, &multipath, 0);
4235 if (ret < 0 || adj < 0) {
4236 if (!g_allow_regfunc)
4237 ferr(po, "non-__cdecl indirect call unhandled yet\n");
4238 pp->is_unresolved = 1;
4242 if (adj > ARRAY_SIZE(pp->arg))
4243 ferr(po, "esp adjust too large: %d\n", adj);
4244 pp->ret_type.name = strdup("int");
4245 pp->argc = pp->argc_stack = adj;
4246 for (arg = 0; arg < pp->argc; arg++)
4247 pp->arg[arg].type.name = strdup("int");
4252 // look for and make use of esp adjust
4255 if (!pp->is_stdcall && pp->argc_stack > 0) {
4256 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
4257 ret = scan_for_esp_adjust(i + 1, opcnt,
4258 adj_expect, &adj, &multipath, 0);
4261 if (pp->is_vararg) {
4262 if (adj / 4 < pp->argc_stack) {
4263 fnote(po, "(this call)\n");
4264 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
4265 adj, pp->argc_stack * 4);
4267 // modify pp to make it have varargs as normal args
4269 pp->argc += adj / 4 - pp->argc_stack;
4270 for (; arg < pp->argc; arg++) {
4271 pp->arg[arg].type.name = strdup("int");
4274 if (pp->argc > ARRAY_SIZE(pp->arg))
4275 ferr(po, "too many args for '%s'\n", tmpname);
4277 if (pp->argc_stack > adj / 4) {
4278 fnote(po, "(this call)\n");
4279 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
4280 tmpname, pp->argc_stack * 4, adj);
4283 scan_for_esp_adjust(i + 1, opcnt,
4284 pp->argc_stack * 4, &adj, &multipath, 1);
4286 else if (pp->is_vararg)
4287 ferr(po, "missing esp_adjust for vararg func '%s'\n",
4293 static int collect_call_args_early(struct parsed_op *po, int i,
4294 struct parsed_proto *pp, int *regmask)
4299 for (arg = 0; arg < pp->argc; arg++)
4300 if (pp->arg[arg].reg == NULL)
4303 // first see if it can be easily done
4304 for (j = i; j > 0 && arg < pp->argc; )
4306 if (g_labels[j] != NULL)
4310 if (ops[j].op == OP_CALL)
4312 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP)
4314 else if (ops[j].op == OP_POP)
4316 else if (ops[j].flags & OPF_CJMP)
4318 else if (ops[j].op == OP_PUSH) {
4319 if (ops[j].flags & (OPF_FARG|OPF_FARGNR))
4321 ret = scan_for_mod(&ops[j], j + 1, i, 1);
4325 if (pp->arg[arg].type.is_va_list)
4329 for (arg++; arg < pp->argc; arg++)
4330 if (pp->arg[arg].reg == NULL)
4339 for (arg = 0; arg < pp->argc; arg++)
4340 if (pp->arg[arg].reg == NULL)
4343 for (j = i; j > 0 && arg < pp->argc; )
4347 if (ops[j].op == OP_PUSH)
4349 ops[j].p_argnext = -1;
4350 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
4351 pp->arg[arg].datap = &ops[j];
4353 if (ops[j].operand[0].type == OPT_REG)
4354 *regmask |= 1 << ops[j].operand[0].reg;
4356 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4357 ops[j].flags &= ~OPF_RSAVE;
4360 for (arg++; arg < pp->argc; arg++)
4361 if (pp->arg[arg].reg == NULL)
4369 static int collect_call_args_r(struct parsed_op *po, int i,
4370 struct parsed_proto *pp, int *regmask, int *save_arg_vars,
4371 int *arg_grp, int arg, int magic, int need_op_saving, int may_reuse)
4373 struct parsed_proto *pp_tmp;
4374 struct parsed_op *po_tmp;
4375 struct label_ref *lr;
4376 int need_to_save_current;
4377 int arg_grp_current = 0;
4378 int save_args_seen = 0;
4386 ferr(po, "dead label encountered\n");
4390 for (; arg < pp->argc; arg++)
4391 if (pp->arg[arg].reg == NULL)
4393 magic = (magic & 0xffffff) | (arg << 24);
4395 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
4397 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
4398 if (ops[j].cc_scratch != magic) {
4399 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
4403 // ok: have already been here
4406 ops[j].cc_scratch = magic;
4408 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
4409 lr = &g_label_refs[j];
4410 if (lr->next != NULL)
4412 for (; lr->next; lr = lr->next) {
4413 check_i(&ops[j], lr->i);
4414 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4416 ret = collect_call_args_r(po, lr->i, pp, regmask, save_arg_vars,
4417 arg_grp, arg, magic, need_op_saving, may_reuse);
4422 check_i(&ops[j], lr->i);
4423 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4425 if (j > 0 && LAST_OP(j - 1)) {
4426 // follow last branch in reverse
4431 ret = collect_call_args_r(po, lr->i, pp, regmask, save_arg_vars,
4432 arg_grp, arg, magic, need_op_saving, may_reuse);
4438 if (ops[j].op == OP_CALL)
4440 if (pp->is_unresolved)
4445 ferr(po, "arg collect hit unparsed call '%s'\n",
4446 ops[j].operand[0].name);
4447 if (may_reuse && pp_tmp->argc_stack > 0)
4448 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
4449 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
4451 // esp adjust of 0 means we collected it before
4452 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
4453 && (ops[j].operand[1].type != OPT_CONST
4454 || ops[j].operand[1].val != 0))
4456 if (pp->is_unresolved)
4459 fnote(po, "(this call)\n");
4460 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
4461 arg, pp->argc, ops[j].operand[1].val);
4463 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
4465 if (pp->is_unresolved)
4468 fnote(po, "(this call)\n");
4469 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
4471 else if (ops[j].flags & OPF_CJMP)
4473 if (pp->is_unresolved)
4478 else if (ops[j].op == OP_PUSH
4479 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
4481 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
4484 ops[j].p_argnext = -1;
4485 po_tmp = pp->arg[arg].datap;
4487 ops[j].p_argnext = po_tmp - ops;
4488 pp->arg[arg].datap = &ops[j];
4490 need_to_save_current = 0;
4493 if (ops[j].operand[0].type == OPT_REG)
4494 reg = ops[j].operand[0].reg;
4496 if (!need_op_saving) {
4497 ret = scan_for_mod(&ops[j], j + 1, i, 1);
4498 need_to_save_current = (ret >= 0);
4500 if (need_op_saving || need_to_save_current) {
4501 // mark this push as one that needs operand saving
4502 ops[j].flags &= ~OPF_RMD;
4503 if (ops[j].p_argnum == 0) {
4504 ops[j].p_argnum = arg + 1;
4505 save_args |= 1 << arg;
4507 else if (ops[j].p_argnum < arg + 1) {
4508 // XXX: might kill valid var..
4509 //*save_arg_vars &= ~(1 << (ops[j].p_argnum - 1));
4510 ops[j].p_argnum = arg + 1;
4511 save_args |= 1 << arg;
4514 if (save_args_seen & (1 << (ops[j].p_argnum - 1))) {
4517 if (arg_grp_current >= MAX_ARG_GRP)
4518 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
4519 ops[j].p_argnum, pp->name);
4522 else if (ops[j].p_argnum == 0)
4523 ops[j].flags |= OPF_RMD;
4525 // some PUSHes are reused by different calls on other branches,
4526 // but that can't happen if we didn't branch, so they
4527 // can be removed from future searches (handles nested calls)
4529 ops[j].flags |= OPF_FARGNR;
4531 ops[j].flags |= OPF_FARG;
4532 ops[j].flags &= ~OPF_RSAVE;
4534 // check for __VALIST
4535 if (!pp->is_unresolved && g_func_pp != NULL
4536 && pp->arg[arg].type.is_va_list)
4539 ret = resolve_origin(j, &ops[j].operand[0],
4540 magic + 1, &k, NULL);
4541 if (ret == 1 && k >= 0)
4543 if (ops[k].op == OP_LEA) {
4544 if (!g_func_pp->is_vararg)
4545 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
4548 snprintf(buf, sizeof(buf), "arg_%X",
4549 g_func_pp->argc_stack * 4);
4550 if (strstr(ops[k].operand[1].name, buf)
4551 || strstr(ops[k].operand[1].name, "arglist"))
4553 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
4554 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
4555 save_args &= ~(1 << arg);
4559 ferr(&ops[k], "va_list arg detection failed\n");
4561 // check for va_list from g_func_pp arg too
4562 else if (ops[k].op == OP_MOV
4563 && is_stack_access(&ops[k], &ops[k].operand[1]))
4565 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
4566 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
4568 ops[k].flags |= OPF_RMD | OPF_DONE;
4569 ops[j].flags |= OPF_RMD;
4570 ops[j].p_argpass = ret + 1;
4571 save_args &= ~(1 << arg);
4578 *save_arg_vars |= save_args;
4580 // tracking reg usage
4582 *regmask |= 1 << reg;
4585 if (!pp->is_unresolved) {
4587 for (; arg < pp->argc; arg++)
4588 if (pp->arg[arg].reg == NULL)
4591 magic = (magic & 0xffffff) | (arg << 24);
4594 if (ops[j].p_arggrp > arg_grp_current) {
4596 arg_grp_current = ops[j].p_arggrp;
4598 if (ops[j].p_argnum > 0)
4599 save_args_seen |= 1 << (ops[j].p_argnum - 1);
4602 if (arg < pp->argc) {
4603 ferr(po, "arg collect failed for '%s': %d/%d\n",
4604 pp->name, arg, pp->argc);
4608 if (arg_grp_current > *arg_grp)
4609 *arg_grp = arg_grp_current;
4614 static int collect_call_args(struct parsed_op *po, int i,
4615 struct parsed_proto *pp, int *regmask, int *save_arg_vars,
4618 // arg group is for cases when pushes for
4619 // multiple funcs are going on
4620 struct parsed_op *po_tmp;
4621 int save_arg_vars_current = 0;
4626 ret = collect_call_args_r(po, i, pp, regmask,
4627 &save_arg_vars_current, &arg_grp, 0, magic, 0, 0);
4632 // propagate arg_grp
4633 for (a = 0; a < pp->argc; a++) {
4634 if (pp->arg[a].reg != NULL)
4637 po_tmp = pp->arg[a].datap;
4638 while (po_tmp != NULL) {
4639 po_tmp->p_arggrp = arg_grp;
4640 if (po_tmp->p_argnext > 0)
4641 po_tmp = &ops[po_tmp->p_argnext];
4647 save_arg_vars[arg_grp] |= save_arg_vars_current;
4649 if (pp->is_unresolved) {
4651 pp->argc_stack += ret;
4652 for (a = 0; a < pp->argc; a++)
4653 if (pp->arg[a].type.name == NULL)
4654 pp->arg[a].type.name = strdup("int");
4660 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
4661 int regmask_now, int *regmask,
4662 int regmask_save_now, int *regmask_save,
4663 int *regmask_init, int regmask_arg)
4665 struct parsed_op *po;
4674 for (; i < opcnt; i++)
4677 if (cbits[i >> 3] & (1 << (i & 7)))
4679 cbits[i >> 3] |= (1 << (i & 7));
4681 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4682 if (po->flags & (OPF_RMD|OPF_DONE))
4684 if (po->btj != NULL) {
4685 for (j = 0; j < po->btj->count; j++) {
4686 check_i(po, po->btj->d[j].bt_i);
4687 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
4688 regmask_now, regmask, regmask_save_now, regmask_save,
4689 regmask_init, regmask_arg);
4694 check_i(po, po->bt_i);
4695 if (po->flags & OPF_CJMP)
4696 reg_use_pass(po->bt_i, opcnt, cbits,
4697 regmask_now, regmask, regmask_save_now, regmask_save,
4698 regmask_init, regmask_arg);
4704 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
4705 && !g_func_pp->is_userstack
4706 && po->operand[0].type == OPT_REG)
4708 reg = po->operand[0].reg;
4709 ferr_assert(po, reg >= 0);
4712 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
4713 if (regmask_now & (1 << reg)) {
4714 already_saved = regmask_save_now & (1 << reg);
4715 flags_set = OPF_RSAVE | OPF_DONE;
4718 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0);
4720 scan_for_pop(i + 1, opcnt, i + opcnt * 4, reg, 0, flags_set);
4723 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
4725 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
4730 ferr_assert(po, !already_saved);
4731 po->flags |= flags_set;
4733 if (regmask_now & (1 << reg)) {
4734 regmask_save_now |= (1 << reg);
4735 *regmask_save |= regmask_save_now;
4740 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
4741 reg = po->operand[0].reg;
4742 ferr_assert(po, reg >= 0);
4744 if (regmask_save_now & (1 << reg))
4745 regmask_save_now &= ~(1 << reg);
4747 regmask_now &= ~(1 << reg);
4750 else if (po->op == OP_CALL) {
4751 if ((po->regmask_dst & (1 << xAX))
4752 && !(po->regmask_dst & (1 << xDX)))
4754 if (po->flags & OPF_TAIL)
4755 // don't need eax, will do "return f();" or "f(); return;"
4756 po->regmask_dst &= ~(1 << xAX);
4758 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
4760 find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
4763 po->regmask_dst &= ~(1 << xAX);
4768 if (po->flags & OPF_NOREGS)
4771 if (po->flags & OPF_FPUSH) {
4772 if (regmask_now & mxST1)
4773 ferr(po, "TODO: FPUSH on active ST1\n");
4774 if (regmask_now & mxST0)
4775 po->flags |= OPF_FSHIFT;
4776 mask = mxST0 | mxST1;
4777 regmask_now = (regmask_now & ~mask) | ((regmask_now & mxST0) << 1);
4780 // if incomplete register is used, clear it on init to avoid
4781 // later use of uninitialized upper part in some situations
4782 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
4783 && po->operand[0].lmod != OPLM_DWORD)
4785 reg = po->operand[0].reg;
4786 ferr_assert(po, reg >= 0);
4788 if (!(regmask_now & (1 << reg)))
4789 *regmask_init |= 1 << reg;
4792 regmask_op = po->regmask_src | po->regmask_dst;
4794 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
4795 regmask_new &= ~(1 << xSP);
4796 if (g_bp_frame && !(po->flags & OPF_EBP_S))
4797 regmask_new &= ~(1 << xBP);
4799 if (regmask_new != 0)
4800 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
4802 if (regmask_op & (1 << xBP)) {
4803 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
4804 if (po->regmask_dst & (1 << xBP))
4805 // compiler decided to drop bp frame and use ebp as scratch
4806 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
4808 regmask_op &= ~(1 << xBP);
4812 regmask_now |= regmask_op;
4813 *regmask |= regmask_now;
4816 if (po->flags & OPF_FPOP) {
4817 mask = mxST0 | mxST1;
4818 if (!(regmask_now & mask))
4819 ferr(po, "float pop on empty stack?\n");
4820 if (regmask_now & mxST1)
4821 po->flags |= OPF_FSHIFT;
4822 regmask_now = (regmask_now & ~mask) | ((regmask_now & mxST1) >> 1);
4825 if (po->flags & OPF_TAIL) {
4826 if (regmask_now & (mxST0 | mxST1))
4827 ferr(po, "float regs on tail: %x\n", regmask_now);
4829 // there is support for "conditional tailcall", sort of
4830 if (!(po->flags & OPF_CC))
4836 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
4840 for (i = 0; i < pp->argc; i++)
4841 if (pp->arg[i].reg == NULL)
4845 memmove(&pp->arg[i + 1], &pp->arg[i],
4846 sizeof(pp->arg[0]) * pp->argc_stack);
4847 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
4848 pp->arg[i].reg = strdup(reg);
4849 pp->arg[i].type.name = strdup("int");
4854 static void output_std_flags(FILE *fout, struct parsed_op *po,
4855 int *pfomask, const char *dst_opr_text)
4857 if (*pfomask & (1 << PFO_Z)) {
4858 fprintf(fout, "\n cond_z = (%s%s == 0);",
4859 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
4860 *pfomask &= ~(1 << PFO_Z);
4862 if (*pfomask & (1 << PFO_S)) {
4863 fprintf(fout, "\n cond_s = (%s%s < 0);",
4864 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
4865 *pfomask &= ~(1 << PFO_S);
4870 OPP_FORCE_NORETURN = (1 << 0),
4871 OPP_SIMPLE_ARGS = (1 << 1),
4872 OPP_ALIGN = (1 << 2),
4875 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
4878 const char *cconv = "";
4880 if (pp->is_fastcall)
4881 cconv = "__fastcall ";
4882 else if (pp->is_stdcall && pp->argc_reg == 0)
4883 cconv = "__stdcall ";
4885 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
4887 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
4888 fprintf(fout, "noreturn ");
4891 static void output_pp(FILE *fout, const struct parsed_proto *pp,
4896 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
4900 output_pp_attrs(fout, pp, flags);
4903 fprintf(fout, "%s", pp->name);
4908 for (i = 0; i < pp->argc; i++) {
4910 fprintf(fout, ", ");
4911 if (pp->arg[i].fptr != NULL && !(flags & OPP_SIMPLE_ARGS)) {
4913 output_pp(fout, pp->arg[i].fptr, 0);
4915 else if (pp->arg[i].type.is_retreg) {
4916 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
4919 fprintf(fout, "%s", pp->arg[i].type.name);
4921 fprintf(fout, " a%d", i + 1);
4924 if (pp->is_vararg) {
4926 fprintf(fout, ", ");
4927 fprintf(fout, "...");
4932 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
4938 snprintf(buf1, sizeof(buf1), "%d", grp);
4939 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
4944 static void gen_x_cleanup(int opcnt);
4946 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
4948 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
4949 struct parsed_opr *last_arith_dst = NULL;
4950 char buf1[256], buf2[256], buf3[256], cast[64];
4951 struct parsed_proto *pp, *pp_tmp;
4952 struct parsed_data *pd;
4954 int save_arg_vars[MAX_ARG_GRP] = { 0, };
4955 unsigned char cbits[MAX_OPS / 8];
4956 const char *float_type;
4958 int need_tmp_var = 0;
4961 int label_pending = 0;
4962 int need_double = 0;
4963 int regmask_save = 0; // regs saved/restored in this func
4964 int regmask_arg; // regs from this function args (fastcall, etc)
4965 int regmask_ret; // regs needed on ret
4966 int regmask_now; // temp
4967 int regmask_init = 0; // regs that need zero initialization
4968 int regmask_pp = 0; // regs used in complex push-pop graph
4969 int regmask = 0; // used regs
4978 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
4979 g_stack_frame_used = 0;
4980 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
4981 regmask_init = g_regmask_init;
4983 g_func_pp = proto_parse(fhdr, funcn, 0);
4984 if (g_func_pp == NULL)
4985 ferr(ops, "proto_parse failed for '%s'\n", funcn);
4987 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
4988 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
4991 // - resolve all branches
4992 // - parse calls with labels
4993 resolve_branches_parse_calls(opcnt);
4996 // - handle ebp/esp frame, remove ops related to it
4997 scan_prologue_epilogue(opcnt);
5000 // - remove dead labels
5001 // - set regs needed at ret
5002 for (i = 0; i < opcnt; i++)
5004 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
5009 if (ops[i].op == OP_RET)
5010 ops[i].regmask_src |= regmask_ret;
5014 // - process trivial calls
5015 for (i = 0; i < opcnt; i++)
5018 if (po->flags & (OPF_RMD|OPF_DONE))
5021 if (po->op == OP_CALL)
5023 pp = process_call_early(i, opcnt, &j);
5025 if (!(po->flags & OPF_ATAIL))
5026 // since we know the args, try to collect them
5027 if (collect_call_args_early(po, i, pp, ®mask) != 0)
5033 // commit esp adjust
5034 if (ops[j].op != OP_POP)
5035 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5037 for (l = 0; l < pp->argc_stack; l++)
5038 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
5042 if (strstr(pp->ret_type.name, "int64"))
5045 po->flags |= OPF_DONE;
5051 // - process calls, stage 2
5052 // - handle some push/pop pairs
5053 // - scan for STD/CLD, propagate DF
5054 for (i = 0; i < opcnt; i++)
5057 if (po->flags & OPF_RMD)
5060 if (po->op == OP_CALL)
5062 if (!(po->flags & OPF_DONE)) {
5063 pp = process_call(i, opcnt);
5065 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
5066 // since we know the args, collect them
5067 collect_call_args(po, i, pp, ®mask, save_arg_vars,
5070 // for unresolved, collect after other passes
5074 ferr_assert(po, pp != NULL);
5076 po->regmask_src |= get_pp_arg_regmask_src(pp);
5077 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
5079 if (po->regmask_dst & mxST0)
5080 po->flags |= OPF_FPUSH;
5082 if (strstr(pp->ret_type.name, "int64"))
5088 if (po->flags & OPF_DONE)
5091 if (po->op == OP_PUSH && !(po->flags & OPF_FARG)
5092 && !(po->flags & OPF_RSAVE) && po->operand[0].type == OPT_CONST)
5094 scan_for_pop_const(i, opcnt, i + opcnt * 12);
5096 else if (po->op == OP_POP)
5097 scan_pushes_for_pop(i, opcnt, ®mask_pp);
5098 else if (po->op == OP_STD) {
5099 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
5100 scan_propagate_df(i + 1, opcnt);
5105 // - find POPs for PUSHes, rm both
5106 // - scan for all used registers
5107 memset(cbits, 0, sizeof(cbits));
5108 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
5109 0, ®mask_save, ®mask_init, regmask_arg);
5112 // - find flag set ops for their users
5113 // - do unresolved calls
5114 // - declare indirect functions
5115 for (i = 0; i < opcnt; i++)
5118 if (po->flags & (OPF_RMD|OPF_DONE))
5121 if (po->flags & OPF_CC)
5123 int setters[16], cnt = 0, branched = 0;
5125 ret = scan_for_flag_set(i, i + opcnt * 6,
5126 &branched, setters, &cnt);
5127 if (ret < 0 || cnt <= 0)
5128 ferr(po, "unable to trace flag setter(s)\n");
5129 if (cnt > ARRAY_SIZE(setters))
5130 ferr(po, "too many flag setters\n");
5132 for (j = 0; j < cnt; j++)
5134 tmp_op = &ops[setters[j]]; // flag setter
5137 // to get nicer code, we try to delay test and cmp;
5138 // if we can't because of operand modification, or if we
5139 // have arith op, or branch, make it calculate flags explicitly
5140 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
5142 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
5143 pfomask = 1 << po->pfo;
5145 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
5146 pfomask = 1 << po->pfo;
5149 // see if we'll be able to handle based on op result
5150 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
5151 && po->pfo != PFO_Z && po->pfo != PFO_S
5152 && po->pfo != PFO_P)
5154 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
5156 pfomask = 1 << po->pfo;
5159 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
5160 propagate_lmod(tmp_op, &tmp_op->operand[0],
5161 &tmp_op->operand[1]);
5162 if (tmp_op->operand[0].lmod == OPLM_DWORD)
5167 tmp_op->pfomask |= pfomask;
5168 cond_vars |= pfomask;
5170 // note: may overwrite, currently not a problem
5174 if (po->op == OP_RCL || po->op == OP_RCR
5175 || po->op == OP_ADC || po->op == OP_SBB)
5176 cond_vars |= 1 << PFO_C;
5179 if (po->op == OP_CMPS || po->op == OP_SCAS) {
5180 cond_vars |= 1 << PFO_Z;
5182 else if (po->op == OP_MUL
5183 || (po->op == OP_IMUL && po->operand_cnt == 1))
5185 if (po->operand[0].lmod == OPLM_DWORD)
5188 else if (po->op == OP_CALL) {
5189 // note: resolved non-reg calls are OPF_DONE already
5191 ferr_assert(po, pp != NULL);
5193 if (pp->is_unresolved) {
5194 int regmask_stack = 0;
5195 collect_call_args(po, i, pp, ®mask, save_arg_vars,
5198 // this is pretty rough guess:
5199 // see ecx and edx were pushed (and not their saved versions)
5200 for (arg = 0; arg < pp->argc; arg++) {
5201 if (pp->arg[arg].reg != NULL)
5204 tmp_op = pp->arg[arg].datap;
5206 ferr(po, "parsed_op missing for arg%d\n", arg);
5207 if (tmp_op->p_argnum == 0 && tmp_op->operand[0].type == OPT_REG)
5208 regmask_stack |= 1 << tmp_op->operand[0].reg;
5211 if (!((regmask_stack & (1 << xCX))
5212 && (regmask_stack & (1 << xDX))))
5214 if (pp->argc_stack != 0
5215 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
5217 pp_insert_reg_arg(pp, "ecx");
5218 pp->is_fastcall = 1;
5219 regmask_init |= 1 << xCX;
5220 regmask |= 1 << xCX;
5222 if (pp->argc_stack != 0
5223 || ((regmask | regmask_arg) & (1 << xDX)))
5225 pp_insert_reg_arg(pp, "edx");
5226 regmask_init |= 1 << xDX;
5227 regmask |= 1 << xDX;
5231 // note: __cdecl doesn't fall into is_unresolved category
5232 if (pp->argc_stack > 0)
5236 else if (po->op == OP_MOV && po->operand[0].pp != NULL
5237 && po->operand[1].pp != NULL)
5239 // <var> = offset <something>
5240 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
5241 && !IS_START(po->operand[1].name, "off_"))
5243 if (!po->operand[0].pp->is_fptr)
5244 ferr(po, "%s not declared as fptr when it should be\n",
5245 po->operand[0].name);
5246 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
5247 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
5248 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
5249 fnote(po, "var: %s\n", buf1);
5250 fnote(po, "func: %s\n", buf2);
5251 ferr(po, "^ mismatch\n");
5255 else if (po->op == OP_DIV || po->op == OP_IDIV) {
5256 if (po->operand[0].lmod == OPLM_DWORD) {
5257 // 32bit division is common, look for it
5258 if (po->op == OP_DIV)
5259 ret = scan_for_reg_clear(i, xDX);
5261 ret = scan_for_cdq_edx(i);
5263 po->flags |= OPF_32BIT;
5270 else if (po->op == OP_CLD)
5271 po->flags |= OPF_RMD | OPF_DONE;
5272 else if (po->op == OPP_FTOL) {
5273 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
5275 find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
5277 po->flags |= OPF_32BIT;
5279 else if (po->op == OP_FLD && po->operand[0].lmod == OPLM_QWORD)
5282 if (po->op == OP_RCL || po->op == OP_RCR || po->op == OP_XCHG)
5286 float_type = need_double ? "double" : "float";
5288 // output starts here
5290 // define userstack size
5291 if (g_func_pp->is_userstack) {
5292 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
5293 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
5294 fprintf(fout, "#endif\n");
5297 // the function itself
5298 ferr_assert(ops, !g_func_pp->is_fptr);
5299 output_pp(fout, g_func_pp,
5300 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
5301 fprintf(fout, "\n{\n");
5303 // declare indirect functions
5304 for (i = 0; i < opcnt; i++) {
5306 if (po->flags & OPF_RMD)
5309 if (po->op == OP_CALL) {
5312 ferr(po, "NULL pp\n");
5314 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
5315 if (pp->name[0] != 0) {
5316 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
5317 memcpy(pp->name, "i_", 2);
5319 // might be declared already
5321 for (j = 0; j < i; j++) {
5322 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
5323 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
5333 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
5336 output_pp(fout, pp, OPP_SIMPLE_ARGS);
5337 fprintf(fout, ";\n");
5342 // output LUTs/jumptables
5343 for (i = 0; i < g_func_pd_cnt; i++) {
5345 fprintf(fout, " static const ");
5346 if (pd->type == OPT_OFFSET) {
5347 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
5349 for (j = 0; j < pd->count; j++) {
5351 fprintf(fout, ", ");
5352 fprintf(fout, "&&%s", pd->d[j].u.label);
5356 fprintf(fout, "%s %s[] =\n { ",
5357 lmod_type_u(ops, pd->lmod), pd->label);
5359 for (j = 0; j < pd->count; j++) {
5361 fprintf(fout, ", ");
5362 fprintf(fout, "%u", pd->d[j].u.val);
5365 fprintf(fout, " };\n");
5369 // declare stack frame, va_arg
5371 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
5372 if (g_func_lmods & (1 << OPLM_WORD))
5373 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
5374 if (g_func_lmods & (1 << OPLM_BYTE))
5375 fprintf(fout, " u8 b[%d];", g_stack_fsz);
5376 if (g_func_lmods & (1 << OPLM_QWORD))
5377 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
5378 fprintf(fout, " } sf;\n");
5382 if (g_func_pp->is_userstack) {
5383 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
5384 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
5388 if (g_func_pp->is_vararg) {
5389 fprintf(fout, " va_list ap;\n");
5393 // declare arg-registers
5394 for (i = 0; i < g_func_pp->argc; i++) {
5395 if (g_func_pp->arg[i].reg != NULL) {
5396 reg = char_array_i(regs_r32,
5397 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
5398 if (regmask & (1 << reg)) {
5399 if (g_func_pp->arg[i].type.is_retreg)
5400 fprintf(fout, " u32 %s = *r_%s;\n",
5401 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
5403 fprintf(fout, " u32 %s = (u32)a%d;\n",
5404 g_func_pp->arg[i].reg, i + 1);
5407 if (g_func_pp->arg[i].type.is_retreg)
5408 ferr(ops, "retreg '%s' is unused?\n",
5409 g_func_pp->arg[i].reg);
5410 fprintf(fout, " // %s = a%d; // unused\n",
5411 g_func_pp->arg[i].reg, i + 1);
5417 // declare normal registers
5418 regmask_now = regmask & ~regmask_arg;
5419 regmask_now &= ~(1 << xSP);
5420 if (regmask_now & 0x00ff) {
5421 for (reg = 0; reg < 8; reg++) {
5422 if (regmask_now & (1 << reg)) {
5423 fprintf(fout, " u32 %s", regs_r32[reg]);
5424 if (regmask_init & (1 << reg))
5425 fprintf(fout, " = 0");
5426 fprintf(fout, ";\n");
5432 if (regmask_now & 0xff00) {
5433 for (reg = 8; reg < 16; reg++) {
5434 if (regmask_now & (1 << reg)) {
5435 fprintf(fout, " mmxr %s", regs_r32[reg]);
5436 if (regmask_init & (1 << reg))
5437 fprintf(fout, " = { 0, }");
5438 fprintf(fout, ";\n");
5444 if (regmask_now & 0xff0000) {
5445 for (reg = 16; reg < 24; reg++) {
5446 if (regmask_now & (1 << reg)) {
5447 fprintf(fout, " %s f_st%d", float_type, reg - 16);
5448 if (regmask_init & (1 << reg))
5449 fprintf(fout, " = 0");
5450 fprintf(fout, ";\n");
5457 for (reg = 0; reg < 8; reg++) {
5458 if (regmask_save & (1 << reg)) {
5459 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
5465 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
5466 if (save_arg_vars[i] == 0)
5468 for (reg = 0; reg < 32; reg++) {
5469 if (save_arg_vars[i] & (1 << reg)) {
5470 fprintf(fout, " u32 %s;\n",
5471 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
5477 // declare push-pop temporaries
5479 for (reg = 0; reg < 8; reg++) {
5480 if (regmask_pp & (1 << reg)) {
5481 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
5488 for (i = 0; i < 8; i++) {
5489 if (cond_vars & (1 << i)) {
5490 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
5497 fprintf(fout, " u32 tmp;\n");
5502 fprintf(fout, " u64 tmp64;\n");
5507 fprintf(fout, "\n");
5509 // do stack clear, if needed
5510 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
5512 if (g_stack_clear_len != 0) {
5513 if (g_stack_clear_len <= 4) {
5514 for (i = 0; i < g_stack_clear_len; i++)
5515 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
5516 fprintf(fout, "0;\n");
5519 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
5520 g_stack_clear_start, g_stack_clear_len * 4);
5524 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
5527 if (g_func_pp->is_vararg) {
5528 if (g_func_pp->argc_stack == 0)
5529 ferr(ops, "vararg func without stack args?\n");
5530 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
5534 for (i = 0; i < opcnt; i++)
5536 if (g_labels[i] != NULL) {
5537 fprintf(fout, "\n%s:\n", g_labels[i]);
5540 delayed_flag_op = NULL;
5541 last_arith_dst = NULL;
5545 if (po->flags & OPF_RMD)
5550 #define assert_operand_cnt(n_) \
5551 if (po->operand_cnt != n_) \
5552 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
5554 // conditional/flag using op?
5555 if (po->flags & OPF_CC)
5561 // we go through all this trouble to avoid using parsed_flag_op,
5562 // which makes generated code much nicer
5563 if (delayed_flag_op != NULL)
5565 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
5566 po->pfo, po->pfo_inv);
5569 else if (last_arith_dst != NULL
5570 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
5571 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
5574 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
5575 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
5576 last_arith_dst->lmod, buf3);
5579 else if (tmp_op != NULL) {
5580 // use preprocessed flag calc results
5581 if (!(tmp_op->pfomask & (1 << po->pfo)))
5582 ferr(po, "not prepared for pfo %d\n", po->pfo);
5584 // note: pfo_inv was not yet applied
5585 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
5586 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
5589 ferr(po, "all methods of finding comparison failed\n");
5592 if (po->flags & OPF_JMP) {
5593 fprintf(fout, " if %s", buf1);
5595 else if (po->op == OP_RCL || po->op == OP_RCR
5596 || po->op == OP_ADC || po->op == OP_SBB)
5599 fprintf(fout, " cond_%s = %s;\n",
5600 parsed_flag_op_names[po->pfo], buf1);
5602 else if (po->flags & OPF_DATA) { // SETcc
5603 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
5604 fprintf(fout, " %s = %s;", buf2, buf1);
5607 ferr(po, "unhandled conditional op\n");
5611 pfomask = po->pfomask;
5613 if (po->flags & (OPF_REPZ|OPF_REPNZ)) {
5614 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
5615 ret = try_resolve_const(i, &opr, opcnt * 7 + i, &uval);
5617 if (ret != 1 || uval == 0) {
5618 // we need initial flags for ecx=0 case..
5619 if (i > 0 && ops[i - 1].op == OP_XOR
5620 && IS(ops[i - 1].operand[0].name,
5621 ops[i - 1].operand[1].name))
5623 fprintf(fout, " cond_z = ");
5624 if (pfomask & (1 << PFO_C))
5625 fprintf(fout, "cond_c = ");
5626 fprintf(fout, "0;\n");
5628 else if (last_arith_dst != NULL) {
5629 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
5630 out_test_for_cc(buf1, sizeof(buf1), po, PFO_Z, 0,
5631 last_arith_dst->lmod, buf3);
5632 fprintf(fout, " cond_z = %s;\n", buf1);
5635 ferr(po, "missing initial ZF\n");
5642 assert_operand_cnt(2);
5643 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5644 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5645 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
5646 fprintf(fout, " %s = %s;", buf1,
5647 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5652 assert_operand_cnt(2);
5653 po->operand[1].lmod = OPLM_DWORD; // always
5654 fprintf(fout, " %s = %s;",
5655 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5656 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5661 assert_operand_cnt(2);
5662 fprintf(fout, " %s = %s;",
5663 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5664 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5668 assert_operand_cnt(2);
5669 switch (po->operand[1].lmod) {
5671 strcpy(buf3, "(s8)");
5674 strcpy(buf3, "(s16)");
5677 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
5679 fprintf(fout, " %s = %s;",
5680 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5681 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5686 assert_operand_cnt(2);
5687 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5688 fprintf(fout, " tmp = %s;",
5689 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
5690 fprintf(fout, " %s = %s;",
5691 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5692 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5693 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
5694 fprintf(fout, " %s = %stmp;",
5695 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
5696 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
5697 snprintf(g_comment, sizeof(g_comment), "xchg");
5701 assert_operand_cnt(1);
5702 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5703 fprintf(fout, " %s = ~%s;", buf1, buf1);
5707 assert_operand_cnt(2);
5708 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5709 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
5710 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
5711 strcpy(g_comment, "xlat");
5715 assert_operand_cnt(2);
5716 fprintf(fout, " %s = (s32)%s >> 31;",
5717 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5718 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5719 strcpy(g_comment, "cdq");
5723 if (po->flags & OPF_REP) {
5724 assert_operand_cnt(3);
5729 assert_operand_cnt(2);
5730 fprintf(fout, " %s = %sesi; esi %c= %d;",
5731 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
5732 lmod_cast_u_ptr(po, po->operand[1].lmod),
5733 (po->flags & OPF_DF) ? '-' : '+',
5734 lmod_bytes(po, po->operand[1].lmod));
5735 strcpy(g_comment, "lods");
5740 if (po->flags & OPF_REP) {
5741 assert_operand_cnt(3);
5742 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
5743 (po->flags & OPF_DF) ? '-' : '+',
5744 lmod_bytes(po, po->operand[1].lmod));
5745 fprintf(fout, " %sedi = eax;",
5746 lmod_cast_u_ptr(po, po->operand[1].lmod));
5747 strcpy(g_comment, "rep stos");
5750 assert_operand_cnt(2);
5751 fprintf(fout, " %sedi = eax; edi %c= %d;",
5752 lmod_cast_u_ptr(po, po->operand[1].lmod),
5753 (po->flags & OPF_DF) ? '-' : '+',
5754 lmod_bytes(po, po->operand[1].lmod));
5755 strcpy(g_comment, "stos");
5760 j = lmod_bytes(po, po->operand[0].lmod);
5761 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
5762 l = (po->flags & OPF_DF) ? '-' : '+';
5763 if (po->flags & OPF_REP) {
5764 assert_operand_cnt(3);
5766 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
5769 " %sedi = %sesi;", buf1, buf1);
5770 strcpy(g_comment, "rep movs");
5773 assert_operand_cnt(2);
5774 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
5775 buf1, buf1, l, j, l, j);
5776 strcpy(g_comment, "movs");
5781 // repe ~ repeat while ZF=1
5782 j = lmod_bytes(po, po->operand[0].lmod);
5783 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
5784 l = (po->flags & OPF_DF) ? '-' : '+';
5785 if (po->flags & OPF_REP) {
5786 assert_operand_cnt(3);
5788 " for (; ecx != 0; ecx--) {\n");
5789 if (pfomask & (1 << PFO_C)) {
5792 " cond_c = %sesi < %sedi;\n", buf1, buf1);
5793 pfomask &= ~(1 << PFO_C);
5796 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
5797 buf1, buf1, l, j, l, j);
5799 " if (cond_z %s 0) break;\n",
5800 (po->flags & OPF_REPZ) ? "==" : "!=");
5803 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
5804 (po->flags & OPF_REPZ) ? "e" : "ne");
5807 assert_operand_cnt(2);
5809 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
5810 buf1, buf1, l, j, l, j);
5811 strcpy(g_comment, "cmps");
5813 pfomask &= ~(1 << PFO_Z);
5814 last_arith_dst = NULL;
5815 delayed_flag_op = NULL;
5819 // only does ZF (for now)
5820 // repe ~ repeat while ZF=1
5821 j = lmod_bytes(po, po->operand[1].lmod);
5822 l = (po->flags & OPF_DF) ? '-' : '+';
5823 if (po->flags & OPF_REP) {
5824 assert_operand_cnt(3);
5826 " for (; ecx != 0; ecx--) {\n");
5828 " cond_z = (%seax == %sedi); edi %c= %d;\n",
5829 lmod_cast_u(po, po->operand[1].lmod),
5830 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
5832 " if (cond_z %s 0) break;\n",
5833 (po->flags & OPF_REPZ) ? "==" : "!=");
5836 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
5837 (po->flags & OPF_REPZ) ? "e" : "ne");
5840 assert_operand_cnt(2);
5841 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
5842 lmod_cast_u(po, po->operand[1].lmod),
5843 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
5844 strcpy(g_comment, "scas");
5846 pfomask &= ~(1 << PFO_Z);
5847 last_arith_dst = NULL;
5848 delayed_flag_op = NULL;
5851 // arithmetic w/flags
5853 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
5854 goto dualop_arith_const;
5855 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5859 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5860 if (po->operand[1].type == OPT_CONST) {
5861 j = lmod_bytes(po, po->operand[0].lmod);
5862 if (((1ull << j * 8) - 1) == po->operand[1].val)
5863 goto dualop_arith_const;
5868 assert_operand_cnt(2);
5869 fprintf(fout, " %s %s= %s;",
5870 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5872 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5873 output_std_flags(fout, po, &pfomask, buf1);
5874 last_arith_dst = &po->operand[0];
5875 delayed_flag_op = NULL;
5879 // and 0, or ~0 used instead mov
5880 assert_operand_cnt(2);
5881 fprintf(fout, " %s = %s;",
5882 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5883 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5884 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
5885 output_std_flags(fout, po, &pfomask, buf1);
5886 last_arith_dst = &po->operand[0];
5887 delayed_flag_op = NULL;
5892 assert_operand_cnt(2);
5893 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5894 if (pfomask & (1 << PFO_C)) {
5895 if (po->operand[1].type == OPT_CONST) {
5896 l = lmod_bytes(po, po->operand[0].lmod) * 8;
5897 j = po->operand[1].val;
5900 if (po->op == OP_SHL)
5904 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
5908 ferr(po, "zero shift?\n");
5912 pfomask &= ~(1 << PFO_C);
5914 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
5915 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5916 if (po->operand[1].type != OPT_CONST)
5917 fprintf(fout, " & 0x1f");
5919 output_std_flags(fout, po, &pfomask, buf1);
5920 last_arith_dst = &po->operand[0];
5921 delayed_flag_op = NULL;
5925 assert_operand_cnt(2);
5926 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5927 fprintf(fout, " %s = %s%s >> %s;", buf1,
5928 lmod_cast_s(po, po->operand[0].lmod), buf1,
5929 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5930 output_std_flags(fout, po, &pfomask, buf1);
5931 last_arith_dst = &po->operand[0];
5932 delayed_flag_op = NULL;
5937 assert_operand_cnt(3);
5938 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5939 l = lmod_bytes(po, po->operand[0].lmod) * 8;
5940 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
5941 if (po->operand[2].type != OPT_CONST) {
5942 // no handling for "undefined" case, hopefully not needed
5943 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
5946 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
5947 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5948 if (po->op == OP_SHLD) {
5949 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
5950 buf1, buf3, buf1, buf2, l, buf3);
5951 strcpy(g_comment, "shld");
5954 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
5955 buf1, buf3, buf1, buf2, l, buf3);
5956 strcpy(g_comment, "shrd");
5958 output_std_flags(fout, po, &pfomask, buf1);
5959 last_arith_dst = &po->operand[0];
5960 delayed_flag_op = NULL;
5965 assert_operand_cnt(2);
5966 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5967 if (po->operand[1].type == OPT_CONST) {
5968 j = po->operand[1].val;
5969 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
5970 fprintf(fout, po->op == OP_ROL ?
5971 " %s = (%s << %d) | (%s >> %d);" :
5972 " %s = (%s >> %d) | (%s << %d);",
5973 buf1, buf1, j, buf1,
5974 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
5978 output_std_flags(fout, po, &pfomask, buf1);
5979 last_arith_dst = &po->operand[0];
5980 delayed_flag_op = NULL;
5985 assert_operand_cnt(2);
5986 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5987 l = lmod_bytes(po, po->operand[0].lmod) * 8;
5988 if (po->operand[1].type == OPT_CONST) {
5989 j = po->operand[1].val % l;
5991 ferr(po, "zero rotate\n");
5992 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
5993 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
5994 if (po->op == OP_RCL) {
5996 " %s = (%s << %d) | (cond_c << %d)",
5997 buf1, buf1, j, j - 1);
5999 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
6003 " %s = (%s >> %d) | (cond_c << %d)",
6004 buf1, buf1, j, l - j);
6006 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
6008 fprintf(fout, ";\n");
6009 fprintf(fout, " cond_c = tmp;");
6013 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
6014 output_std_flags(fout, po, &pfomask, buf1);
6015 last_arith_dst = &po->operand[0];
6016 delayed_flag_op = NULL;
6020 assert_operand_cnt(2);
6021 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6022 if (IS(opr_name(po, 0), opr_name(po, 1))) {
6023 // special case for XOR
6024 if (pfomask & (1 << PFO_BE)) { // weird, but it happens..
6025 fprintf(fout, " cond_be = 1;\n");
6026 pfomask &= ~(1 << PFO_BE);
6028 fprintf(fout, " %s = 0;",
6029 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6030 last_arith_dst = &po->operand[0];
6031 delayed_flag_op = NULL;
6037 assert_operand_cnt(2);
6038 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6039 if (pfomask & (1 << PFO_C)) {
6040 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6041 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6042 if (po->operand[0].lmod == OPLM_DWORD) {
6043 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
6044 fprintf(fout, " cond_c = tmp64 >> 32;\n");
6045 fprintf(fout, " %s = (u32)tmp64;",
6046 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6047 strcat(g_comment, " add64");
6050 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
6051 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
6052 fprintf(fout, " %s += %s;",
6053 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6056 pfomask &= ~(1 << PFO_C);
6057 output_std_flags(fout, po, &pfomask, buf1);
6058 last_arith_dst = &po->operand[0];
6059 delayed_flag_op = NULL;
6065 assert_operand_cnt(2);
6066 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6067 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
6068 for (j = 0; j <= PFO_LE; j++) {
6069 if (!(pfomask & (1 << j)))
6071 if (j == PFO_Z || j == PFO_S)
6074 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0);
6075 fprintf(fout, " cond_%s = %s;\n",
6076 parsed_flag_op_names[j], buf1);
6077 pfomask &= ~(1 << j);
6084 assert_operand_cnt(2);
6085 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6086 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6087 if (po->op == OP_SBB
6088 && IS(po->operand[0].name, po->operand[1].name))
6090 // avoid use of unitialized var
6091 fprintf(fout, " %s = -cond_c;", buf1);
6092 // carry remains what it was
6093 pfomask &= ~(1 << PFO_C);
6096 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
6097 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6099 output_std_flags(fout, po, &pfomask, buf1);
6100 last_arith_dst = &po->operand[0];
6101 delayed_flag_op = NULL;
6105 assert_operand_cnt(2);
6106 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6107 fprintf(fout, " %s = %s ? __builtin_ffs(%s) - 1 : 0;",
6108 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6110 output_std_flags(fout, po, &pfomask, buf1);
6111 last_arith_dst = &po->operand[0];
6112 delayed_flag_op = NULL;
6113 strcat(g_comment, " bsf");
6117 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
6118 for (j = 0; j <= PFO_LE; j++) {
6119 if (!(pfomask & (1 << j)))
6121 if (j == PFO_Z || j == PFO_S || j == PFO_C)
6124 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0);
6125 fprintf(fout, " cond_%s = %s;\n",
6126 parsed_flag_op_names[j], buf1);
6127 pfomask &= ~(1 << j);
6133 if (pfomask & (1 << PFO_C))
6134 // carry is unaffected by inc/dec.. wtf?
6135 ferr(po, "carry propagation needed\n");
6137 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6138 if (po->operand[0].type == OPT_REG) {
6139 strcpy(buf2, po->op == OP_INC ? "++" : "--");
6140 fprintf(fout, " %s%s;", buf1, buf2);
6143 strcpy(buf2, po->op == OP_INC ? "+" : "-");
6144 fprintf(fout, " %s %s= 1;", buf1, buf2);
6146 output_std_flags(fout, po, &pfomask, buf1);
6147 last_arith_dst = &po->operand[0];
6148 delayed_flag_op = NULL;
6152 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6153 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
6154 fprintf(fout, " %s = -%s%s;", buf1,
6155 lmod_cast_s(po, po->operand[0].lmod), buf2);
6156 last_arith_dst = &po->operand[0];
6157 delayed_flag_op = NULL;
6158 if (pfomask & (1 << PFO_C)) {
6159 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
6160 pfomask &= ~(1 << PFO_C);
6165 if (po->operand_cnt == 2) {
6166 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6169 if (po->operand_cnt == 3)
6170 ferr(po, "TODO imul3\n");
6173 assert_operand_cnt(1);
6174 switch (po->operand[0].lmod) {
6176 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
6177 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
6178 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
6179 fprintf(fout, " edx = tmp64 >> 32;\n");
6180 fprintf(fout, " eax = tmp64;");
6183 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
6184 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
6185 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
6189 ferr(po, "TODO: unhandled mul type\n");
6192 last_arith_dst = NULL;
6193 delayed_flag_op = NULL;
6198 assert_operand_cnt(1);
6199 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6200 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
6201 po->op == OP_IDIV));
6202 switch (po->operand[0].lmod) {
6204 if (po->flags & OPF_32BIT)
6205 snprintf(buf2, sizeof(buf2), "%seax", cast);
6207 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
6208 snprintf(buf2, sizeof(buf2), "%stmp64",
6209 (po->op == OP_IDIV) ? "(s64)" : "");
6211 if (po->operand[0].type == OPT_REG
6212 && po->operand[0].reg == xDX)
6214 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
6215 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
6218 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
6219 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
6223 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
6224 snprintf(buf2, sizeof(buf2), "%stmp",
6225 (po->op == OP_IDIV) ? "(s32)" : "");
6226 if (po->operand[0].type == OPT_REG
6227 && po->operand[0].reg == xDX)
6229 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
6231 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
6235 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
6237 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
6240 strcat(g_comment, " div16");
6243 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
6245 last_arith_dst = NULL;
6246 delayed_flag_op = NULL;
6251 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6253 for (j = 0; j < 8; j++) {
6254 if (pfomask & (1 << j)) {
6255 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
6256 fprintf(fout, " cond_%s = %s;",
6257 parsed_flag_op_names[j], buf1);
6264 last_arith_dst = NULL;
6265 delayed_flag_op = po;
6269 // SETcc - should already be handled
6272 // note: we reuse OP_Jcc for SETcc, only flags differ
6274 fprintf(fout, "\n goto %s;", po->operand[0].name);
6278 fprintf(fout, " if (ecx == 0)\n");
6279 fprintf(fout, " goto %s;", po->operand[0].name);
6280 strcat(g_comment, " jecxz");
6284 fprintf(fout, " if (--ecx != 0)\n");
6285 fprintf(fout, " goto %s;", po->operand[0].name);
6286 strcat(g_comment, " loop");
6290 assert_operand_cnt(1);
6291 last_arith_dst = NULL;
6292 delayed_flag_op = NULL;
6294 if (po->operand[0].type == OPT_REGMEM) {
6295 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
6298 ferr(po, "parse failure for jmp '%s'\n",
6299 po->operand[0].name);
6300 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
6303 else if (po->operand[0].type != OPT_LABEL)
6304 ferr(po, "unhandled jmp type\n");
6306 fprintf(fout, " goto %s;", po->operand[0].name);
6310 assert_operand_cnt(1);
6312 my_assert_not(pp, NULL);
6315 if (po->flags & OPF_CC) {
6316 // we treat conditional branch to another func
6317 // (yes such code exists..) as conditional tailcall
6319 fprintf(fout, " {\n");
6322 if (pp->is_fptr && !pp->is_arg) {
6323 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
6324 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6326 if (pp->is_unresolved)
6327 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
6328 buf3, asmfn, po->asmln, pp->name);
6331 fprintf(fout, "%s", buf3);
6332 if (strstr(pp->ret_type.name, "int64")) {
6333 if (po->flags & OPF_TAIL)
6334 ferr(po, "int64 and tail?\n");
6335 fprintf(fout, "tmp64 = ");
6337 else if (!IS(pp->ret_type.name, "void")) {
6338 if (po->flags & OPF_TAIL) {
6339 if (regmask_ret & mxAX) {
6340 fprintf(fout, "return ");
6341 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
6342 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
6344 else if (regmask_ret & mxST0)
6345 ferr(po, "float tailcall\n");
6347 else if (po->regmask_dst & mxAX) {
6348 fprintf(fout, "eax = ");
6349 if (pp->ret_type.is_ptr)
6350 fprintf(fout, "(u32)");
6352 else if (po->regmask_dst & mxST0) {
6353 fprintf(fout, "f_st0 = ");
6357 if (pp->name[0] == 0)
6358 ferr(po, "missing pp->name\n");
6359 fprintf(fout, "%s%s(", pp->name,
6360 pp->has_structarg ? "_sa" : "");
6362 if (po->flags & OPF_ATAIL) {
6363 if (pp->argc_stack != g_func_pp->argc_stack
6364 || (pp->argc_stack > 0
6365 && pp->is_stdcall != g_func_pp->is_stdcall))
6366 ferr(po, "incompatible tailcall\n");
6367 if (g_func_pp->has_retreg)
6368 ferr(po, "TODO: retreg+tailcall\n");
6370 for (arg = j = 0; arg < pp->argc; arg++) {
6372 fprintf(fout, ", ");
6375 if (pp->arg[arg].type.is_ptr)
6376 snprintf(cast, sizeof(cast), "(%s)",
6377 pp->arg[arg].type.name);
6379 if (pp->arg[arg].reg != NULL) {
6380 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6384 for (; j < g_func_pp->argc; j++)
6385 if (g_func_pp->arg[j].reg == NULL)
6387 fprintf(fout, "%sa%d", cast, j + 1);
6392 for (arg = 0; arg < pp->argc; arg++) {
6394 fprintf(fout, ", ");
6397 if (pp->arg[arg].type.is_ptr)
6398 snprintf(cast, sizeof(cast), "(%s)",
6399 pp->arg[arg].type.name);
6401 if (pp->arg[arg].reg != NULL) {
6402 if (pp->arg[arg].type.is_retreg)
6403 fprintf(fout, "&%s", pp->arg[arg].reg);
6405 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6410 tmp_op = pp->arg[arg].datap;
6412 ferr(po, "parsed_op missing for arg%d\n", arg);
6414 if (tmp_op->flags & OPF_VAPUSH) {
6415 fprintf(fout, "ap");
6417 else if (tmp_op->p_argpass != 0) {
6418 fprintf(fout, "a%d", tmp_op->p_argpass);
6420 else if (tmp_op->p_argnum != 0) {
6421 fprintf(fout, "%s%s", cast,
6422 saved_arg_name(buf1, sizeof(buf1),
6423 tmp_op->p_arggrp, tmp_op->p_argnum));
6427 out_src_opr(buf1, sizeof(buf1),
6428 tmp_op, &tmp_op->operand[0], cast, 0));
6432 fprintf(fout, ");");
6434 if (strstr(pp->ret_type.name, "int64")) {
6435 fprintf(fout, "\n");
6436 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
6437 fprintf(fout, "%seax = tmp64;", buf3);
6440 if (pp->is_unresolved) {
6441 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
6443 strcat(g_comment, buf2);
6446 if (po->flags & OPF_TAIL) {
6448 if (i == opcnt - 1 || pp->is_noreturn)
6450 else if (IS(pp->ret_type.name, "void"))
6452 else if (!(regmask_ret & (1 << xAX)))
6454 // else already handled as 'return f()'
6457 fprintf(fout, "\n%sreturn;", buf3);
6458 strcat(g_comment, " ^ tailcall");
6461 strcat(g_comment, " tailcall");
6463 if ((regmask_ret & (1 << xAX))
6464 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
6466 ferr(po, "int func -> void func tailcall?\n");
6469 if (pp->is_noreturn)
6470 strcat(g_comment, " noreturn");
6471 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
6472 strcat(g_comment, " argframe");
6473 if (po->flags & OPF_CC)
6474 strcat(g_comment, " cond");
6476 if (po->flags & OPF_CC)
6477 fprintf(fout, "\n }");
6479 delayed_flag_op = NULL;
6480 last_arith_dst = NULL;
6484 if (g_func_pp->is_vararg)
6485 fprintf(fout, " va_end(ap);\n");
6486 if (g_func_pp->has_retreg) {
6487 for (arg = 0; arg < g_func_pp->argc; arg++)
6488 if (g_func_pp->arg[arg].type.is_retreg)
6489 fprintf(fout, " *r_%s = %s;\n",
6490 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
6493 if (!(regmask_ret & (1 << xAX))) {
6494 if (i != opcnt - 1 || label_pending)
6495 fprintf(fout, " return;");
6497 else if (g_func_pp->ret_type.is_ptr) {
6498 fprintf(fout, " return (%s)eax;",
6499 g_func_pp->ret_type.name);
6501 else if (IS(g_func_pp->ret_type.name, "__int64"))
6502 fprintf(fout, " return ((u64)edx << 32) | eax;");
6504 fprintf(fout, " return eax;");
6506 last_arith_dst = NULL;
6507 delayed_flag_op = NULL;
6511 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6512 if (po->p_argnum != 0) {
6513 // special case - saved func arg
6514 fprintf(fout, " %s = %s;",
6515 saved_arg_name(buf2, sizeof(buf2),
6516 po->p_arggrp, po->p_argnum), buf1);
6519 else if (po->flags & OPF_RSAVE) {
6520 fprintf(fout, " s_%s = %s;", buf1, buf1);
6523 else if (po->flags & OPF_PPUSH) {
6525 ferr_assert(po, tmp_op != NULL);
6526 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
6527 fprintf(fout, " pp_%s = %s;", buf2, buf1);
6530 else if (g_func_pp->is_userstack) {
6531 fprintf(fout, " *(--esp) = %s;", buf1);
6534 if (!(g_ida_func_attr & IDAFA_NORETURN))
6535 ferr(po, "stray push encountered\n");
6540 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6541 if (po->flags & OPF_RSAVE) {
6542 fprintf(fout, " %s = s_%s;", buf1, buf1);
6545 else if (po->flags & OPF_PPUSH) {
6546 // push/pop graph / non-const
6547 ferr_assert(po, po->datap == NULL);
6548 fprintf(fout, " %s = pp_%s;", buf1, buf1);
6551 else if (po->datap != NULL) {
6554 fprintf(fout, " %s = %s;", buf1,
6555 out_src_opr(buf2, sizeof(buf2),
6556 tmp_op, &tmp_op->operand[0],
6557 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6560 else if (g_func_pp->is_userstack) {
6561 fprintf(fout, " %s = *esp++;", buf1);
6565 ferr(po, "stray pop encountered\n");
6574 if (po->flags & OPF_FSHIFT)
6575 fprintf(fout, " f_st1 = f_st0;\n");
6576 if (po->operand[0].type == OPT_REG
6577 && po->operand[0].reg == xST0)
6579 strcat(g_comment, " fld st");
6582 fprintf(fout, " f_st0 = %s;",
6583 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0]));
6584 strcat(g_comment, " fld");
6588 if (po->flags & OPF_FSHIFT)
6589 fprintf(fout, " f_st1 = f_st0;\n");
6590 fprintf(fout, " f_st0 = (%s)%s;", float_type,
6591 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6592 lmod_cast(po, po->operand[0].lmod, 1), 0));
6593 strcat(g_comment, " fild");
6597 if (po->flags & OPF_FSHIFT)
6598 fprintf(fout, " f_st1 = f_st0;\n");
6599 fprintf(fout, " f_st0 = ");
6600 switch (po->operand[0].val) {
6601 case X87_CONST_1: fprintf(fout, "1.0;"); break;
6602 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
6603 default: ferr(po, "TODO\n"); break;
6608 if ((po->flags & OPF_FPOP) && po->operand[0].type == OPT_REG
6609 && po->operand[0].reg == xST0)
6614 fprintf(fout, " %s = f_st0;",
6615 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0]));
6616 if (po->flags & OPF_FSHIFT)
6617 fprintf(fout, "\n f_st0 = f_st1;");
6618 strcat(g_comment, " fst");
6626 case OP_FADD: j = '+'; break;
6627 case OP_FDIV: j = '/'; break;
6628 case OP_FMUL: j = '*'; break;
6629 case OP_FSUB: j = '-'; break;
6630 default: j = 'x'; break;
6632 if (po->flags & OPF_FSHIFT) {
6633 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
6636 fprintf(fout, " %s %c= %s;",
6637 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0]),
6639 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1]));
6645 if (po->flags & OPF_FSHIFT)
6646 snprintf(buf1, sizeof(buf1), "f_st0");
6648 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0]);
6649 fprintf(fout, " %s = %s %c %s;", buf1,
6650 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1]),
6651 po->op == OP_FDIVR ? '/' : '-',
6652 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0]));
6660 case OP_FIADD: j = '+'; break;
6661 case OP_FIDIV: j = '/'; break;
6662 case OP_FIMUL: j = '*'; break;
6663 case OP_FISUB: j = '-'; break;
6664 default: j = 'x'; break;
6666 fprintf(fout, " f_st0 %c= (%s)%s;", j, float_type,
6667 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6668 lmod_cast(po, po->operand[0].lmod, 1), 0));
6673 fprintf(fout, " f_st0 = %s %c f_st0;",
6674 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1]),
6675 po->op == OP_FIDIVR ? '/' : '-');
6679 fprintf(fout, " f_st0 = cos%s(f_st0);",
6680 need_double ? "" : "f");
6684 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
6685 need_double ? "" : "f");
6689 fprintf(fout, " f_st0 = sin%s(f_st0);",
6690 need_double ? "" : "f");
6694 fprintf(fout, " f_st0 = sqrt%s(f_st0);",
6695 need_double ? "" : "f");
6699 ferr_assert(po, po->flags & OPF_32BIT);
6700 fprintf(fout, " eax = (s32)f_st0;");
6701 if (po->flags & OPF_FSHIFT)
6702 fprintf(fout, "\n f_st0 = f_st1;");
6703 strcat(g_comment, " ftol");
6708 strcpy(g_comment, " (emms)");
6713 ferr(po, "unhandled op type %d, flags %x\n",
6718 if (g_comment[0] != 0) {
6719 char *p = g_comment;
6720 while (my_isblank(*p))
6722 fprintf(fout, " // %s", p);
6727 fprintf(fout, "\n");
6729 // some sanity checking
6730 if (po->flags & OPF_REP) {
6731 if (po->op != OP_STOS && po->op != OP_MOVS
6732 && po->op != OP_CMPS && po->op != OP_SCAS)
6733 ferr(po, "unexpected rep\n");
6734 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
6735 && (po->op == OP_CMPS || po->op == OP_SCAS))
6736 ferr(po, "cmps/scas with plain rep\n");
6738 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
6739 && po->op != OP_CMPS && po->op != OP_SCAS)
6740 ferr(po, "unexpected repz/repnz\n");
6743 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
6745 // see is delayed flag stuff is still valid
6746 if (delayed_flag_op != NULL && delayed_flag_op != po) {
6747 if (is_any_opr_modified(delayed_flag_op, po, 0))
6748 delayed_flag_op = NULL;
6751 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
6752 if (is_opr_modified(last_arith_dst, po))
6753 last_arith_dst = NULL;
6759 if (g_stack_fsz && !g_stack_frame_used)
6760 fprintf(fout, " (void)sf;\n");
6762 fprintf(fout, "}\n\n");
6764 gen_x_cleanup(opcnt);
6767 static void gen_x_cleanup(int opcnt)
6771 for (i = 0; i < opcnt; i++) {
6772 struct label_ref *lr, *lr_del;
6774 lr = g_label_refs[i].next;
6775 while (lr != NULL) {
6780 g_label_refs[i].i = -1;
6781 g_label_refs[i].next = NULL;
6783 if (ops[i].op == OP_CALL) {
6785 proto_release(ops[i].pp);
6791 struct func_proto_dep;
6793 struct func_prototype {
6798 int has_ret:3; // -1, 0, 1: unresolved, no, yes
6799 unsigned int dep_resolved:1;
6800 unsigned int is_stdcall:1;
6801 struct func_proto_dep *dep_func;
6803 const struct parsed_proto *pp; // seed pp, if any
6806 struct func_proto_dep {
6808 struct func_prototype *proto;
6809 int regmask_live; // .. at the time of call
6810 unsigned int ret_dep:1; // return from this is caller's return
6813 static struct func_prototype *hg_fp;
6814 static int hg_fp_cnt;
6816 static struct scanned_var {
6818 enum opr_lenmod lmod;
6819 unsigned int is_seeded:1;
6820 unsigned int is_c_str:1;
6821 const struct parsed_proto *pp; // seed pp, if any
6823 static int hg_var_cnt;
6825 static char **hg_refs;
6826 static int hg_ref_cnt;
6828 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
6831 static struct func_prototype *hg_fp_add(const char *funcn)
6833 struct func_prototype *fp;
6835 if ((hg_fp_cnt & 0xff) == 0) {
6836 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
6837 my_assert_not(hg_fp, NULL);
6838 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
6841 fp = &hg_fp[hg_fp_cnt];
6842 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
6844 fp->argc_stack = -1;
6850 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
6855 for (i = 0; i < fp->dep_func_cnt; i++)
6856 if (IS(fp->dep_func[i].name, name))
6857 return &fp->dep_func[i];
6862 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
6865 if (hg_fp_find_dep(fp, name))
6868 if ((fp->dep_func_cnt & 0xff) == 0) {
6869 fp->dep_func = realloc(fp->dep_func,
6870 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
6871 my_assert_not(fp->dep_func, NULL);
6872 memset(&fp->dep_func[fp->dep_func_cnt], 0,
6873 sizeof(fp->dep_func[0]) * 0x100);
6875 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
6879 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
6881 const struct func_prototype *p1 = p1_, *p2 = p2_;
6882 return strcmp(p1->name, p2->name);
6886 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
6888 const struct func_prototype *p1 = p1_, *p2 = p2_;
6889 return p1->id - p2->id;
6893 static void hg_ref_add(const char *name)
6895 if ((hg_ref_cnt & 0xff) == 0) {
6896 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
6897 my_assert_not(hg_refs, NULL);
6898 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
6901 hg_refs[hg_ref_cnt] = strdup(name);
6902 my_assert_not(hg_refs[hg_ref_cnt], NULL);
6906 // recursive register dep pass
6907 // - track saved regs (part 2)
6908 // - try to figure out arg-regs
6909 // - calculate reg deps
6910 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
6911 struct func_prototype *fp, int regmask_save, int regmask_dst,
6912 int *regmask_dep, int *has_ret)
6914 struct func_proto_dep *dep;
6915 struct parsed_op *po;
6916 int from_caller = 0;
6921 for (; i < opcnt; i++)
6923 if (cbits[i >> 3] & (1 << (i & 7)))
6925 cbits[i >> 3] |= (1 << (i & 7));
6929 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
6930 if (po->flags & OPF_RMD)
6933 if (po->btj != NULL) {
6935 for (j = 0; j < po->btj->count; j++) {
6936 check_i(po, po->btj->d[j].bt_i);
6937 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
6938 regmask_save, regmask_dst, regmask_dep, has_ret);
6943 check_i(po, po->bt_i);
6944 if (po->flags & OPF_CJMP) {
6945 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
6946 regmask_save, regmask_dst, regmask_dep, has_ret);
6954 if (po->flags & OPF_FARG)
6955 /* (just calculate register deps) */;
6956 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
6958 reg = po->operand[0].reg;
6959 ferr_assert(po, reg >= 0);
6961 if (po->flags & OPF_RSAVE) {
6962 regmask_save |= 1 << reg;
6965 if (po->flags & OPF_DONE)
6968 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0);
6970 regmask_save |= 1 << reg;
6971 po->flags |= OPF_RMD;
6972 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, OPF_RMD);
6976 else if (po->flags & OPF_RMD)
6978 else if (po->op == OP_CALL) {
6979 po->regmask_dst |= 1 << xAX;
6981 dep = hg_fp_find_dep(fp, po->operand[0].name);
6983 dep->regmask_live = regmask_save | regmask_dst;
6985 else if (po->op == OP_RET) {
6986 if (po->operand_cnt > 0) {
6988 if (fp->argc_stack >= 0
6989 && fp->argc_stack != po->operand[0].val / 4)
6990 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
6991 fp->argc_stack = po->operand[0].val / 4;
6995 // if has_ret is 0, there is uninitialized eax path,
6996 // which means it's most likely void func
6997 if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
6998 if (po->op == OP_CALL) {
7003 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
7006 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
7009 if (ret != 1 && from_caller) {
7010 // unresolved eax - probably void func
7014 if (j >= 0 && ops[j].op == OP_CALL) {
7015 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
7026 l = regmask_save | regmask_dst;
7027 if (g_bp_frame && !(po->flags & OPF_EBP_S))
7030 l = po->regmask_src & ~l;
7033 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
7034 l, regmask_dst, regmask_save, po->flags);
7037 regmask_dst |= po->regmask_dst;
7039 if (po->flags & OPF_TAIL)
7044 static void gen_hdr(const char *funcn, int opcnt)
7046 int save_arg_vars[MAX_ARG_GRP] = { 0, };
7047 unsigned char cbits[MAX_OPS / 8];
7048 const struct parsed_proto *pp_c;
7049 struct parsed_proto *pp;
7050 struct func_prototype *fp;
7051 struct parsed_op *po;
7052 int regmask_dummy = 0;
7054 int max_bp_offset = 0;
7059 pp_c = proto_parse(g_fhdr, funcn, 1);
7061 // already in seed, will add to hg_fp later
7064 fp = hg_fp_add(funcn);
7066 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
7067 g_stack_frame_used = 0;
7070 // - resolve all branches
7071 // - parse calls with labels
7072 resolve_branches_parse_calls(opcnt);
7075 // - handle ebp/esp frame, remove ops related to it
7076 scan_prologue_epilogue(opcnt);
7079 // - remove dead labels
7081 for (i = 0; i < opcnt; i++)
7083 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7089 if (po->flags & (OPF_RMD|OPF_DONE))
7092 if (po->op == OP_CALL) {
7093 if (po->operand[0].type == OPT_LABEL)
7094 hg_fp_add_dep(fp, opr_name(po, 0));
7095 else if (po->pp != NULL)
7096 hg_fp_add_dep(fp, po->pp->name);
7101 // - remove dead labels
7102 // - handle push <const>/pop pairs
7103 for (i = 0; i < opcnt; i++)
7105 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7111 if (po->flags & (OPF_RMD|OPF_DONE))
7114 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
7115 scan_for_pop_const(i, opcnt, i + opcnt * 13);
7119 // - process trivial calls
7120 for (i = 0; i < opcnt; i++)
7123 if (po->flags & (OPF_RMD|OPF_DONE))
7126 if (po->op == OP_CALL)
7128 pp = process_call_early(i, opcnt, &j);
7130 if (!(po->flags & OPF_ATAIL))
7131 // since we know the args, try to collect them
7132 if (collect_call_args_early(po, i, pp, ®mask_dummy) != 0)
7138 // commit esp adjust
7139 if (ops[j].op != OP_POP)
7140 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
7142 for (l = 0; l < pp->argc_stack; l++)
7143 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
7147 po->flags |= OPF_DONE;
7153 // - track saved regs (simple)
7155 for (i = 0; i < opcnt; i++)
7158 if (po->flags & (OPF_RMD|OPF_DONE))
7161 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
7162 && po->operand[0].reg != xCX)
7164 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
7166 // regmask_save |= 1 << po->operand[0].reg; // do it later
7167 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
7168 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
7171 else if (po->op == OP_CALL)
7173 pp = process_call(i, opcnt);
7175 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
7176 // since we know the args, collect them
7177 ret = collect_call_args(po, i, pp, ®mask_dummy, save_arg_vars,
7184 memset(cbits, 0, sizeof(cbits));
7188 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, ®mask_dep, &has_ret);
7190 // find unreachable code - must be fixed in IDA
7191 for (i = 0; i < opcnt; i++)
7193 if (cbits[i >> 3] & (1 << (i & 7)))
7196 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
7197 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
7199 // the compiler sometimes still generates code after
7200 // noreturn OS functions
7203 if (ops[i].op != OP_NOP)
7204 ferr(&ops[i], "unreachable code\n");
7207 for (i = 0; i < g_eqcnt; i++) {
7208 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
7209 max_bp_offset = g_eqs[i].offset;
7212 if (fp->argc_stack < 0) {
7213 max_bp_offset = (max_bp_offset + 3) & ~3;
7214 fp->argc_stack = max_bp_offset / 4;
7215 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
7219 fp->regmask_dep = regmask_dep & ~(1 << xSP);
7220 fp->has_ret = has_ret;
7222 printf("// has_ret %d, regmask_dep %x\n",
7223 fp->has_ret, fp->regmask_dep);
7224 output_hdr_fp(stdout, fp, 1);
7225 if (IS(funcn, "sub_10007F72")) exit(1);
7228 gen_x_cleanup(opcnt);
7231 static void hg_fp_resolve_deps(struct func_prototype *fp)
7233 struct func_prototype fp_s;
7237 // this thing is recursive, so mark first..
7238 fp->dep_resolved = 1;
7240 for (i = 0; i < fp->dep_func_cnt; i++) {
7241 strcpy(fp_s.name, fp->dep_func[i].name);
7242 fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
7243 sizeof(hg_fp[0]), hg_fp_cmp_name);
7244 if (fp->dep_func[i].proto != NULL) {
7245 if (!fp->dep_func[i].proto->dep_resolved)
7246 hg_fp_resolve_deps(fp->dep_func[i].proto);
7248 dep = ~fp->dep_func[i].regmask_live
7249 & fp->dep_func[i].proto->regmask_dep;
7250 fp->regmask_dep |= dep;
7251 // printf("dep %s %s |= %x\n", fp->name,
7252 // fp->dep_func[i].name, dep);
7254 if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
7255 fp->has_ret = fp->dep_func[i].proto->has_ret;
7260 // make all thiscall/edx arg functions referenced from .data fastcall
7261 static void do_func_refs_from_data(void)
7263 struct func_prototype *fp, fp_s;
7266 for (i = 0; i < hg_ref_cnt; i++) {
7267 strcpy(fp_s.name, hg_refs[i]);
7268 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
7269 sizeof(hg_fp[0]), hg_fp_cmp_name);
7273 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
7274 fp->regmask_dep |= mxCX | mxDX;
7278 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7281 const struct parsed_proto *pp;
7282 char *p, namebuf[NAMELEN];
7288 for (; count > 0; count--, fp++) {
7289 if (fp->has_ret == -1)
7290 fprintf(fout, "// ret unresolved\n");
7292 fprintf(fout, "// dep:");
7293 for (j = 0; j < fp->dep_func_cnt; j++) {
7294 fprintf(fout, " %s/", fp->dep_func[j].name);
7295 if (fp->dep_func[j].proto != NULL)
7296 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
7297 fp->dep_func[j].proto->has_ret);
7299 fprintf(fout, "\n");
7302 p = strchr(fp->name, '@');
7304 memcpy(namebuf, fp->name, p - fp->name);
7305 namebuf[p - fp->name] = 0;
7313 pp = proto_parse(g_fhdr, name, 1);
7314 if (pp != NULL && pp->is_include)
7317 if (fp->pp != NULL) {
7318 // part of seed, output later
7322 regmask_dep = fp->regmask_dep;
7323 argc_normal = fp->argc_stack;
7325 fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
7326 (fp->has_ret ? "int" : "void"));
7327 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
7328 && (regmask_dep & ~mxCX) == 0)
7330 fprintf(fout, "/*__thiscall*/ ");
7334 else if (regmask_dep && (fp->is_stdcall || fp->argc_stack == 0)
7335 && (regmask_dep & ~(mxCX | mxDX)) == 0)
7337 fprintf(fout, " __fastcall ");
7338 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
7344 else if (regmask_dep && !fp->is_stdcall) {
7345 fprintf(fout, "/*__usercall*/ ");
7347 else if (regmask_dep) {
7348 fprintf(fout, "/*__userpurge*/ ");
7350 else if (fp->is_stdcall)
7351 fprintf(fout, " __stdcall ");
7353 fprintf(fout, " __cdecl ");
7355 fprintf(fout, "%s(", name);
7358 for (j = 0; j < xSP; j++) {
7359 if (regmask_dep & (1 << j)) {
7362 fprintf(fout, ", ");
7364 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
7366 fprintf(fout, "int");
7367 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
7371 for (j = 0; j < argc_normal; j++) {
7374 fprintf(fout, ", ");
7375 if (fp->pp != NULL) {
7376 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
7377 if (!fp->pp->arg[arg - 1].type.is_ptr)
7381 fprintf(fout, "int ");
7382 fprintf(fout, "a%d", arg);
7385 fprintf(fout, ");\n");
7389 static void output_hdr(FILE *fout)
7391 static const char *lmod_c_names[] = {
7392 [OPLM_UNSPEC] = "???",
7393 [OPLM_BYTE] = "uint8_t",
7394 [OPLM_WORD] = "uint16_t",
7395 [OPLM_DWORD] = "uint32_t",
7396 [OPLM_QWORD] = "uint64_t",
7398 const struct scanned_var *var;
7399 struct func_prototype *fp;
7400 char line[256] = { 0, };
7404 // add stuff from headers
7405 for (i = 0; i < pp_cache_size; i++) {
7406 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
7407 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
7409 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
7410 fp = hg_fp_add(name);
7411 fp->pp = &pp_cache[i];
7412 fp->argc_stack = fp->pp->argc_stack;
7413 fp->is_stdcall = fp->pp->is_stdcall;
7414 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
7415 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
7419 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
7420 for (i = 0; i < hg_fp_cnt; i++)
7421 hg_fp_resolve_deps(&hg_fp[i]);
7423 // adjust functions referenced from data segment
7424 do_func_refs_from_data();
7426 // note: messes up .proto ptr, don't use
7427 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
7430 for (i = 0; i < hg_var_cnt; i++) {
7433 if (var->pp != NULL)
7436 else if (var->is_c_str)
7437 fprintf(fout, "extern %-8s %s[];", "char", var->name);
7439 fprintf(fout, "extern %-8s %s;",
7440 lmod_c_names[var->lmod], var->name);
7443 fprintf(fout, " // seeded");
7444 fprintf(fout, "\n");
7447 fprintf(fout, "\n");
7449 // output function prototypes
7450 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
7453 fprintf(fout, "\n// - seed -\n");
7456 while (fgets(line, sizeof(line), g_fhdr))
7457 fwrite(line, 1, strlen(line), fout);
7460 // '=' needs special treatment
7462 static char *next_word_s(char *w, size_t wsize, char *s)
7469 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
7471 for (i = 1; i < wsize - 1; i++) {
7473 printf("warning: missing closing quote: \"%s\"\n", s);
7482 for (; i < wsize - 1; i++) {
7483 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
7489 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
7490 printf("warning: '%s' truncated\n", w);
7495 static int cmpstringp(const void *p1, const void *p2)
7497 return strcmp(*(char * const *)p1, *(char * const *)p2);
7500 static int is_xref_needed(char *p, char **rlist, int rlist_len)
7505 if (strstr(p, "..."))
7506 // unable to determine, assume needed
7509 if (*p == '.') // .text, .data, ...
7510 // ref from other data or non-function -> no
7513 p2 = strpbrk(p, "+:\r\n\x18");
7516 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
7517 // referenced from removed code
7523 static int ida_xrefs_show_need(FILE *fasm, char *p,
7524 char **rlist, int rlist_len)
7530 p = strrchr(p, ';');
7531 if (p != NULL && *p == ';' && IS_START(p + 2, "DATA XREF: ")) {
7533 if (is_xref_needed(p, rlist, rlist_len))
7540 if (!my_fgets(line, sizeof(line), fasm))
7542 // non-first line is always indented
7543 if (!my_isblank(line[0]))
7546 // should be no content, just comment
7551 p = strrchr(p, ';');
7553 // it's printed once, but no harm to check again
7554 if (IS_START(p, "DATA XREF: "))
7557 if (is_xref_needed(p, rlist, rlist_len)) {
7562 fseek(fasm, pos, SEEK_SET);
7566 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
7568 struct scanned_var *var;
7569 char line[256] = { 0, };
7578 // skip to next data section
7579 while (my_fgets(line, sizeof(line), fasm))
7584 if (*p == 0 || *p == ';')
7587 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
7588 if (*p == 0 || *p == ';')
7591 if (*p != 's' || !IS_START(p, "segment para public"))
7597 if (p == NULL || !IS_START(p, "segment para public"))
7601 if (!IS_START(p, "'DATA'"))
7605 while (my_fgets(line, sizeof(line), fasm))
7610 no_identifier = my_isblank(*p);
7613 if (*p == 0 || *p == ';')
7616 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
7617 words[wordc][0] = 0;
7618 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
7619 if (*p == 0 || *p == ';') {
7625 if (wordc == 2 && IS(words[1], "ends"))
7630 if (no_identifier) {
7631 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
7632 hg_ref_add(words[2]);
7636 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
7637 // when this starts, we don't need anything from this section
7641 // check refs comment(s)
7642 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
7645 if ((hg_var_cnt & 0xff) == 0) {
7646 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
7647 * (hg_var_cnt + 0x100));
7648 my_assert_not(hg_vars, NULL);
7649 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
7652 var = &hg_vars[hg_var_cnt++];
7653 snprintf(var->name, sizeof(var->name), "%s", words[0]);
7655 // maybe already in seed header?
7656 var->pp = proto_parse(g_fhdr, var->name, 1);
7657 if (var->pp != NULL) {
7658 if (var->pp->is_fptr) {
7659 var->lmod = OPLM_DWORD;
7662 else if (var->pp->is_func)
7664 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
7665 aerr("unhandled C type '%s' for '%s'\n",
7666 var->pp->type.name, var->name);
7672 if (IS(words[1], "dd")) {
7673 var->lmod = OPLM_DWORD;
7674 if (wordc >= 4 && IS(words[2], "offset"))
7675 hg_ref_add(words[3]);
7677 else if (IS(words[1], "dw"))
7678 var->lmod = OPLM_WORD;
7679 else if (IS(words[1], "db")) {
7680 var->lmod = OPLM_BYTE;
7681 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
7682 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
7686 else if (IS(words[1], "dq"))
7687 var->lmod = OPLM_QWORD;
7688 //else if (IS(words[1], "dt"))
7690 aerr("type '%s' not known\n", words[1]);
7698 static void set_label(int i, const char *name)
7704 p = strchr(name, ':');
7708 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
7709 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
7710 g_labels[i] = realloc(g_labels[i], len + 1);
7711 my_assert_not(g_labels[i], NULL);
7712 memcpy(g_labels[i], name, len);
7713 g_labels[i][len] = 0;
7722 static struct chunk_item *func_chunks;
7723 static int func_chunk_cnt;
7724 static int func_chunk_alloc;
7726 static void add_func_chunk(FILE *fasm, const char *name, int line)
7728 if (func_chunk_cnt >= func_chunk_alloc) {
7729 func_chunk_alloc *= 2;
7730 func_chunks = realloc(func_chunks,
7731 func_chunk_alloc * sizeof(func_chunks[0]));
7732 my_assert_not(func_chunks, NULL);
7734 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
7735 func_chunks[func_chunk_cnt].name = strdup(name);
7736 func_chunks[func_chunk_cnt].asmln = line;
7740 static int cmp_chunks(const void *p1, const void *p2)
7742 const struct chunk_item *c1 = p1, *c2 = p2;
7743 return strcmp(c1->name, c2->name);
7746 static void scan_ahead(FILE *fasm)
7756 oldpos = ftell(fasm);
7759 while (my_fgets(line, sizeof(line), fasm))
7770 // get rid of random tabs
7771 for (i = 0; line[i] != 0; i++)
7772 if (line[i] == '\t')
7775 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
7778 next_word(words[0], sizeof(words[0]), p);
7779 if (words[0][0] == 0)
7780 aerr("missing name for func chunk?\n");
7782 add_func_chunk(fasm, words[0], asmln);
7784 else if (IS_START(p, "; sctend"))
7790 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
7791 words[wordc][0] = 0;
7792 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
7793 if (*p == 0 || *p == ';') {
7799 if (wordc == 2 && IS(words[1], "ends"))
7803 fseek(fasm, oldpos, SEEK_SET);
7807 int main(int argc, char *argv[])
7809 FILE *fout, *fasm, *frlist;
7810 struct parsed_data *pd = NULL;
7812 char **rlist = NULL;
7814 int rlist_alloc = 0;
7815 int func_chunks_used = 0;
7816 int func_chunks_sorted = 0;
7817 int func_chunk_i = -1;
7818 long func_chunk_ret = 0;
7819 int func_chunk_ret_ln = 0;
7820 int scanned_ahead = 0;
7822 char words[20][256];
7823 enum opr_lenmod lmod;
7824 char *sctproto = NULL;
7826 int pending_endp = 0;
7828 int skip_warned = 0;
7841 for (arg = 1; arg < argc; arg++) {
7842 if (IS(argv[arg], "-v"))
7844 else if (IS(argv[arg], "-rf"))
7845 g_allow_regfunc = 1;
7846 else if (IS(argv[arg], "-m"))
7848 else if (IS(argv[arg], "-hdr"))
7849 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
7854 if (argc < arg + 3) {
7855 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
7856 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
7858 " -hdr - header generation mode\n"
7859 " -rf - allow unannotated indirect calls\n"
7860 " -m - allow multiple .text sections\n"
7861 "[rlist] is a file with function names to skip,"
7869 asmfn = argv[arg++];
7870 fasm = fopen(asmfn, "r");
7871 my_assert_not(fasm, NULL);
7873 hdrfn = argv[arg++];
7874 g_fhdr = fopen(hdrfn, "r");
7875 my_assert_not(g_fhdr, NULL);
7878 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
7879 my_assert_not(rlist, NULL);
7880 // needs special handling..
7881 rlist[rlist_len++] = "__alloca_probe";
7883 func_chunk_alloc = 32;
7884 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
7885 my_assert_not(func_chunks, NULL);
7887 memset(words, 0, sizeof(words));
7889 for (; arg < argc; arg++) {
7890 frlist = fopen(argv[arg], "r");
7891 my_assert_not(frlist, NULL);
7893 while (my_fgets(line, sizeof(line), frlist)) {
7895 if (*p == 0 || *p == ';')
7898 if (IS_START(p, "#if 0")
7899 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
7903 else if (IS_START(p, "#endif"))
7910 p = next_word(words[0], sizeof(words[0]), p);
7911 if (words[0][0] == 0)
7914 if (rlist_len >= rlist_alloc) {
7915 rlist_alloc = rlist_alloc * 2 + 64;
7916 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
7917 my_assert_not(rlist, NULL);
7919 rlist[rlist_len++] = strdup(words[0]);
7928 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
7930 fout = fopen(argv[arg_out], "w");
7931 my_assert_not(fout, NULL);
7934 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
7935 my_assert_not(g_eqs, NULL);
7937 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
7938 g_label_refs[i].i = -1;
7939 g_label_refs[i].next = NULL;
7943 scan_variables(fasm, rlist, rlist_len);
7945 while (my_fgets(line, sizeof(line), fasm))
7954 // get rid of random tabs
7955 for (i = 0; line[i] != 0; i++)
7956 if (line[i] == '\t')
7961 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
7962 goto do_pending_endp; // eww..
7964 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
7966 static const char *attrs[] = {
7975 // parse IDA's attribute-list comment
7976 g_ida_func_attr = 0;
7979 for (; *p != 0; p = sskip(p)) {
7980 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
7981 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
7982 g_ida_func_attr |= 1 << i;
7983 p += strlen(attrs[i]);
7987 if (i == ARRAY_SIZE(attrs)) {
7988 anote("unparsed IDA attr: %s\n", p);
7991 if (IS(attrs[i], "fpd=")) {
7992 p = next_word(words[0], sizeof(words[0]), p);
7997 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
7999 static const char *attrs[] = {
8004 // parse manual attribute-list comment
8005 g_sct_func_attr = 0;
8008 for (; *p != 0; p = sskip(p)) {
8009 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8010 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8011 g_sct_func_attr |= 1 << i;
8012 p += strlen(attrs[i]);
8019 // clear_sf=start,len (in dwords)
8020 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
8021 &g_stack_clear_len, &j);
8023 // clear_regmask=<mask>
8024 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
8026 anote("unparsed attr value: %s\n", p);
8031 else if (i == ARRAY_SIZE(attrs)) {
8032 anote("unparsed sct attr: %s\n", p);
8037 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8040 next_word(words[0], sizeof(words[0]), p);
8041 if (words[0][0] == 0)
8042 aerr("missing name for func chunk?\n");
8044 if (!scanned_ahead) {
8045 add_func_chunk(fasm, words[0], asmln);
8046 func_chunks_sorted = 0;
8049 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
8051 if (func_chunk_i >= 0) {
8052 if (func_chunk_i < func_chunk_cnt
8053 && IS(func_chunks[func_chunk_i].name, g_func))
8055 // move on to next chunk
8056 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
8058 aerr("seek failed for '%s' chunk #%d\n",
8059 g_func, func_chunk_i);
8060 asmln = func_chunks[func_chunk_i].asmln;
8064 if (func_chunk_ret == 0)
8065 aerr("no return from chunk?\n");
8066 fseek(fasm, func_chunk_ret, SEEK_SET);
8067 asmln = func_chunk_ret_ln;
8073 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
8074 func_chunks_used = 1;
8076 if (IS_START(g_func, "sub_")) {
8077 unsigned long addr = strtoul(p, NULL, 16);
8078 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
8079 if (addr > f_addr && !scanned_ahead) {
8080 //anote("scan_ahead caused by '%s', addr %lx\n",
8084 func_chunks_sorted = 0;
8092 for (i = wordc; i < ARRAY_SIZE(words); i++)
8094 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8095 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8096 if (*p == 0 || *p == ';') {
8101 if (*p != 0 && *p != ';')
8102 aerr("too many words\n");
8104 // alow asm patches in comments
8106 if (IS_START(p, "; sctpatch:")) {
8108 if (*p == 0 || *p == ';')
8110 goto parse_words; // lame
8112 if (IS_START(p, "; sctproto:")) {
8113 sctproto = strdup(p + 11);
8115 else if (IS_START(p, "; sctend")) {
8124 awarn("wordc == 0?\n");
8128 // don't care about this:
8129 if (words[0][0] == '.'
8130 || IS(words[0], "include")
8131 || IS(words[0], "assume") || IS(words[1], "segment")
8132 || IS(words[0], "align"))
8138 // do delayed endp processing to collect switch jumptables
8140 if (in_func && !g_skip_func && !end && wordc >= 2
8141 && ((words[0][0] == 'd' && words[0][2] == 0)
8142 || (words[1][0] == 'd' && words[1][2] == 0)))
8145 if (words[1][0] == 'd' && words[1][2] == 0) {
8147 if (g_func_pd_cnt >= pd_alloc) {
8148 pd_alloc = pd_alloc * 2 + 16;
8149 g_func_pd = realloc(g_func_pd,
8150 sizeof(g_func_pd[0]) * pd_alloc);
8151 my_assert_not(g_func_pd, NULL);
8153 pd = &g_func_pd[g_func_pd_cnt];
8155 memset(pd, 0, sizeof(*pd));
8156 strcpy(pd->label, words[0]);
8157 pd->type = OPT_CONST;
8158 pd->lmod = lmod_from_directive(words[1]);
8164 anote("skipping alignment byte?\n");
8167 lmod = lmod_from_directive(words[0]);
8168 if (lmod != pd->lmod)
8169 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
8172 if (pd->count_alloc < pd->count + wordc) {
8173 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
8174 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
8175 my_assert_not(pd->d, NULL);
8177 for (; i < wordc; i++) {
8178 if (IS(words[i], "offset")) {
8179 pd->type = OPT_OFFSET;
8182 p = strchr(words[i], ',');
8185 if (pd->type == OPT_OFFSET)
8186 pd->d[pd->count].u.label = strdup(words[i]);
8188 pd->d[pd->count].u.val = parse_number(words[i]);
8189 pd->d[pd->count].bt_i = -1;
8195 if (in_func && !g_skip_func) {
8197 gen_hdr(g_func, pi);
8199 gen_func(fout, g_fhdr, g_func, pi);
8204 g_ida_func_attr = 0;
8205 g_sct_func_attr = 0;
8206 g_stack_clear_start = 0;
8207 g_stack_clear_len = 0;
8212 func_chunks_used = 0;
8215 memset(&ops, 0, pi * sizeof(ops[0]));
8220 for (i = 0; i < g_func_pd_cnt; i++) {
8222 if (pd->type == OPT_OFFSET) {
8223 for (j = 0; j < pd->count; j++)
8224 free(pd->d[j].u.label);
8239 if (IS(words[1], "proc")) {
8241 aerr("proc '%s' while in_func '%s'?\n",
8244 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8246 strcpy(g_func, words[0]);
8247 set_label(0, words[0]);
8252 if (IS(words[1], "endp"))
8255 aerr("endp '%s' while not in_func?\n", words[0]);
8256 if (!IS(g_func, words[0]))
8257 aerr("endp '%s' while in_func '%s'?\n",
8260 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
8261 && ops[0].op == OP_JMP && ops[0].operand[0].had_ds)
8267 if (!g_skip_func && func_chunks_used) {
8268 // start processing chunks
8269 struct chunk_item *ci, key = { g_func, 0 };
8271 func_chunk_ret = ftell(fasm);
8272 func_chunk_ret_ln = asmln;
8273 if (!func_chunks_sorted) {
8274 qsort(func_chunks, func_chunk_cnt,
8275 sizeof(func_chunks[0]), cmp_chunks);
8276 func_chunks_sorted = 1;
8278 ci = bsearch(&key, func_chunks, func_chunk_cnt,
8279 sizeof(func_chunks[0]), cmp_chunks);
8281 aerr("'%s' needs chunks, but none found\n", g_func);
8282 func_chunk_i = ci - func_chunks;
8283 for (; func_chunk_i > 0; func_chunk_i--)
8284 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
8287 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
8289 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
8290 asmln = func_chunks[func_chunk_i].asmln;
8298 if (wordc == 2 && IS(words[1], "ends")) {
8302 goto do_pending_endp;
8306 // scan for next text segment
8307 while (my_fgets(line, sizeof(line), fasm)) {
8310 if (*p == 0 || *p == ';')
8313 if (strstr(p, "segment para public 'CODE' use32"))
8320 p = strchr(words[0], ':');
8322 set_label(pi, words[0]);
8326 if (!in_func || g_skip_func) {
8327 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
8329 anote("skipping from '%s'\n", g_labels[pi]);
8333 g_labels[pi] = NULL;
8337 if (wordc > 1 && IS(words[1], "="))
8340 aerr("unhandled equ, wc=%d\n", wordc);
8341 if (g_eqcnt >= eq_alloc) {
8343 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
8344 my_assert_not(g_eqs, NULL);
8347 len = strlen(words[0]);
8348 if (len > sizeof(g_eqs[0].name) - 1)
8349 aerr("equ name too long: %d\n", len);
8350 strcpy(g_eqs[g_eqcnt].name, words[0]);
8352 if (!IS(words[3], "ptr"))
8353 aerr("unhandled equ\n");
8354 if (IS(words[2], "dword"))
8355 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
8356 else if (IS(words[2], "word"))
8357 g_eqs[g_eqcnt].lmod = OPLM_WORD;
8358 else if (IS(words[2], "byte"))
8359 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
8360 else if (IS(words[2], "qword"))
8361 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
8363 aerr("bad lmod: '%s'\n", words[2]);
8365 g_eqs[g_eqcnt].offset = parse_number(words[4]);
8370 if (pi >= ARRAY_SIZE(ops))
8371 aerr("too many ops\n");
8373 parse_op(&ops[pi], words, wordc);
8375 ops[pi].datap = sctproto;
8390 // vim:ts=2:shiftwidth=2:expandtab