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 */
149 // pseudo-ops for lib calls
164 // must be sorted (larger len must be further in enum)
173 #define MAX_EXITS 128
175 #define MAX_OPERANDS 3
178 #define OPR_INIT(type_, lmod_, reg_) \
179 { type_, lmod_, reg_, }
183 enum opr_lenmod lmod;
185 unsigned int is_ptr:1; // pointer in C
186 unsigned int is_array:1; // array in C
187 unsigned int type_from_var:1; // .. in header, sometimes wrong
188 unsigned int size_mismatch:1; // type override differs from C
189 unsigned int size_lt:1; // type override is larger than C
190 unsigned int had_ds:1; // had ds: prefix
191 const struct parsed_proto *pp; // for OPT_LABEL
198 struct parsed_opr operand[MAX_OPERANDS];
201 unsigned char pfo_inv;
202 unsigned char operand_cnt;
203 unsigned char p_argnum; // arg push: altered before call arg #
204 unsigned char p_arggrp; // arg push: arg group # for above
205 unsigned char p_argpass;// arg push: arg of host func
206 short p_argnext;// arg push: same arg pushed elsewhere or -1
207 int regmask_src; // all referensed regs
209 int pfomask; // flagop: parsed_flag_op that can't be delayed
210 int cc_scratch; // scratch storage during analysis
211 int bt_i; // branch target for branches
212 struct parsed_data *btj;// branch targets for jumptables
213 struct parsed_proto *pp;// parsed_proto for OP_CALL
219 // on start: function/data type hint (sctproto)
221 // (OPF_CC) - points to one of (OPF_FLAGS) that affects cc op
222 // OP_PUSH - points to OP_POP in complex push/pop graph
223 // OP_POP - points to OP_PUSH in simple push/pop pair
227 enum opr_lenmod lmod;
234 enum opr_lenmod lmod;
248 struct label_ref *next;
252 IDAFA_BP_FRAME = (1 << 0),
253 IDAFA_LIB_FUNC = (1 << 1),
254 IDAFA_STATIC = (1 << 2),
255 IDAFA_NORETURN = (1 << 3),
256 IDAFA_THUNK = (1 << 4),
257 IDAFA_FPD = (1 << 5),
261 SCTFA_CLEAR_SF = (1 << 0), // clear stack frame
262 SCTFA_CLEAR_REGS = (1 << 1), // clear registers (mask)
275 // note: limited to 32k due to p_argnext
277 #define MAX_ARG_GRP 2
279 static struct parsed_op ops[MAX_OPS];
280 static struct parsed_equ *g_eqs;
282 static char *g_labels[MAX_OPS];
283 static struct label_ref g_label_refs[MAX_OPS];
284 static const struct parsed_proto *g_func_pp;
285 static struct parsed_data *g_func_pd;
286 static int g_func_pd_cnt;
287 static int g_func_lmods;
288 static char g_func[256];
289 static char g_comment[256];
290 static int g_bp_frame;
291 static int g_sp_frame;
292 static int g_stack_frame_used;
293 static int g_stack_fsz;
294 static int g_ida_func_attr;
295 static int g_sct_func_attr;
296 static int g_stack_clear_start; // in dwords
297 static int g_stack_clear_len;
298 static int g_regmask_init;
299 static int g_skip_func;
300 static int g_allow_regfunc;
301 static int g_quiet_pp;
302 static int g_header_mode;
304 #define ferr(op_, fmt, ...) do { \
305 printf("%s:%d: error %u: [%s] '%s': " fmt, asmfn, (op_)->asmln, \
306 __LINE__, g_func, dump_op(op_), ##__VA_ARGS__); \
310 #define fnote(op_, fmt, ...) \
311 printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
312 dump_op(op_), ##__VA_ARGS__)
314 #define ferr_assert(op_, cond) do { \
315 if (!(cond)) ferr(op_, "assertion '%s' failed\n", #cond); \
318 const char *regs_r32[] = {
319 "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
320 // not r32, but list here for easy parsing and printing
321 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
322 "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"
324 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
325 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
326 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
332 xMM0, xMM1, xMM2, xMM3, // mmx
333 xMM4, xMM5, xMM6, xMM7,
334 xST0, xST1, xST2, xST3, // x87
335 xST4, xST5, xST6, xST7,
338 #define mxAX (1 << xAX)
339 #define mxCX (1 << xCX)
340 #define mxDX (1 << xDX)
341 #define mxST0 (1 << xST0)
342 #define mxST1 (1 << xST1)
343 #define mxST1_0 (mxST1 | mxST0)
344 #define mxST7_2 (0xfc << xST0)
345 #define mxSTa (0xff << xST0)
347 // possible basic comparison types (without inversion)
348 enum parsed_flag_op {
352 PFO_BE, // 6 CF=1||ZF=1
356 PFO_LE, // e ZF=1||SF!=OF
359 #define PFOB_O (1 << PFO_O)
360 #define PFOB_C (1 << PFO_C)
361 #define PFOB_Z (1 << PFO_Z)
362 #define PFOB_S (1 << PFO_S)
364 static const char *parsed_flag_op_names[] = {
365 "o", "c", "z", "be", "s", "p", "l", "le"
368 static int char_array_i(const char *array[], size_t len, const char *s)
372 for (i = 0; i < len; i++)
379 static void printf_number(char *buf, size_t buf_size,
380 unsigned long number)
382 // output in C-friendly form
383 snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
386 static int check_segment_prefix(const char *s)
388 if (s[0] == 0 || s[1] != 's' || s[2] != ':')
402 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
406 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
408 *reg_lmod = OPLM_QWORD;
412 *reg_lmod = OPLM_DWORD;
415 reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
417 *reg_lmod = OPLM_WORD;
420 reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
422 *reg_lmod = OPLM_BYTE;
425 reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
427 *reg_lmod = OPLM_BYTE;
434 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
436 enum opr_lenmod lmod;
449 while (my_isblank(*s))
451 for (; my_issep(*s); d++, s++)
453 while (my_isblank(*s))
457 // skip '?s:' prefixes
458 if (check_segment_prefix(s))
461 s = next_idt(w, sizeof(w), s);
466 reg = parse_reg(&lmod, w);
468 *regmask |= 1 << reg;
472 if ('0' <= w[0] && w[0] <= '9') {
473 number = parse_number(w);
474 printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
478 // probably some label/identifier - pass
481 snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
485 strcpy(name, cvtbuf);
490 static int is_reg_in_str(const char *s)
494 if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
497 for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
498 if (!strncmp(s, regs_r32[i], 3))
504 static const char *parse_stack_el(const char *name, char *extra_reg,
507 const char *p, *p2, *s;
513 if (g_bp_frame || early_try)
516 if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
518 if (extra_reg != NULL) {
519 strncpy(extra_reg, name, 3);
524 if (IS_START(p, "ebp+")) {
528 if (p2 != NULL && is_reg_in_str(p)) {
529 if (extra_reg != NULL) {
530 strncpy(extra_reg, p, p2 - p);
531 extra_reg[p2 - p] = 0;
536 if (!('0' <= *p && *p <= '9'))
543 if (!IS_START(name, "esp+"))
549 if (is_reg_in_str(s)) {
550 if (extra_reg != NULL) {
551 strncpy(extra_reg, s, p - s);
552 extra_reg[p - s] = 0;
557 aerr("%s IDA stackvar not set?\n", __func__);
559 if (!('0' <= *s && *s <= '9')) {
560 aerr("%s IDA stackvar offset not set?\n", __func__);
563 if (s[0] == '0' && s[1] == 'x')
566 if (len < sizeof(buf) - 1) {
567 strncpy(buf, s, len);
569 val = strtol(buf, &endp, 16);
570 if (val == 0 || *endp != 0) {
571 aerr("%s num parse fail for '%s'\n", __func__, buf);
580 if ('0' <= *p && *p <= '9')
586 static int guess_lmod_from_name(struct parsed_opr *opr)
588 if (IS_START(opr->name, "dword_") || IS_START(opr->name, "off_")) {
589 opr->lmod = OPLM_DWORD;
592 if (IS_START(opr->name, "word_")) {
593 opr->lmod = OPLM_WORD;
596 if (IS_START(opr->name, "byte_")) {
597 opr->lmod = OPLM_BYTE;
600 if (IS_START(opr->name, "qword_")) {
601 opr->lmod = OPLM_QWORD;
607 static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
608 const struct parsed_type *c_type)
610 static const char *dword_types[] = {
611 "uint32_t", "int", "_DWORD", "UINT_PTR", "DWORD",
612 "WPARAM", "LPARAM", "UINT", "__int32",
613 "LONG", "HIMC", "BOOL", "size_t",
616 static const char *word_types[] = {
617 "uint16_t", "int16_t", "_WORD", "WORD",
618 "unsigned __int16", "__int16",
620 static const char *byte_types[] = {
621 "uint8_t", "int8_t", "char",
622 "unsigned __int8", "__int8", "BYTE", "_BYTE",
624 // structures.. deal the same as with _UNKNOWN for now
630 if (c_type->is_ptr) {
635 n = skip_type_mod(c_type->name);
637 for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
638 if (IS(n, dword_types[i])) {
644 for (i = 0; i < ARRAY_SIZE(word_types); i++) {
645 if (IS(n, word_types[i])) {
651 for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
652 if (IS(n, byte_types[i])) {
661 static char *default_cast_to(char *buf, size_t buf_size,
662 struct parsed_opr *opr)
666 if (!opr->is_ptr || strchr(opr->name, '['))
668 if (opr->pp == NULL || opr->pp->type.name == NULL
671 snprintf(buf, buf_size, "%s", "(void *)");
675 snprintf(buf, buf_size, "(%s)", opr->pp->type.name);
679 static enum opr_type lmod_from_directive(const char *d)
683 else if (IS(d, "dw"))
685 else if (IS(d, "db"))
688 aerr("unhandled directive: '%s'\n", d);
692 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
698 *regmask |= 1 << reg;
701 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
704 static int parse_operand(struct parsed_opr *opr,
705 int *regmask, int *regmask_indirect,
706 char words[16][256], int wordc, int w, unsigned int op_flags)
708 const struct parsed_proto *pp = NULL;
709 enum opr_lenmod tmplmod;
710 unsigned long number;
718 aerr("parse_operand w %d, wordc %d\n", w, wordc);
722 for (i = w; i < wordc; i++) {
723 len = strlen(words[i]);
724 if (words[i][len - 1] == ',') {
725 words[i][len - 1] = 0;
731 wordc_in = wordc - w;
733 if ((op_flags & OPF_JMP) && wordc_in > 0
734 && !('0' <= words[w][0] && words[w][0] <= '9'))
736 const char *label = NULL;
738 if (wordc_in == 3 && !strncmp(words[w], "near", 4)
739 && IS(words[w + 1], "ptr"))
740 label = words[w + 2];
741 else if (wordc_in == 2 && IS(words[w], "short"))
742 label = words[w + 1];
743 else if (wordc_in == 1
744 && strchr(words[w], '[') == NULL
745 && parse_reg(&tmplmod, words[w]) < 0)
749 opr->type = OPT_LABEL;
750 ret = check_segment_prefix(label);
753 aerr("fs/gs used\n");
757 strcpy(opr->name, label);
763 if (IS(words[w + 1], "ptr")) {
764 if (IS(words[w], "dword"))
765 opr->lmod = OPLM_DWORD;
766 else if (IS(words[w], "word"))
767 opr->lmod = OPLM_WORD;
768 else if (IS(words[w], "byte"))
769 opr->lmod = OPLM_BYTE;
770 else if (IS(words[w], "qword"))
771 opr->lmod = OPLM_QWORD;
773 aerr("type parsing failed\n");
775 wordc_in = wordc - w;
780 if (IS(words[w], "offset")) {
781 opr->type = OPT_OFFSET;
782 opr->lmod = OPLM_DWORD;
783 strcpy(opr->name, words[w + 1]);
784 pp = proto_parse(g_fhdr, opr->name, 1);
787 if (IS(words[w], "(offset")) {
788 p = strchr(words[w + 1], ')');
790 aerr("parse of bracketed offset failed\n");
792 opr->type = OPT_OFFSET;
793 strcpy(opr->name, words[w + 1]);
799 aerr("parse_operand 1 word expected\n");
801 ret = check_segment_prefix(words[w]);
804 aerr("fs/gs used\n");
806 memmove(words[w], words[w] + 3, strlen(words[w]) - 2);
808 strcpy(opr->name, words[w]);
810 if (words[w][0] == '[') {
811 opr->type = OPT_REGMEM;
812 ret = sscanf(words[w], "[%[^]]]", opr->name);
814 aerr("[] parse failure\n");
816 parse_indmode(opr->name, regmask_indirect, 1);
817 if (opr->lmod == OPLM_UNSPEC && parse_stack_el(opr->name, NULL, 1))
820 struct parsed_equ *eq =
821 equ_find(NULL, parse_stack_el(opr->name, NULL, 1), &i);
823 opr->lmod = eq->lmod;
825 // might be unaligned access
826 g_func_lmods |= 1 << OPLM_BYTE;
830 else if (strchr(words[w], '[')) {
832 p = strchr(words[w], '[');
833 opr->type = OPT_REGMEM;
834 parse_indmode(p, regmask_indirect, 0);
835 strncpy(buf, words[w], p - words[w]);
836 buf[p - words[w]] = 0;
837 pp = proto_parse(g_fhdr, buf, 1);
840 else if (('0' <= words[w][0] && words[w][0] <= '9')
841 || words[w][0] == '-')
843 number = parse_number(words[w]);
844 opr->type = OPT_CONST;
846 printf_number(opr->name, sizeof(opr->name), number);
850 ret = parse_reg(&tmplmod, opr->name);
852 setup_reg_opr(opr, ret, tmplmod, regmask);
856 // most likely var in data segment
857 opr->type = OPT_LABEL;
858 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
862 if (pp->is_fptr || pp->is_func) {
863 opr->lmod = OPLM_DWORD;
867 tmplmod = OPLM_UNSPEC;
868 if (!guess_lmod_from_c_type(&tmplmod, &pp->type))
869 anote("unhandled C type '%s' for '%s'\n",
870 pp->type.name, opr->name);
872 if (opr->lmod == OPLM_UNSPEC) {
874 opr->type_from_var = 1;
876 else if (opr->lmod != tmplmod) {
877 opr->size_mismatch = 1;
878 if (tmplmod < opr->lmod)
881 opr->is_ptr = pp->type.is_ptr;
883 opr->is_array = pp->type.is_array;
887 if (opr->lmod == OPLM_UNSPEC)
888 guess_lmod_from_name(opr);
892 static const struct {
897 { "repe", OPF_REP|OPF_REPZ },
898 { "repz", OPF_REP|OPF_REPZ },
899 { "repne", OPF_REP|OPF_REPNZ },
900 { "repnz", OPF_REP|OPF_REPNZ },
901 { "lock", OPF_LOCK }, // ignored for now..
904 #define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
906 static const struct {
909 unsigned short minopr;
910 unsigned short maxopr;
913 unsigned char pfo_inv;
915 { "nop", OP_NOP, 0, 0, 0 },
916 { "push", OP_PUSH, 1, 1, 0 },
917 { "pop", OP_POP, 1, 1, OPF_DATA },
918 { "leave",OP_LEAVE, 0, 0, OPF_DATA },
919 { "mov" , OP_MOV, 2, 2, OPF_DATA },
920 { "lea", OP_LEA, 2, 2, OPF_DATA },
921 { "movzx",OP_MOVZX, 2, 2, OPF_DATA },
922 { "movsx",OP_MOVSX, 2, 2, OPF_DATA },
923 { "xchg", OP_XCHG, 2, 2, OPF_DATA },
924 { "not", OP_NOT, 1, 1, OPF_DATA },
925 { "xlat", OP_XLAT, 0, 0, OPF_DATA },
926 { "cdq", OP_CDQ, 0, 0, OPF_DATA },
927 { "lodsb",OP_LODS, 0, 0, OPF_DATA },
928 { "lodsw",OP_LODS, 0, 0, OPF_DATA },
929 { "lodsd",OP_LODS, 0, 0, OPF_DATA },
930 { "stosb",OP_STOS, 0, 0, OPF_DATA },
931 { "stosw",OP_STOS, 0, 0, OPF_DATA },
932 { "stosd",OP_STOS, 0, 0, OPF_DATA },
933 { "movsb",OP_MOVS, 0, 0, OPF_DATA },
934 { "movsw",OP_MOVS, 0, 0, OPF_DATA },
935 { "movsd",OP_MOVS, 0, 0, OPF_DATA },
936 { "cmpsb",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
937 { "cmpsw",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
938 { "cmpsd",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
939 { "scasb",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
940 { "scasw",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
941 { "scasd",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
942 { "std", OP_STD, 0, 0, OPF_DATA }, // special flag
943 { "cld", OP_CLD, 0, 0, OPF_DATA },
944 { "add", OP_ADD, 2, 2, OPF_DATA|OPF_FLAGS },
945 { "sub", OP_SUB, 2, 2, OPF_DATA|OPF_FLAGS },
946 { "and", OP_AND, 2, 2, OPF_DATA|OPF_FLAGS },
947 { "or", OP_OR, 2, 2, OPF_DATA|OPF_FLAGS },
948 { "xor", OP_XOR, 2, 2, OPF_DATA|OPF_FLAGS },
949 { "shl", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
950 { "shr", OP_SHR, 2, 2, OPF_DATA|OPF_FLAGS },
951 { "sal", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
952 { "sar", OP_SAR, 2, 2, OPF_DATA|OPF_FLAGS },
953 { "shld", OP_SHLD, 3, 3, OPF_DATA|OPF_FLAGS },
954 { "shrd", OP_SHRD, 3, 3, OPF_DATA|OPF_FLAGS },
955 { "rol", OP_ROL, 2, 2, OPF_DATA|OPF_FLAGS },
956 { "ror", OP_ROR, 2, 2, OPF_DATA|OPF_FLAGS },
957 { "rcl", OP_RCL, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
958 { "rcr", OP_RCR, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
959 { "adc", OP_ADC, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
960 { "sbb", OP_SBB, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
961 { "bsf", OP_BSF, 2, 2, OPF_DATA|OPF_FLAGS },
962 { "inc", OP_INC, 1, 1, OPF_DATA|OPF_FLAGS },
963 { "dec", OP_DEC, 1, 1, OPF_DATA|OPF_FLAGS },
964 { "neg", OP_NEG, 1, 1, OPF_DATA|OPF_FLAGS },
965 { "mul", OP_MUL, 1, 1, OPF_DATA|OPF_FLAGS },
966 { "imul", OP_IMUL, 1, 3, OPF_DATA|OPF_FLAGS },
967 { "div", OP_DIV, 1, 1, OPF_DATA|OPF_FLAGS },
968 { "idiv", OP_IDIV, 1, 1, OPF_DATA|OPF_FLAGS },
969 { "test", OP_TEST, 2, 2, OPF_FLAGS },
970 { "cmp", OP_CMP, 2, 2, OPF_FLAGS },
971 { "retn", OP_RET, 0, 1, OPF_TAIL },
972 { "call", OP_CALL, 1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
973 { "jmp", OP_JMP, 1, 1, OPF_JMP },
974 { "jecxz",OP_JECXZ, 1, 1, OPF_JMP|OPF_CJMP },
975 { "loop", OP_LOOP, 1, 1, OPF_JMP|OPF_CJMP|OPF_DATA },
976 { "jo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 0 }, // 70 OF=1
977 { "jno", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 1 }, // 71 OF=0
978 { "jc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72 CF=1
979 { "jb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72
980 { "jnc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73 CF=0
981 { "jnb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
982 { "jae", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
983 { "jz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74 ZF=1
984 { "je", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74
985 { "jnz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75 ZF=0
986 { "jne", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75
987 { "jbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76 CF=1||ZF=1
988 { "jna", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76
989 { "ja", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77 CF=0&&ZF=0
990 { "jnbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77
991 { "js", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 0 }, // 78 SF=1
992 { "jns", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 1 }, // 79 SF=0
993 { "jp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a PF=1
994 { "jpe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a
995 { "jnp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b PF=0
996 { "jpo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b
997 { "jl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c SF!=OF
998 { "jnge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c
999 { "jge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d SF=OF
1000 { "jnl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d
1001 { "jle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e ZF=1||SF!=OF
1002 { "jng", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e
1003 { "jg", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f ZF=0&&SF=OF
1004 { "jnle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f
1005 { "seto", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 0 },
1006 { "setno", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 1 },
1007 { "setc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1008 { "setb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1009 { "setnc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1010 { "setae", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1011 { "setnb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1012 { "setz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1013 { "sete", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1014 { "setnz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1015 { "setne", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1016 { "setbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1017 { "setna", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1018 { "seta", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1019 { "setnbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1020 { "sets", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 0 },
1021 { "setns", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 1 },
1022 { "setp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1023 { "setpe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1024 { "setnp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1025 { "setpo", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1026 { "setl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1027 { "setnge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1028 { "setge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1029 { "setnl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1030 { "setle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1031 { "setng", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1032 { "setg", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1033 { "setnle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1035 { "fld", OP_FLD, 1, 1, OPF_FPUSH },
1036 { "fild", OP_FILD, 1, 1, OPF_FPUSH },
1037 { "fld1", OP_FLDc, 0, 0, OPF_FPUSH },
1038 { "fldln2", OP_FLDc, 0, 0, OPF_FPUSH },
1039 { "fldz", OP_FLDc, 0, 0, OPF_FPUSH },
1040 { "fstp", OP_FST, 1, 1, OPF_FPOP },
1041 { "fst", OP_FST, 1, 1, 0 },
1042 { "fadd", OP_FADD, 0, 2, 0 },
1043 { "faddp", OP_FADD, 0, 2, OPF_FPOP },
1044 { "fdiv", OP_FDIV, 0, 2, 0 },
1045 { "fdivp", OP_FDIV, 0, 2, OPF_FPOP },
1046 { "fmul", OP_FMUL, 0, 2, 0 },
1047 { "fmulp", OP_FMUL, 0, 2, OPF_FPOP },
1048 { "fsub", OP_FSUB, 0, 2, 0 },
1049 { "fsubp", OP_FSUB, 0, 2, OPF_FPOP },
1050 { "fdivr", OP_FDIVR, 0, 2, 0 },
1051 { "fdivrp", OP_FDIVR, 0, 2, OPF_FPOP },
1052 { "fsubr", OP_FSUBR, 0, 2, 0 },
1053 { "fsubrp", OP_FSUBR, 0, 2, OPF_FPOP },
1054 { "fiadd", OP_FIADD, 1, 1, 0 },
1055 { "fidiv", OP_FIDIV, 1, 1, 0 },
1056 { "fimul", OP_FIMUL, 1, 1, 0 },
1057 { "fisub", OP_FISUB, 1, 1, 0 },
1058 { "fidivr", OP_FIDIVR, 1, 1, 0 },
1059 { "fisubr", OP_FISUBR, 1, 1, 0 },
1060 { "fchs", OP_FCHS, 0, 0, 0 },
1061 { "fcos", OP_FCOS, 0, 0, 0 },
1062 { "fpatan", OP_FPATAN, 0, 0, OPF_FPOP },
1063 { "fptan", OP_FPTAN, 0, 0, OPF_FPUSH },
1064 { "fsin", OP_FSIN, 0, 0, 0 },
1065 { "fsqrt", OP_FSQRT, 0, 0, 0 },
1066 { "fxch", OP_FXCH, 1, 1, 0 },
1067 { "fyl2x", OP_FYL2X, 0, 0, OPF_FPOP },
1069 { "emms", OP_EMMS, 0, 0, OPF_DATA },
1070 { "movq", OP_MOV, 2, 2, OPF_DATA },
1071 // pseudo-ops for lib calls
1072 { "_ftol", OPP_FTOL },
1077 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
1079 enum opr_lenmod lmod = OPLM_UNSPEC;
1080 int prefix_flags = 0;
1088 for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
1089 if (IS(words[w], pref_table[i].name)) {
1090 prefix_flags = pref_table[i].flags;
1097 aerr("lone prefix: '%s'\n", words[0]);
1102 for (i = 0; i < ARRAY_SIZE(op_table); i++) {
1103 if (IS(words[w], op_table[i].name))
1107 if (i == ARRAY_SIZE(op_table)) {
1109 aerr("unhandled op: '%s'\n", words[0]);
1114 op->op = op_table[i].op;
1115 op->flags = op_table[i].flags | prefix_flags;
1116 op->pfo = op_table[i].pfo;
1117 op->pfo_inv = op_table[i].pfo_inv;
1118 op->regmask_src = op->regmask_dst = 0;
1121 if (op->op == OP_UD2)
1124 for (opr = 0; opr < op_table[i].maxopr; opr++) {
1125 if (opr >= op_table[i].minopr && w >= wordc)
1128 regmask = regmask_ind = 0;
1129 w = parse_operand(&op->operand[opr], ®mask, ®mask_ind,
1130 words, wordc, w, op->flags);
1132 if (opr == 0 && (op->flags & OPF_DATA))
1133 op->regmask_dst = regmask;
1135 op->regmask_src |= regmask;
1136 op->regmask_src |= regmask_ind;
1138 if (op->operand[opr].lmod != OPLM_UNSPEC)
1139 g_func_lmods |= 1 << op->operand[opr].lmod;
1143 aerr("parse_op %s incomplete: %d/%d\n",
1144 words[0], w, wordc);
1147 op->operand_cnt = opr;
1148 if (!strncmp(op_table[i].name, "set", 3))
1149 op->operand[0].lmod = OPLM_BYTE;
1152 // first operand is not dst
1155 op->regmask_src |= op->regmask_dst;
1156 op->regmask_dst = 0;
1159 // first operand is src too
1171 op->regmask_src |= op->regmask_dst;
1176 op->regmask_src |= op->regmask_dst;
1177 op->regmask_dst |= op->regmask_src;
1183 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1184 && op->operand[0].lmod == op->operand[1].lmod
1185 && op->operand[0].reg == op->operand[1].reg
1186 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1188 op->regmask_src = 0;
1191 op->regmask_src |= op->regmask_dst;
1194 // ops with implicit argumets
1196 op->operand_cnt = 2;
1197 setup_reg_opr(&op->operand[0], xAX, OPLM_BYTE, &op->regmask_src);
1198 op->regmask_dst = op->regmask_src;
1199 setup_reg_opr(&op->operand[1], xBX, OPLM_DWORD, &op->regmask_src);
1203 op->operand_cnt = 2;
1204 setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
1205 setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
1211 if (words[op_w][4] == 'b')
1213 else if (words[op_w][4] == 'w')
1215 else if (words[op_w][4] == 'd')
1218 op->regmask_src = 0;
1219 setup_reg_opr(&op->operand[j++], op->op == OP_LODS ? xSI : xDI,
1220 OPLM_DWORD, &op->regmask_src);
1221 op->regmask_dst = op->regmask_src;
1222 setup_reg_opr(&op->operand[j++], xAX, lmod,
1223 op->op == OP_LODS ? &op->regmask_dst : &op->regmask_src);
1224 if (op->flags & OPF_REP) {
1225 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1226 op->regmask_dst |= 1 << xCX;
1228 op->operand_cnt = j;
1233 if (words[op_w][4] == 'b')
1235 else if (words[op_w][4] == 'w')
1237 else if (words[op_w][4] == 'd')
1240 op->regmask_src = 0;
1241 // note: lmod is not correct, don't have where to place it
1242 setup_reg_opr(&op->operand[j++], xDI, lmod, &op->regmask_src);
1243 setup_reg_opr(&op->operand[j++], xSI, OPLM_DWORD, &op->regmask_src);
1244 if (op->flags & OPF_REP)
1245 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1246 op->operand_cnt = j;
1247 op->regmask_dst = op->regmask_src;
1251 op->regmask_dst = 1 << xCX;
1254 op->operand_cnt = 2;
1255 op->regmask_src = 1 << xCX;
1256 op->operand[1].type = OPT_REG;
1257 op->operand[1].reg = xCX;
1258 op->operand[1].lmod = OPLM_DWORD;
1262 if (op->operand_cnt == 2) {
1263 if (op->operand[0].type != OPT_REG)
1264 aerr("reg expected\n");
1265 op->regmask_src |= 1 << op->operand[0].reg;
1267 if (op->operand_cnt != 1)
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;
1280 // we could set up operands for edx:eax, but there is no real need to
1281 // (see is_opr_modified())
1282 op->regmask_src |= op->regmask_dst;
1283 op->regmask_dst = (1 << xDX) | (1 << xAX);
1284 if (op->operand[0].lmod == OPLM_UNSPEC)
1285 op->operand[0].lmod = OPLM_DWORD;
1293 op->regmask_src |= op->regmask_dst;
1294 if (op->operand[1].lmod == OPLM_UNSPEC)
1295 op->operand[1].lmod = OPLM_BYTE;
1300 op->regmask_src |= op->regmask_dst;
1301 if (op->operand[2].lmod == OPLM_UNSPEC)
1302 op->operand[2].lmod = OPLM_BYTE;
1306 op->regmask_src |= op->regmask_dst;
1307 op->regmask_dst = 0;
1308 if (op->operand[0].lmod == OPLM_UNSPEC
1309 && (op->operand[0].type == OPT_CONST
1310 || op->operand[0].type == OPT_OFFSET
1311 || op->operand[0].type == OPT_LABEL))
1312 op->operand[0].lmod = OPLM_DWORD;
1318 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1319 && op->operand[0].lmod == op->operand[1].lmod
1320 && op->operand[0].reg == op->operand[1].reg
1321 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1323 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1324 op->regmask_src = op->regmask_dst = 0;
1329 if (op->operand[0].type == OPT_REG
1330 && op->operand[1].type == OPT_REGMEM)
1333 snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1334 if (IS(buf, op->operand[1].name))
1335 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1340 // trashed regs must be explicitly detected later
1341 op->regmask_dst = 0;
1345 op->regmask_dst = (1 << xBP) | (1 << xSP);
1346 op->regmask_src = 1 << xBP;
1351 op->regmask_dst |= mxST0;
1355 op->regmask_dst |= mxST0;
1356 if (IS(words[op_w] + 3, "1"))
1357 op->operand[0].val = X87_CONST_1;
1358 else if (IS(words[op_w] + 3, "ln2"))
1359 op->operand[0].val = X87_CONST_LN2;
1360 else if (IS(words[op_w] + 3, "z"))
1361 op->operand[0].val = X87_CONST_Z;
1367 op->regmask_src |= mxST0;
1376 op->regmask_src |= mxST0;
1377 if (op->operand_cnt == 2)
1378 op->regmask_src |= op->regmask_dst;
1379 else if (op->operand_cnt == 1) {
1380 memcpy(&op->operand[1], &op->operand[0], sizeof(op->operand[1]));
1381 op->operand[0].type = OPT_REG;
1382 op->operand[0].lmod = OPLM_QWORD;
1383 op->operand[0].reg = xST0;
1384 op->regmask_dst |= mxST0;
1387 // IDA doesn't use this
1388 aerr("no operands?\n");
1402 op->regmask_src |= mxST0;
1403 op->regmask_dst |= mxST0;
1408 op->regmask_src |= mxST0 | mxST1;
1409 op->regmask_dst |= mxST0;
1420 if (op->operand[0].type == OPT_REG
1421 && op->operand[1].type == OPT_CONST)
1423 struct parsed_opr *op1 = &op->operand[1];
1424 if ((op->op == OP_AND && op1->val == 0)
1427 || (op->operand[0].lmod == OPLM_WORD && op1->val == 0xffff)
1428 || (op->operand[0].lmod == OPLM_BYTE && op1->val == 0xff))))
1430 op->regmask_src = 0;
1435 static const char *op_name(struct parsed_op *po)
1437 static char buf[16];
1441 if (po->op == OP_JCC || po->op == OP_SCC) {
1443 *p++ = (po->op == OP_JCC) ? 'j' : 's';
1446 strcpy(p, parsed_flag_op_names[po->pfo]);
1450 for (i = 0; i < ARRAY_SIZE(op_table); i++)
1451 if (op_table[i].op == po->op)
1452 return op_table[i].name;
1458 static const char *dump_op(struct parsed_op *po)
1460 static char out[128];
1467 snprintf(out, sizeof(out), "%s", op_name(po));
1468 for (i = 0; i < po->operand_cnt; i++) {
1472 snprintf(p, sizeof(out) - (p - out),
1473 po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1474 po->operand[i].name);
1480 static const char *lmod_type_u(struct parsed_op *po,
1481 enum opr_lenmod lmod)
1493 ferr(po, "invalid lmod: %d\n", lmod);
1494 return "(_invalid_)";
1498 static const char *lmod_cast_u(struct parsed_op *po,
1499 enum opr_lenmod lmod)
1511 ferr(po, "invalid lmod: %d\n", lmod);
1512 return "(_invalid_)";
1516 static const char *lmod_cast_u_ptr(struct parsed_op *po,
1517 enum opr_lenmod lmod)
1529 ferr(po, "invalid lmod: %d\n", lmod);
1530 return "(_invalid_)";
1534 static const char *lmod_cast_s(struct parsed_op *po,
1535 enum opr_lenmod lmod)
1547 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1548 return "(_invalid_)";
1552 static const char *lmod_cast(struct parsed_op *po,
1553 enum opr_lenmod lmod, int is_signed)
1556 lmod_cast_s(po, lmod) :
1557 lmod_cast_u(po, lmod);
1560 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1572 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1577 static const char *opr_name(struct parsed_op *po, int opr_num)
1579 if (opr_num >= po->operand_cnt)
1580 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1581 return po->operand[opr_num].name;
1584 static unsigned int opr_const(struct parsed_op *po, int opr_num)
1586 if (opr_num >= po->operand_cnt)
1587 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1588 if (po->operand[opr_num].type != OPT_CONST)
1589 ferr(po, "opr %d: const expected\n", opr_num);
1590 return po->operand[opr_num].val;
1593 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1595 if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
1596 ferr(po, "invalid reg: %d\n", popr->reg);
1597 return regs_r32[popr->reg];
1600 static int check_simple_cast(const char *cast, int *bits, int *is_signed)
1602 if (IS_START(cast, "(s8)") || IS_START(cast, "(u8)"))
1604 else if (IS_START(cast, "(s16)") || IS_START(cast, "(u16)"))
1606 else if (IS_START(cast, "(s32)") || IS_START(cast, "(u32)"))
1608 else if (IS_START(cast, "(s64)") || IS_START(cast, "(u64)"))
1613 *is_signed = cast[1] == 's' ? 1 : 0;
1617 static int check_deref_cast(const char *cast, int *bits)
1619 if (IS_START(cast, "*(u8 *)"))
1621 else if (IS_START(cast, "*(u16 *)"))
1623 else if (IS_START(cast, "*(u32 *)"))
1625 else if (IS_START(cast, "*(u64 *)"))
1633 // cast1 is the "final" cast
1634 static const char *simplify_cast(const char *cast1, const char *cast2)
1636 static char buf[256];
1644 if (IS(cast1, cast2))
1647 if (check_simple_cast(cast1, &bits1, &s1) == 0
1648 && check_simple_cast(cast2, &bits2, &s2) == 0)
1653 if (check_simple_cast(cast1, &bits1, &s1) == 0
1654 && check_deref_cast(cast2, &bits2) == 0)
1656 if (bits1 == bits2) {
1657 snprintf(buf, sizeof(buf), "*(%c%d *)", s1 ? 's' : 'u', bits1);
1662 if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1665 snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1669 static const char *simplify_cast_num(const char *cast, unsigned int val)
1671 if (IS(cast, "(u8)") && val < 0x100)
1673 if (IS(cast, "(s8)") && val < 0x80)
1675 if (IS(cast, "(u16)") && val < 0x10000)
1677 if (IS(cast, "(s16)") && val < 0x8000)
1679 if (IS(cast, "(s32)") && val < 0x80000000)
1685 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1694 namelen = strlen(name);
1696 p = strchr(name, '+');
1700 ferr(po, "equ parse failed for '%s'\n", name);
1702 if (IS_START(p, "0x"))
1704 *extra_offs = strtol(p, &endp, 16);
1706 ferr(po, "equ parse failed for '%s'\n", name);
1709 for (i = 0; i < g_eqcnt; i++)
1710 if (strncmp(g_eqs[i].name, name, namelen) == 0
1711 && g_eqs[i].name[namelen] == 0)
1715 ferr(po, "unresolved equ name: '%s'\n", name);
1722 static int is_stack_access(struct parsed_op *po,
1723 const struct parsed_opr *popr)
1725 return (parse_stack_el(popr->name, NULL, 0)
1726 || (g_bp_frame && !(po->flags & OPF_EBP_S)
1727 && IS_START(popr->name, "ebp")));
1730 static void parse_stack_access(struct parsed_op *po,
1731 const char *name, char *ofs_reg, int *offset_out,
1732 int *stack_ra_out, const char **bp_arg_out, int is_lea)
1734 const char *bp_arg = "";
1735 const char *p = NULL;
1736 struct parsed_equ *eq;
1743 if (IS_START(name, "ebp-")
1744 || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1747 if (IS_START(p, "0x"))
1749 offset = strtoul(p, &endp, 16);
1753 ferr(po, "ebp- parse of '%s' failed\n", name);
1756 bp_arg = parse_stack_el(name, ofs_reg, 0);
1757 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1758 eq = equ_find(po, bp_arg, &offset);
1760 ferr(po, "detected but missing eq\n");
1761 offset += eq->offset;
1764 if (!strncmp(name, "ebp", 3))
1767 // yes it sometimes LEAs ra for compares..
1768 if (!is_lea && ofs_reg[0] == 0
1769 && stack_ra <= offset && offset < stack_ra + 4)
1771 ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1774 *offset_out = offset;
1775 *stack_ra_out = stack_ra;
1777 *bp_arg_out = bp_arg;
1780 static int stack_frame_access(struct parsed_op *po,
1781 struct parsed_opr *popr, char *buf, size_t buf_size,
1782 const char *name, const char *cast, int is_src, int is_lea)
1784 enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1785 const char *prefix = "";
1786 const char *bp_arg = NULL;
1787 char ofs_reg[16] = { 0, };
1788 int i, arg_i, arg_s;
1796 if (po->flags & OPF_EBP_S)
1797 ferr(po, "stack_frame_access while ebp is scratch\n");
1799 parse_stack_access(po, name, ofs_reg, &offset,
1800 &stack_ra, &bp_arg, is_lea);
1802 if (offset > stack_ra)
1804 arg_i = (offset - stack_ra - 4) / 4;
1805 if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1807 if (g_func_pp->is_vararg
1808 && arg_i == g_func_pp->argc_stack && is_lea)
1810 // should be va_list
1813 snprintf(buf, buf_size, "%sap", cast);
1816 ferr(po, "offset %d (%s,%d) doesn't map to any arg\n",
1817 offset, bp_arg, arg_i);
1819 if (ofs_reg[0] != 0)
1820 ferr(po, "offset reg on arg access?\n");
1822 for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1823 if (g_func_pp->arg[i].reg != NULL)
1829 if (i == g_func_pp->argc)
1830 ferr(po, "arg %d not in prototype?\n", arg_i);
1832 popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
1839 ferr(po, "lea/byte to arg?\n");
1840 if (is_src && (offset & 3) == 0)
1841 snprintf(buf, buf_size, "%sa%d",
1842 simplify_cast(cast, "(u8)"), i + 1);
1844 snprintf(buf, buf_size, "%sBYTE%d(a%d)",
1845 cast, offset & 3, i + 1);
1850 ferr(po, "lea/word to arg?\n");
1855 ferr(po, "problematic arg store\n");
1856 snprintf(buf, buf_size, "%s((char *)&a%d + 1)",
1857 simplify_cast(cast, "*(u16 *)"), i + 1);
1860 ferr(po, "unaligned arg word load\n");
1862 else if (is_src && (offset & 2) == 0)
1863 snprintf(buf, buf_size, "%sa%d",
1864 simplify_cast(cast, "(u16)"), i + 1);
1866 snprintf(buf, buf_size, "%s%sWORD(a%d)",
1867 cast, (offset & 2) ? "HI" : "LO", i + 1);
1879 snprintf(buf, buf_size, "(u32)&a%d + %d",
1882 ferr(po, "unaligned arg store\n");
1884 // mov edx, [ebp+arg_4+2]; movsx ecx, dx
1885 snprintf(buf, buf_size, "%s(a%d >> %d)",
1886 prefix, i + 1, (offset & 3) * 8);
1890 snprintf(buf, buf_size, "%s%sa%d",
1891 prefix, is_lea ? "&" : "", i + 1);
1896 ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
1900 snprintf(g_comment, sizeof(g_comment), "%s unaligned", bp_arg);
1903 guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
1904 if (tmp_lmod != OPLM_DWORD
1905 && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
1906 < lmod_bytes(po, popr->lmod) + (offset & 3))))
1908 ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
1909 i + 1, offset, g_func_pp->arg[i].type.name);
1911 // can't check this because msvc likes to reuse
1912 // arg space for scratch..
1913 //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
1914 // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
1918 if (g_stack_fsz == 0)
1919 ferr(po, "stack var access without stackframe\n");
1920 g_stack_frame_used = 1;
1922 sf_ofs = g_stack_fsz + offset;
1923 lim = (ofs_reg[0] != 0) ? -4 : 0;
1924 if (offset > 0 || sf_ofs < lim)
1925 ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
1935 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1936 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1940 if ((sf_ofs & 1) || ofs_reg[0] != 0) {
1941 // known unaligned or possibly unaligned
1942 strcat(g_comment, " unaligned");
1944 prefix = "*(u16 *)&";
1945 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1946 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1949 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
1953 if ((sf_ofs & 3) || ofs_reg[0] != 0) {
1954 // known unaligned or possibly unaligned
1955 strcat(g_comment, " unaligned");
1957 prefix = "*(u32 *)&";
1958 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1959 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1962 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
1966 ferr_assert(po, !(sf_ofs & 7));
1967 ferr_assert(po, ofs_reg[0] == 0);
1968 // float callers set is_lea
1969 ferr_assert(po, is_lea);
1970 snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
1974 ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
1981 static void check_func_pp(struct parsed_op *po,
1982 const struct parsed_proto *pp, const char *pfx)
1984 enum opr_lenmod tmp_lmod;
1988 if (pp->argc_reg != 0) {
1989 if (/*!g_allow_regfunc &&*/ !pp->is_fastcall) {
1990 pp_print(buf, sizeof(buf), pp);
1991 ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
1993 if (pp->argc_stack > 0 && pp->argc_reg != 2)
1994 ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
1995 pfx, pp->argc_reg, pp->argc_stack);
1998 // fptrs must use 32bit args, callsite might have no information and
1999 // lack a cast to smaller types, which results in incorrectly masked
2000 // args passed (callee may assume masked args, it does on ARM)
2001 if (!pp->is_osinc) {
2002 for (i = 0; i < pp->argc; i++) {
2003 ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
2004 if (ret && tmp_lmod != OPLM_DWORD)
2005 ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
2006 i + 1, pp->arg[i].type.name);
2011 static const char *check_label_read_ref(struct parsed_op *po,
2014 const struct parsed_proto *pp;
2016 pp = proto_parse(g_fhdr, name, 0);
2018 ferr(po, "proto_parse failed for ref '%s'\n", name);
2021 check_func_pp(po, pp, "ref");
2026 static char *out_src_opr(char *buf, size_t buf_size,
2027 struct parsed_op *po, struct parsed_opr *popr, const char *cast,
2030 char tmp1[256], tmp2[256];
2039 switch (popr->type) {
2042 ferr(po, "lea from reg?\n");
2044 switch (popr->lmod) {
2046 snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2049 snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2052 snprintf(buf, buf_size, "%s%s",
2053 simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2056 if (popr->name[1] == 'h') // XXX..
2057 snprintf(buf, buf_size, "%s(%s >> 8)",
2058 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2060 snprintf(buf, buf_size, "%s%s",
2061 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2064 ferr(po, "invalid src lmod: %d\n", popr->lmod);
2069 if (is_stack_access(po, popr)) {
2070 stack_frame_access(po, popr, buf, buf_size,
2071 popr->name, cast, 1, is_lea);
2075 strcpy(expr, popr->name);
2076 if (strchr(expr, '[')) {
2077 // special case: '[' can only be left for label[reg] form
2078 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2080 ferr(po, "parse failure for '%s'\n", expr);
2081 if (tmp1[0] == '(') {
2082 // (off_4FFF50+3)[eax]
2083 p = strchr(tmp1 + 1, ')');
2084 if (p == NULL || p[1] != 0)
2085 ferr(po, "parse failure (2) for '%s'\n", expr);
2087 memmove(tmp1, tmp1 + 1, strlen(tmp1));
2089 snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2092 // XXX: do we need more parsing?
2094 snprintf(buf, buf_size, "%s", expr);
2098 snprintf(buf, buf_size, "%s(%s)",
2099 simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2103 name = check_label_read_ref(po, popr->name);
2104 if (cast[0] == 0 && popr->is_ptr)
2108 snprintf(buf, buf_size, "(u32)&%s", name);
2109 else if (popr->size_lt)
2110 snprintf(buf, buf_size, "%s%s%s%s", cast,
2111 lmod_cast_u_ptr(po, popr->lmod),
2112 popr->is_array ? "" : "&", name);
2114 snprintf(buf, buf_size, "%s%s%s", cast, name,
2115 popr->is_array ? "[0]" : "");
2119 name = check_label_read_ref(po, popr->name);
2123 ferr(po, "lea an offset?\n");
2124 snprintf(buf, buf_size, "%s&%s", cast, name);
2129 ferr(po, "lea from const?\n");
2131 printf_number(tmp1, sizeof(tmp1), popr->val);
2132 if (popr->val == 0 && strchr(cast, '*'))
2133 snprintf(buf, buf_size, "NULL");
2135 snprintf(buf, buf_size, "%s%s",
2136 simplify_cast_num(cast, popr->val), tmp1);
2140 ferr(po, "invalid src type: %d\n", popr->type);
2146 // note: may set is_ptr (we find that out late for ebp frame..)
2147 static char *out_dst_opr(char *buf, size_t buf_size,
2148 struct parsed_op *po, struct parsed_opr *popr)
2150 switch (popr->type) {
2152 switch (popr->lmod) {
2154 snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2157 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2161 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2165 if (popr->name[1] == 'h') // XXX..
2166 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2168 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2171 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2176 if (is_stack_access(po, popr)) {
2177 stack_frame_access(po, popr, buf, buf_size,
2178 popr->name, "", 0, 0);
2182 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2185 if (popr->size_mismatch)
2186 snprintf(buf, buf_size, "%s%s%s",
2187 lmod_cast_u_ptr(po, popr->lmod),
2188 popr->is_array ? "" : "&", popr->name);
2190 snprintf(buf, buf_size, "%s%s", popr->name,
2191 popr->is_array ? "[0]" : "");
2195 ferr(po, "invalid dst type: %d\n", popr->type);
2201 static char *out_src_opr_u32(char *buf, size_t buf_size,
2202 struct parsed_op *po, struct parsed_opr *popr)
2204 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2207 static char *out_src_opr_float(char *buf, size_t buf_size,
2208 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2210 const char *cast = NULL;
2213 switch (popr->type) {
2215 if (popr->reg < xST0 || popr->reg > xST7)
2216 ferr(po, "bad reg: %d\n", popr->reg);
2218 if (need_float_stack) {
2219 if (popr->reg == xST0)
2220 snprintf(buf, buf_size, "f_st[f_stp & 7]");
2222 snprintf(buf, buf_size, "f_st[(f_stp + %d) & 7]",
2226 snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2232 switch (popr->lmod) {
2240 ferr(po, "unhandled lmod: %d\n", popr->lmod);
2243 out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2244 snprintf(buf, buf_size, "*((%s *)%s)", cast, tmp);
2248 ferr(po, "invalid float type: %d\n", popr->type);
2254 static char *out_dst_opr_float(char *buf, size_t buf_size,
2255 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2258 return out_src_opr_float(buf, buf_size, po, popr, need_float_stack);
2261 static void out_test_for_cc(char *buf, size_t buf_size,
2262 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2263 enum opr_lenmod lmod, const char *expr)
2265 const char *cast, *scast;
2267 cast = lmod_cast_u(po, lmod);
2268 scast = lmod_cast_s(po, lmod);
2272 case PFO_BE: // CF=1||ZF=1; CF=0
2273 snprintf(buf, buf_size, "(%s%s %s 0)",
2274 cast, expr, is_inv ? "!=" : "==");
2278 case PFO_L: // SF!=OF; OF=0
2279 snprintf(buf, buf_size, "(%s%s %s 0)",
2280 scast, expr, is_inv ? ">=" : "<");
2283 case PFO_LE: // ZF=1||SF!=OF; OF=0
2284 snprintf(buf, buf_size, "(%s%s %s 0)",
2285 scast, expr, is_inv ? ">" : "<=");
2289 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2293 static void out_cmp_for_cc(char *buf, size_t buf_size,
2294 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2296 const char *cast, *scast, *cast_use;
2297 char buf1[256], buf2[256];
2298 enum opr_lenmod lmod;
2300 if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2301 ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2302 po->operand[0].lmod, po->operand[1].lmod);
2303 lmod = po->operand[0].lmod;
2305 cast = lmod_cast_u(po, lmod);
2306 scast = lmod_cast_s(po, lmod);
2322 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2325 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2326 if (po->op == OP_DEC)
2327 snprintf(buf2, sizeof(buf2), "1");
2329 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_use, 0);
2333 // note: must be unsigned compare
2334 snprintf(buf, buf_size, "(%s %s %s)",
2335 buf1, is_inv ? ">=" : "<", buf2);
2339 snprintf(buf, buf_size, "(%s %s %s)",
2340 buf1, is_inv ? "!=" : "==", buf2);
2344 // note: must be unsigned compare
2345 snprintf(buf, buf_size, "(%s %s %s)",
2346 buf1, is_inv ? ">" : "<=", buf2);
2349 if (is_inv && lmod == OPLM_BYTE
2350 && po->operand[1].type == OPT_CONST
2351 && po->operand[1].val == 0xff)
2353 snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2354 snprintf(buf, buf_size, "(0)");
2358 // note: must be signed compare
2360 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2361 scast, buf1, buf2, is_inv ? ">=" : "<");
2365 snprintf(buf, buf_size, "(%s %s %s)",
2366 buf1, is_inv ? ">=" : "<", buf2);
2370 snprintf(buf, buf_size, "(%s %s %s)",
2371 buf1, is_inv ? ">" : "<=", buf2);
2379 static void out_cmp_test(char *buf, size_t buf_size,
2380 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2382 char buf1[256], buf2[256], buf3[256];
2384 if (po->op == OP_TEST) {
2385 if (IS(opr_name(po, 0), opr_name(po, 1))) {
2386 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2389 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2390 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2391 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2393 out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2394 po->operand[0].lmod, buf3);
2396 else if (po->op == OP_CMP) {
2397 out_cmp_for_cc(buf, buf_size, po, pfo, is_inv);
2400 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2403 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2404 struct parsed_opr *popr2)
2406 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2407 ferr(po, "missing lmod for both operands\n");
2409 if (popr1->lmod == OPLM_UNSPEC)
2410 popr1->lmod = popr2->lmod;
2411 else if (popr2->lmod == OPLM_UNSPEC)
2412 popr2->lmod = popr1->lmod;
2413 else if (popr1->lmod != popr2->lmod) {
2414 if (popr1->type_from_var) {
2415 popr1->size_mismatch = 1;
2416 if (popr1->lmod < popr2->lmod)
2418 popr1->lmod = popr2->lmod;
2420 else if (popr2->type_from_var) {
2421 popr2->size_mismatch = 1;
2422 if (popr2->lmod < popr1->lmod)
2424 popr2->lmod = popr1->lmod;
2427 ferr(po, "conflicting lmods: %d vs %d\n",
2428 popr1->lmod, popr2->lmod);
2432 static const char *op_to_c(struct parsed_op *po)
2456 ferr(po, "op_to_c was supplied with %d\n", po->op);
2460 // last op in stream - unconditional branch or ret
2461 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2462 || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2463 && ops[_i].op != OP_CALL))
2465 #define check_i(po, i) \
2467 ferr(po, "bad " #i ": %d\n", i)
2469 // note: this skips over calls and rm'd stuff assuming they're handled
2470 // so it's intended to use at one of final passes
2471 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2472 int depth, int flags_set)
2474 struct parsed_op *po;
2479 for (; i < opcnt; i++) {
2481 if (po->cc_scratch == magic)
2482 return ret; // already checked
2483 po->cc_scratch = magic;
2485 if (po->flags & OPF_TAIL) {
2486 if (po->op == OP_CALL) {
2487 if (po->pp != NULL && po->pp->is_noreturn)
2488 // assume no stack cleanup for noreturn
2491 return -1; // deadend
2494 if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
2497 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2498 if (po->btj != NULL) {
2500 for (j = 0; j < po->btj->count; j++) {
2501 check_i(po, po->btj->d[j].bt_i);
2502 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2505 return ret; // dead end
2510 check_i(po, po->bt_i);
2511 if (po->flags & OPF_CJMP) {
2512 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2515 return ret; // dead end
2524 if ((po->op == OP_POP || po->op == OP_PUSH)
2525 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2530 if (po->op == OP_PUSH) {
2533 else if (po->op == OP_POP) {
2534 if (relevant && depth == 0) {
2535 po->flags |= flags_set;
2545 // scan for 'reg' pop backwards starting from i
2546 // intended to use for register restore search, so other reg
2547 // references are considered an error
2548 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2550 struct parsed_op *po;
2551 struct label_ref *lr;
2554 ops[i].cc_scratch = magic;
2558 if (g_labels[i] != NULL) {
2559 lr = &g_label_refs[i];
2560 for (; lr != NULL; lr = lr->next) {
2561 check_i(&ops[i], lr->i);
2562 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2566 if (i > 0 && LAST_OP(i - 1))
2574 if (ops[i].cc_scratch == magic)
2576 ops[i].cc_scratch = magic;
2579 if (po->op == OP_POP && po->operand[0].reg == reg) {
2580 if (po->flags & (OPF_RMD|OPF_DONE))
2583 po->flags |= set_flags;
2587 // this also covers the case where we reach corresponding push
2588 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2592 // nothing interesting on this path
2596 static void find_reachable_exits(int i, int opcnt, int magic,
2597 int *exits, int *exit_count)
2599 struct parsed_op *po;
2602 for (; i < opcnt; i++)
2605 if (po->cc_scratch == magic)
2607 po->cc_scratch = magic;
2609 if (po->flags & OPF_TAIL) {
2610 ferr_assert(po, *exit_count < MAX_EXITS);
2611 exits[*exit_count] = i;
2616 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2617 if (po->flags & OPF_RMD)
2620 if (po->btj != NULL) {
2621 for (j = 0; j < po->btj->count; j++) {
2622 check_i(po, po->btj->d[j].bt_i);
2623 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2629 check_i(po, po->bt_i);
2630 if (po->flags & OPF_CJMP)
2631 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2639 // scan for 'reg' pop backwards starting from exits (all paths)
2640 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2642 static int exits[MAX_EXITS];
2643 static int exit_count;
2648 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2650 ferr_assert(&ops[i], exit_count > 0);
2653 for (j = 0; j < exit_count; j++) {
2654 ret = scan_for_rsave_pop_reg(exits[j], i + opcnt * 16 + set_flags,
2663 // scan for one or more pop of push <const>
2664 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2665 int push_i, int is_probe)
2667 struct parsed_op *po;
2668 struct label_ref *lr;
2672 for (; i < opcnt; i++)
2675 if (po->cc_scratch == magic)
2676 return ret; // already checked
2677 po->cc_scratch = magic;
2679 if (po->flags & OPF_JMP) {
2680 if (po->flags & OPF_RMD)
2682 if (po->op == OP_CALL)
2685 if (po->btj != NULL) {
2686 for (j = 0; j < po->btj->count; j++) {
2687 check_i(po, po->btj->d[j].bt_i);
2688 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2696 check_i(po, po->bt_i);
2697 if (po->flags & OPF_CJMP) {
2698 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2709 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2712 if (g_labels[i] != NULL) {
2713 // all refs must be visited
2714 lr = &g_label_refs[i];
2715 for (; lr != NULL; lr = lr->next) {
2717 if (ops[lr->i].cc_scratch != magic)
2720 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2724 if (po->op == OP_POP)
2726 if (po->flags & (OPF_RMD|OPF_DONE))
2730 po->flags |= OPF_DONE;
2731 po->datap = &ops[push_i];
2740 static void scan_for_pop_const(int i, int opcnt, int magic)
2744 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
2746 ops[i].flags |= OPF_RMD | OPF_DONE;
2747 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
2751 // check if all branch targets within a marked path are also marked
2752 // note: the path checked must not be empty or end with a branch
2753 static int check_path_branches(int opcnt, int magic)
2755 struct parsed_op *po;
2758 for (i = 0; i < opcnt; i++) {
2760 if (po->cc_scratch != magic)
2763 if (po->flags & OPF_JMP) {
2764 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
2767 if (po->btj != NULL) {
2768 for (j = 0; j < po->btj->count; j++) {
2769 check_i(po, po->btj->d[j].bt_i);
2770 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
2775 check_i(po, po->bt_i);
2776 if (ops[po->bt_i].cc_scratch != magic)
2778 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
2786 // scan for multiple pushes for given pop
2787 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
2790 int reg = ops[pop_i].operand[0].reg;
2791 struct parsed_op *po;
2792 struct label_ref *lr;
2795 ops[i].cc_scratch = magic;
2799 if (g_labels[i] != NULL) {
2800 lr = &g_label_refs[i];
2801 for (; lr != NULL; lr = lr->next) {
2802 check_i(&ops[i], lr->i);
2803 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
2807 if (i > 0 && LAST_OP(i - 1))
2815 if (ops[i].cc_scratch == magic)
2817 ops[i].cc_scratch = magic;
2820 if (po->op == OP_CALL)
2822 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
2825 if (po->op == OP_PUSH)
2827 if (po->datap != NULL)
2829 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2830 // leave this case for reg save/restore handlers
2834 po->flags |= OPF_PPUSH | OPF_DONE;
2835 po->datap = &ops[pop_i];
2844 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
2846 int magic = i + opcnt * 14;
2849 ret = scan_pushes_for_pop_r(i, magic, i, 1);
2851 ret = check_path_branches(opcnt, magic);
2853 ops[i].flags |= OPF_PPUSH | OPF_DONE;
2854 *regmask_pp |= 1 << ops[i].operand[0].reg;
2855 scan_pushes_for_pop_r(i, magic + 1, i, 0);
2860 static void scan_propagate_df(int i, int opcnt)
2862 struct parsed_op *po = &ops[i];
2865 for (; i < opcnt; i++) {
2867 if (po->flags & OPF_DF)
2868 return; // already resolved
2869 po->flags |= OPF_DF;
2871 if (po->op == OP_CALL)
2872 ferr(po, "call with DF set?\n");
2874 if (po->flags & OPF_JMP) {
2875 if (po->btj != NULL) {
2877 for (j = 0; j < po->btj->count; j++) {
2878 check_i(po, po->btj->d[j].bt_i);
2879 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
2884 if (po->flags & OPF_RMD)
2886 check_i(po, po->bt_i);
2887 if (po->flags & OPF_CJMP)
2888 scan_propagate_df(po->bt_i, opcnt);
2894 if (po->flags & OPF_TAIL)
2897 if (po->op == OP_CLD) {
2898 po->flags |= OPF_RMD | OPF_DONE;
2903 ferr(po, "missing DF clear?\n");
2906 // is operand 'opr' referenced by parsed_op 'po'?
2907 static int is_opr_referenced(const struct parsed_opr *opr,
2908 const struct parsed_op *po)
2912 if (opr->type == OPT_REG) {
2913 mask = po->regmask_dst | po->regmask_src;
2914 if (po->op == OP_CALL)
2915 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
2916 if ((1 << opr->reg) & mask)
2922 for (i = 0; i < po->operand_cnt; i++)
2923 if (IS(po->operand[0].name, opr->name))
2929 // is operand 'opr' read by parsed_op 'po'?
2930 static int is_opr_read(const struct parsed_opr *opr,
2931 const struct parsed_op *po)
2933 if (opr->type == OPT_REG) {
2934 if (po->regmask_src & (1 << opr->reg))
2944 // is operand 'opr' modified by parsed_op 'po'?
2945 static int is_opr_modified(const struct parsed_opr *opr,
2946 const struct parsed_op *po)
2950 if (opr->type == OPT_REG) {
2951 if (po->op == OP_CALL) {
2952 mask = po->regmask_dst;
2953 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
2954 if (mask & (1 << opr->reg))
2960 if (po->regmask_dst & (1 << opr->reg))
2966 return IS(po->operand[0].name, opr->name);
2969 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
2970 static int is_any_opr_modified(const struct parsed_op *po_test,
2971 const struct parsed_op *po, int c_mode)
2976 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
2979 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
2982 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
2985 // in reality, it can wreck any register, but in decompiled C
2986 // version it can only overwrite eax or edx:eax
2987 mask = (1 << xAX) | (1 << xDX);
2991 if (po->op == OP_CALL
2992 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
2995 for (i = 0; i < po_test->operand_cnt; i++)
2996 if (IS(po_test->operand[i].name, po->operand[0].name))
3002 // scan for any po_test operand modification in range given
3003 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
3006 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3009 for (; i < opcnt; i++) {
3010 if (is_any_opr_modified(po_test, &ops[i], c_mode))
3017 // scan for po_test operand[0] modification in range given
3018 static int scan_for_mod_opr0(struct parsed_op *po_test,
3021 for (; i < opcnt; i++) {
3022 if (is_opr_modified(&po_test->operand[0], &ops[i]))
3029 static int scan_for_flag_set(int i, int magic, int *branched,
3030 int *setters, int *setter_cnt)
3032 struct label_ref *lr;
3036 if (ops[i].cc_scratch == magic) {
3037 // is this a problem?
3038 //ferr(&ops[i], "%s looped\n", __func__);
3041 ops[i].cc_scratch = magic;
3043 if (g_labels[i] != NULL) {
3046 lr = &g_label_refs[i];
3047 for (; lr->next; lr = lr->next) {
3048 check_i(&ops[i], lr->i);
3049 ret = scan_for_flag_set(lr->i, magic,
3050 branched, setters, setter_cnt);
3055 check_i(&ops[i], lr->i);
3056 if (i > 0 && LAST_OP(i - 1)) {
3060 ret = scan_for_flag_set(lr->i, magic,
3061 branched, setters, setter_cnt);
3067 if (ops[i].flags & OPF_FLAGS) {
3068 setters[*setter_cnt] = i;
3073 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3080 // scan back for cdq, if anything modifies edx, fail
3081 static int scan_for_cdq_edx(int i)
3084 if (g_labels[i] != NULL) {
3085 if (g_label_refs[i].next != NULL)
3087 if (i > 0 && LAST_OP(i - 1)) {
3088 i = g_label_refs[i].i;
3095 if (ops[i].op == OP_CDQ)
3098 if (ops[i].regmask_dst & (1 << xDX))
3105 static int scan_for_reg_clear(int i, int reg)
3108 if (g_labels[i] != NULL) {
3109 if (g_label_refs[i].next != NULL)
3111 if (i > 0 && LAST_OP(i - 1)) {
3112 i = g_label_refs[i].i;
3119 if (ops[i].op == OP_XOR
3120 && ops[i].operand[0].lmod == OPLM_DWORD
3121 && ops[i].operand[0].reg == ops[i].operand[1].reg
3122 && ops[i].operand[0].reg == reg)
3125 if (ops[i].regmask_dst & (1 << reg))
3132 static void patch_esp_adjust(struct parsed_op *po, int adj)
3134 ferr_assert(po, po->op == OP_ADD);
3135 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3136 ferr_assert(po, po->operand[1].type == OPT_CONST);
3138 // this is a bit of a hack, but deals with use of
3139 // single adj for multiple calls
3140 po->operand[1].val -= adj;
3141 po->flags |= OPF_RMD;
3142 if (po->operand[1].val == 0)
3143 po->flags |= OPF_DONE;
3144 ferr_assert(po, (int)po->operand[1].val >= 0);
3147 // scan for positive, constant esp adjust
3148 // multipath case is preliminary
3149 static int scan_for_esp_adjust(int i, int opcnt,
3150 int adj_expect, int *adj, int *is_multipath, int do_update)
3152 int adj_expect_unknown = 0;
3153 struct parsed_op *po;
3157 *adj = *is_multipath = 0;
3158 if (adj_expect < 0) {
3159 adj_expect_unknown = 1;
3160 adj_expect = 32 * 4; // enough?
3163 for (; i < opcnt && *adj < adj_expect; i++) {
3164 if (g_labels[i] != NULL)
3168 if (po->flags & OPF_DONE)
3171 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3172 if (po->operand[1].type != OPT_CONST)
3173 ferr(&ops[i], "non-const esp adjust?\n");
3174 *adj += po->operand[1].val;
3176 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3179 patch_esp_adjust(po, adj_expect);
3181 po->flags |= OPF_RMD;
3185 else if (po->op == OP_PUSH) {
3186 //if (first_pop == -1)
3187 // first_pop = -2; // none
3188 *adj -= lmod_bytes(po, po->operand[0].lmod);
3190 else if (po->op == OP_POP) {
3191 if (!(po->flags & OPF_DONE)) {
3192 // seems like msvc only uses 'pop ecx' for stack realignment..
3193 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3195 if (first_pop == -1 && *adj >= 0)
3198 if (do_update && *adj >= 0) {
3199 po->flags |= OPF_RMD;
3201 po->flags |= OPF_DONE | OPF_NOREGS;
3204 *adj += lmod_bytes(po, po->operand[0].lmod);
3205 if (*adj > adj_best)
3208 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3209 if (po->op == OP_JMP && po->btj == NULL) {
3215 if (po->op != OP_CALL)
3217 if (po->operand[0].type != OPT_LABEL)
3219 if (po->pp != NULL && po->pp->is_stdcall)
3221 if (adj_expect_unknown && first_pop >= 0)
3223 // assume it's another cdecl call
3227 if (first_pop >= 0) {
3228 // probably only 'pop ecx' was used
3236 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3238 struct parsed_op *po;
3242 ferr(ops, "%s: followed bad branch?\n", __func__);
3244 for (; i < opcnt; i++) {
3246 if (po->cc_scratch == magic)
3248 po->cc_scratch = magic;
3251 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3252 if (po->btj != NULL) {
3254 for (j = 0; j < po->btj->count; j++)
3255 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3259 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3260 if (!(po->flags & OPF_CJMP))
3263 if (po->flags & OPF_TAIL)
3268 static const struct parsed_proto *try_recover_pp(
3269 struct parsed_op *po, const struct parsed_opr *opr, int *search_instead)
3271 const struct parsed_proto *pp = NULL;
3275 // maybe an arg of g_func?
3276 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3278 char ofs_reg[16] = { 0, };
3279 int arg, arg_s, arg_i;
3286 parse_stack_access(po, opr->name, ofs_reg,
3287 &offset, &stack_ra, NULL, 0);
3288 if (ofs_reg[0] != 0)
3289 ferr(po, "offset reg on arg access?\n");
3290 if (offset <= stack_ra) {
3291 // search who set the stack var instead
3292 if (search_instead != NULL)
3293 *search_instead = 1;
3297 arg_i = (offset - stack_ra - 4) / 4;
3298 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3299 if (g_func_pp->arg[arg].reg != NULL)
3305 if (arg == g_func_pp->argc)
3306 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3308 pp = g_func_pp->arg[arg].fptr;
3310 ferr(po, "icall sa: arg%d is not a fptr?\n", arg + 1);
3311 check_func_pp(po, pp, "icall arg");
3313 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3315 p = strchr(opr->name + 1, '[');
3316 memcpy(buf, opr->name, p - opr->name);
3317 buf[p - opr->name] = 0;
3318 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3320 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3321 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3324 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3327 check_func_pp(po, pp, "reg-fptr ref");
3333 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3334 int magic, const struct parsed_proto **pp_found, int *pp_i,
3337 const struct parsed_proto *pp = NULL;
3338 struct parsed_op *po;
3339 struct label_ref *lr;
3341 ops[i].cc_scratch = magic;
3344 if (g_labels[i] != NULL) {
3345 lr = &g_label_refs[i];
3346 for (; lr != NULL; lr = lr->next) {
3347 check_i(&ops[i], lr->i);
3348 scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3350 if (i > 0 && LAST_OP(i - 1))
3358 if (ops[i].cc_scratch == magic)
3360 ops[i].cc_scratch = magic;
3362 if (!(ops[i].flags & OPF_DATA))
3364 if (!is_opr_modified(opr, &ops[i]))
3366 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3367 // most probably trashed by some processing
3372 opr = &ops[i].operand[1];
3373 if (opr->type != OPT_REG)
3377 po = (i >= 0) ? &ops[i] : ops;
3380 // reached the top - can only be an arg-reg
3381 if (opr->type != OPT_REG || g_func_pp == NULL)
3384 for (i = 0; i < g_func_pp->argc; i++) {
3385 if (g_func_pp->arg[i].reg == NULL)
3387 if (IS(opr->name, g_func_pp->arg[i].reg))
3390 if (i == g_func_pp->argc)
3392 pp = g_func_pp->arg[i].fptr;
3394 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3395 i + 1, g_func_pp->arg[i].reg);
3396 check_func_pp(po, pp, "icall reg-arg");
3399 pp = try_recover_pp(po, opr, NULL);
3401 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3402 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3403 || (*pp_found)->is_stdcall != pp->is_stdcall
3404 || (*pp_found)->is_fptr != pp->is_fptr
3405 || (*pp_found)->argc != pp->argc
3406 || (*pp_found)->argc_reg != pp->argc_reg
3407 || (*pp_found)->argc_stack != pp->argc_stack)
3409 ferr(po, "icall: parsed_proto mismatch\n");
3419 static void add_label_ref(struct label_ref *lr, int op_i)
3421 struct label_ref *lr_new;
3428 lr_new = calloc(1, sizeof(*lr_new));
3430 lr_new->next = lr->next;
3434 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3436 struct parsed_op *po = &ops[i];
3437 struct parsed_data *pd;
3438 char label[NAMELEN], *p;
3441 p = strchr(po->operand[0].name, '[');
3445 len = p - po->operand[0].name;
3446 strncpy(label, po->operand[0].name, len);
3449 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3450 if (IS(g_func_pd[j].label, label)) {
3456 //ferr(po, "label '%s' not parsed?\n", label);
3459 if (pd->type != OPT_OFFSET)
3460 ferr(po, "label '%s' with non-offset data?\n", label);
3462 // find all labels, link
3463 for (j = 0; j < pd->count; j++) {
3464 for (l = 0; l < opcnt; l++) {
3465 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3466 add_label_ref(&g_label_refs[l], i);
3476 static void clear_labels(int count)
3480 for (i = 0; i < count; i++) {
3481 if (g_labels[i] != NULL) {
3488 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3493 for (i = 0; i < pp->argc; i++) {
3494 if (pp->arg[i].reg != NULL) {
3495 reg = char_array_i(regs_r32,
3496 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3498 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3499 pp->arg[i].reg, pp->name);
3500 regmask |= 1 << reg;
3507 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3512 if (pp->has_retreg) {
3513 for (i = 0; i < pp->argc; i++) {
3514 if (pp->arg[i].type.is_retreg) {
3515 reg = char_array_i(regs_r32,
3516 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3517 ferr_assert(ops, reg >= 0);
3518 regmask |= 1 << reg;
3523 if (strstr(pp->ret_type.name, "int64"))
3524 return regmask | (1 << xAX) | (1 << xDX);
3525 if (IS(pp->ret_type.name, "float")
3526 || IS(pp->ret_type.name, "double"))
3528 return regmask | mxST0;
3530 if (strcasecmp(pp->ret_type.name, "void") == 0)
3533 return regmask | mxAX;
3536 static void resolve_branches_parse_calls(int opcnt)
3538 static const struct {
3542 unsigned int regmask_src;
3543 unsigned int regmask_dst;
3545 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3547 const struct parsed_proto *pp_c;
3548 struct parsed_proto *pp;
3549 struct parsed_data *pd;
3550 struct parsed_op *po;
3551 const char *tmpname;
3555 for (i = 0; i < opcnt; i++)
3561 if (po->datap != NULL) {
3562 pp = calloc(1, sizeof(*pp));
3563 my_assert_not(pp, NULL);
3565 ret = parse_protostr(po->datap, pp);
3567 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3573 if (po->op == OP_CALL) {
3578 else if (po->operand[0].type == OPT_LABEL)
3580 tmpname = opr_name(po, 0);
3581 if (IS_START(tmpname, "loc_"))
3582 ferr(po, "call to loc_*\n");
3584 // convert some calls to pseudo-ops
3585 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3586 if (!IS(tmpname, pseudo_ops[l].name))
3589 po->op = pseudo_ops[l].op;
3590 po->operand_cnt = 0;
3591 po->regmask_src = pseudo_ops[l].regmask_src;
3592 po->regmask_dst = pseudo_ops[l].regmask_dst;
3593 po->flags = pseudo_ops[l].flags;
3594 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3597 if (l < ARRAY_SIZE(pseudo_ops))
3600 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3601 if (!g_header_mode && pp_c == NULL)
3602 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3605 pp = proto_clone(pp_c);
3606 my_assert_not(pp, NULL);
3612 check_func_pp(po, pp, "fptr var call");
3613 if (pp->is_noreturn)
3614 po->flags |= OPF_TAIL;
3620 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3623 if (po->operand[0].type == OPT_REGMEM) {
3624 pd = try_resolve_jumptab(i, opcnt);
3632 for (l = 0; l < opcnt; l++) {
3633 if (g_labels[l] != NULL
3634 && IS(po->operand[0].name, g_labels[l]))
3636 if (l == i + 1 && po->op == OP_JMP) {
3637 // yet another alignment type..
3638 po->flags |= OPF_RMD|OPF_DONE;
3641 add_label_ref(&g_label_refs[l], i);
3647 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3650 if (po->operand[0].type == OPT_LABEL)
3654 ferr(po, "unhandled branch\n");
3658 po->flags |= OPF_TAIL;
3659 if (i > 0 && ops[i - 1].op == OP_POP)
3660 po->flags |= OPF_ATAIL;
3665 static void scan_prologue_epilogue(int opcnt)
3667 int ecx_push = 0, esp_sub = 0;
3671 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
3672 && ops[1].op == OP_MOV
3673 && IS(opr_name(&ops[1], 0), "ebp")
3674 && IS(opr_name(&ops[1], 1), "esp"))
3677 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3678 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3681 if (ops[2].op == OP_SUB && IS(opr_name(&ops[2], 0), "esp")) {
3682 g_stack_fsz = opr_const(&ops[2], 1);
3683 ops[2].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3687 // another way msvc builds stack frame..
3689 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3691 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3695 // and another way..
3696 if (i == 2 && ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3697 && ops[i].operand[1].type == OPT_CONST
3698 && ops[i + 1].op == OP_CALL
3699 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3701 g_stack_fsz += ops[i].operand[1].val;
3702 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3704 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3711 for (; i < opcnt; i++)
3712 if (ops[i].flags & OPF_TAIL)
3715 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3716 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3722 if ((ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
3723 || ops[j].op == OP_LEAVE)
3725 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3727 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
3728 && ops[i].pp->is_noreturn)
3730 // on noreturn, msvc sometimes cleans stack, sometimes not
3735 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3736 ferr(&ops[j], "'pop ebp' expected\n");
3738 if (g_stack_fsz != 0) {
3739 if (ops[j].op == OP_LEAVE)
3741 else if (ops[j].op == OP_POP
3742 && ops[j - 1].op == OP_MOV
3743 && IS(opr_name(&ops[j - 1], 0), "esp")
3744 && IS(opr_name(&ops[j - 1], 1), "ebp"))
3746 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3749 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3751 ferr(&ops[j], "esp restore expected\n");
3754 if (ecx_push && j >= 0 && ops[j].op == OP_POP
3755 && IS(opr_name(&ops[j], 0), "ecx"))
3757 ferr(&ops[j], "unexpected ecx pop\n");
3763 } while (i < opcnt);
3766 ferr(ops, "missing ebp epilogue\n");
3772 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3773 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3779 for (; i < opcnt; i++) {
3780 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
3782 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
3783 && ops[i].operand[1].type == OPT_CONST)
3785 g_stack_fsz = ops[i].operand[1].val;
3786 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3792 if (ecx_push && !esp_sub) {
3793 // could actually be args for a call..
3794 for (; i < opcnt; i++)
3795 if (ops[i].op != OP_PUSH)
3798 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
3799 const struct parsed_proto *pp;
3800 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
3801 j = pp ? pp->argc_stack : 0;
3802 while (i > 0 && j > 0) {
3804 if (ops[i].op == OP_PUSH) {
3805 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
3810 ferr(&ops[i], "unhandled prologue\n");
3813 i = g_stack_fsz = ecx_push = 0;
3814 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3815 if (!(ops[i].flags & OPF_RMD))
3825 if (ecx_push || esp_sub)
3830 for (; i < opcnt; i++)
3831 if (ops[i].flags & OPF_TAIL)
3835 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3836 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3843 for (l = 0; l < ecx_push; l++) {
3844 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
3846 else if (ops[j].op == OP_ADD
3847 && IS(opr_name(&ops[j], 0), "esp")
3848 && ops[j].operand[1].type == OPT_CONST)
3851 l += ops[j].operand[1].val / 4 - 1;
3854 ferr(&ops[j], "'pop ecx' expected\n");
3856 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3860 ferr(&ops[j], "epilogue scan failed\n");
3866 if (ops[j].op != OP_ADD
3867 || !IS(opr_name(&ops[j], 0), "esp")
3868 || ops[j].operand[1].type != OPT_CONST
3869 || ops[j].operand[1].val != g_stack_fsz)
3870 ferr(&ops[j], "'add esp' expected\n");
3872 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3873 ops[j].operand[1].val = 0; // hack for stack arg scanner
3878 } while (i < opcnt);
3881 ferr(ops, "missing esp epilogue\n");
3885 // find an instruction that changed opr before i op
3886 // *op_i must be set to -1 by the caller
3887 // *is_caller is set to 1 if one source is determined to be g_func arg
3888 // returns 1 if found, *op_i is then set to origin
3889 // returns -1 if multiple origins are found
3890 static int resolve_origin(int i, const struct parsed_opr *opr,
3891 int magic, int *op_i, int *is_caller)
3893 struct label_ref *lr;
3896 if (ops[i].cc_scratch == magic)
3898 ops[i].cc_scratch = magic;
3901 if (g_labels[i] != NULL) {
3902 lr = &g_label_refs[i];
3903 for (; lr != NULL; lr = lr->next) {
3904 check_i(&ops[i], lr->i);
3905 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
3907 if (i > 0 && LAST_OP(i - 1))
3913 if (is_caller != NULL)
3918 if (ops[i].cc_scratch == magic)
3920 ops[i].cc_scratch = magic;
3922 if (!(ops[i].flags & OPF_DATA))
3924 if (!is_opr_modified(opr, &ops[i]))
3931 // XXX: could check if the other op does the same
3940 // find an instruction that previously referenced opr
3941 // if multiple results are found - fail
3942 // *op_i must be set to -1 by the caller
3943 // returns 1 if found, *op_i is then set to referencer insn
3944 static int resolve_last_ref(int i, const struct parsed_opr *opr,
3945 int magic, int *op_i)
3947 struct label_ref *lr;
3950 if (ops[i].cc_scratch == magic)
3952 ops[i].cc_scratch = magic;
3955 if (g_labels[i] != NULL) {
3956 lr = &g_label_refs[i];
3957 for (; lr != NULL; lr = lr->next) {
3958 check_i(&ops[i], lr->i);
3959 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
3961 if (i > 0 && LAST_OP(i - 1))
3969 if (ops[i].cc_scratch == magic)
3971 ops[i].cc_scratch = magic;
3973 if (!is_opr_referenced(opr, &ops[i]))
3984 // find next instruction that reads opr
3985 // *op_i must be set to -1 by the caller
3986 // on return, *op_i is set to first referencer insn
3987 // returns 1 if exactly 1 referencer is found
3988 static int find_next_read(int i, int opcnt,
3989 const struct parsed_opr *opr, int magic, int *op_i)
3991 struct parsed_op *po;
3994 for (; i < opcnt; i++)
3996 if (ops[i].cc_scratch == magic)
3998 ops[i].cc_scratch = magic;
4001 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4002 if (po->btj != NULL) {
4004 for (j = 0; j < po->btj->count; j++) {
4005 check_i(po, po->btj->d[j].bt_i);
4006 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4012 if (po->flags & OPF_RMD)
4014 check_i(po, po->bt_i);
4015 if (po->flags & OPF_CJMP) {
4016 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4025 if (!is_opr_read(opr, po)) {
4026 if (is_opr_modified(opr, po)
4027 && (po->op == OP_CALL
4028 || ((po->flags & OPF_DATA)
4029 && po->operand[0].lmod == OPLM_DWORD)))
4034 if (po->flags & OPF_TAIL)
4049 static int try_resolve_const(int i, const struct parsed_opr *opr,
4050 int magic, unsigned int *val)
4055 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4058 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4061 *val = ops[i].operand[1].val;
4068 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4069 int *pp_i, int *multi_src)
4071 const struct parsed_proto *pp = NULL;
4072 int search_advice = 0;
4082 switch (ops[i].operand[0].type) {
4084 // try to resolve struct member calls
4085 ret = sscanf(ops[i].operand[0].name, "%3s+%x%n",
4086 s_reg, &offset, &len);
4087 if (ret == 2 && len == strlen(ops[i].operand[0].name))
4089 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4091 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, reg);
4093 ret = resolve_origin(i, &opr, i + opcnt * 19, &j, NULL);
4096 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4097 && ops[j].operand[0].lmod == OPLM_DWORD
4098 && ops[j].pp == NULL) // no hint
4100 // allow one simple dereference (directx)
4101 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4102 ops[j].operand[1].name);
4105 struct parsed_opr opr2 = OPR_INIT(OPT_REG, OPLM_DWORD, reg);
4107 ret = resolve_origin(j, &opr2, j + opcnt * 19, &k, NULL);
4112 if (ops[j].op != OP_MOV)
4114 if (ops[j].operand[0].lmod != OPLM_DWORD)
4116 if (ops[j].pp != NULL) {
4120 else if (ops[j].operand[1].type == OPT_REGMEM) {
4121 // allow 'hello[ecx]' - assume array of same type items
4122 ret = sscanf(ops[j].operand[1].name, "%[^[][e%2s]",
4126 pp = proto_parse(g_fhdr, name, g_quiet_pp);
4128 else if (ops[j].operand[1].type == OPT_LABEL)
4129 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4134 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4138 pp = proto_lookup_struct(g_fhdr, pp->type.name, offset);
4145 pp = try_recover_pp(&ops[i], &ops[i].operand[0], &search_advice);
4150 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4158 static struct parsed_proto *process_call_early(int i, int opcnt,
4161 struct parsed_op *po = &ops[i];
4162 struct parsed_proto *pp;
4168 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4172 // look for and make use of esp adjust
4174 if (!pp->is_stdcall && pp->argc_stack > 0)
4175 ret = scan_for_esp_adjust(i + 1, opcnt,
4176 pp->argc_stack * 4, &adj, &multipath, 0);
4178 if (pp->argc_stack > adj / 4)
4182 if (ops[ret].op == OP_POP) {
4183 for (j = 1; j < adj / 4; j++) {
4184 if (ops[ret + j].op != OP_POP
4185 || ops[ret + j].operand[0].reg != xCX)
4197 static struct parsed_proto *process_call(int i, int opcnt)
4199 struct parsed_op *po = &ops[i];
4200 const struct parsed_proto *pp_c;
4201 struct parsed_proto *pp;
4202 const char *tmpname;
4203 int call_i = -1, ref_i = -1;
4204 int adj = 0, multipath = 0;
4207 tmpname = opr_name(po, 0);
4212 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4214 if (!pp_c->is_func && !pp_c->is_fptr)
4215 ferr(po, "call to non-func: %s\n", pp_c->name);
4216 pp = proto_clone(pp_c);
4217 my_assert_not(pp, NULL);
4219 // not resolved just to single func
4222 switch (po->operand[0].type) {
4224 // we resolved this call and no longer need the register
4225 po->regmask_src &= ~(1 << po->operand[0].reg);
4227 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4228 && ops[call_i].operand[1].type == OPT_LABEL)
4230 // no other source users?
4231 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4233 if (ret == 1 && call_i == ref_i) {
4234 // and nothing uses it after us?
4236 find_next_read(i + 1, opcnt, &po->operand[0],
4237 i + opcnt * 11, &ref_i);
4239 // then also don't need the source mov
4240 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4252 pp = calloc(1, sizeof(*pp));
4253 my_assert_not(pp, NULL);
4256 ret = scan_for_esp_adjust(i + 1, opcnt,
4257 -1, &adj, &multipath, 0);
4258 if (ret < 0 || adj < 0) {
4259 if (!g_allow_regfunc)
4260 ferr(po, "non-__cdecl indirect call unhandled yet\n");
4261 pp->is_unresolved = 1;
4265 if (adj > ARRAY_SIZE(pp->arg))
4266 ferr(po, "esp adjust too large: %d\n", adj);
4267 pp->ret_type.name = strdup("int");
4268 pp->argc = pp->argc_stack = adj;
4269 for (arg = 0; arg < pp->argc; arg++)
4270 pp->arg[arg].type.name = strdup("int");
4275 // look for and make use of esp adjust
4278 if (!pp->is_stdcall && pp->argc_stack > 0) {
4279 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
4280 ret = scan_for_esp_adjust(i + 1, opcnt,
4281 adj_expect, &adj, &multipath, 0);
4284 if (pp->is_vararg) {
4285 if (adj / 4 < pp->argc_stack) {
4286 fnote(po, "(this call)\n");
4287 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
4288 adj, pp->argc_stack * 4);
4290 // modify pp to make it have varargs as normal args
4292 pp->argc += adj / 4 - pp->argc_stack;
4293 for (; arg < pp->argc; arg++) {
4294 pp->arg[arg].type.name = strdup("int");
4297 if (pp->argc > ARRAY_SIZE(pp->arg))
4298 ferr(po, "too many args for '%s'\n", tmpname);
4300 if (pp->argc_stack > adj / 4) {
4301 fnote(po, "(this call)\n");
4302 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
4303 tmpname, pp->argc_stack * 4, adj);
4306 scan_for_esp_adjust(i + 1, opcnt,
4307 pp->argc_stack * 4, &adj, &multipath, 1);
4309 else if (pp->is_vararg)
4310 ferr(po, "missing esp_adjust for vararg func '%s'\n",
4316 static int collect_call_args_early(struct parsed_op *po, int i,
4317 struct parsed_proto *pp, int *regmask)
4322 for (arg = 0; arg < pp->argc; arg++)
4323 if (pp->arg[arg].reg == NULL)
4326 // first see if it can be easily done
4327 for (j = i; j > 0 && arg < pp->argc; )
4329 if (g_labels[j] != NULL)
4333 if (ops[j].op == OP_CALL)
4335 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP)
4337 else if (ops[j].op == OP_POP)
4339 else if (ops[j].flags & OPF_CJMP)
4341 else if (ops[j].op == OP_PUSH) {
4342 if (ops[j].flags & (OPF_FARG|OPF_FARGNR))
4344 ret = scan_for_mod(&ops[j], j + 1, i, 1);
4348 if (pp->arg[arg].type.is_va_list)
4352 for (arg++; arg < pp->argc; arg++)
4353 if (pp->arg[arg].reg == NULL)
4362 for (arg = 0; arg < pp->argc; arg++)
4363 if (pp->arg[arg].reg == NULL)
4366 for (j = i; j > 0 && arg < pp->argc; )
4370 if (ops[j].op == OP_PUSH)
4372 ops[j].p_argnext = -1;
4373 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
4374 pp->arg[arg].datap = &ops[j];
4376 if (ops[j].operand[0].type == OPT_REG)
4377 *regmask |= 1 << ops[j].operand[0].reg;
4379 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4380 ops[j].flags &= ~OPF_RSAVE;
4383 for (arg++; arg < pp->argc; arg++)
4384 if (pp->arg[arg].reg == NULL)
4392 static int collect_call_args_r(struct parsed_op *po, int i,
4393 struct parsed_proto *pp, int *regmask, int *save_arg_vars,
4394 int *arg_grp, int arg, int magic, int need_op_saving, int may_reuse)
4396 struct parsed_proto *pp_tmp;
4397 struct parsed_op *po_tmp;
4398 struct label_ref *lr;
4399 int need_to_save_current;
4400 int arg_grp_current = 0;
4401 int save_args_seen = 0;
4409 ferr(po, "dead label encountered\n");
4413 for (; arg < pp->argc; arg++)
4414 if (pp->arg[arg].reg == NULL)
4416 magic = (magic & 0xffffff) | (arg << 24);
4418 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
4420 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
4421 if (ops[j].cc_scratch != magic) {
4422 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
4426 // ok: have already been here
4429 ops[j].cc_scratch = magic;
4431 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
4432 lr = &g_label_refs[j];
4433 if (lr->next != NULL)
4435 for (; lr->next; lr = lr->next) {
4436 check_i(&ops[j], lr->i);
4437 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4439 ret = collect_call_args_r(po, lr->i, pp, regmask, save_arg_vars,
4440 arg_grp, arg, magic, need_op_saving, may_reuse);
4445 check_i(&ops[j], lr->i);
4446 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4448 if (j > 0 && LAST_OP(j - 1)) {
4449 // follow last branch in reverse
4454 ret = collect_call_args_r(po, lr->i, pp, regmask, save_arg_vars,
4455 arg_grp, arg, magic, need_op_saving, may_reuse);
4461 if (ops[j].op == OP_CALL)
4463 if (pp->is_unresolved)
4468 ferr(po, "arg collect hit unparsed call '%s'\n",
4469 ops[j].operand[0].name);
4470 if (may_reuse && pp_tmp->argc_stack > 0)
4471 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
4472 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
4474 // esp adjust of 0 means we collected it before
4475 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
4476 && (ops[j].operand[1].type != OPT_CONST
4477 || ops[j].operand[1].val != 0))
4479 if (pp->is_unresolved)
4482 fnote(po, "(this call)\n");
4483 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
4484 arg, pp->argc, ops[j].operand[1].val);
4486 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
4488 if (pp->is_unresolved)
4491 fnote(po, "(this call)\n");
4492 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
4494 else if (ops[j].flags & OPF_CJMP)
4496 if (pp->is_unresolved)
4501 else if (ops[j].op == OP_PUSH
4502 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
4504 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
4507 ops[j].p_argnext = -1;
4508 po_tmp = pp->arg[arg].datap;
4510 ops[j].p_argnext = po_tmp - ops;
4511 pp->arg[arg].datap = &ops[j];
4513 need_to_save_current = 0;
4516 if (ops[j].operand[0].type == OPT_REG)
4517 reg = ops[j].operand[0].reg;
4519 if (!need_op_saving) {
4520 ret = scan_for_mod(&ops[j], j + 1, i, 1);
4521 need_to_save_current = (ret >= 0);
4523 if (need_op_saving || need_to_save_current) {
4524 // mark this push as one that needs operand saving
4525 ops[j].flags &= ~OPF_RMD;
4526 if (ops[j].p_argnum == 0) {
4527 ops[j].p_argnum = arg + 1;
4528 save_args |= 1 << arg;
4530 else if (ops[j].p_argnum < arg + 1) {
4531 // XXX: might kill valid var..
4532 //*save_arg_vars &= ~(1 << (ops[j].p_argnum - 1));
4533 ops[j].p_argnum = arg + 1;
4534 save_args |= 1 << arg;
4537 if (save_args_seen & (1 << (ops[j].p_argnum - 1))) {
4540 if (arg_grp_current >= MAX_ARG_GRP)
4541 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
4542 ops[j].p_argnum, pp->name);
4545 else if (ops[j].p_argnum == 0)
4546 ops[j].flags |= OPF_RMD;
4548 // some PUSHes are reused by different calls on other branches,
4549 // but that can't happen if we didn't branch, so they
4550 // can be removed from future searches (handles nested calls)
4552 ops[j].flags |= OPF_FARGNR;
4554 ops[j].flags |= OPF_FARG;
4555 ops[j].flags &= ~OPF_RSAVE;
4557 // check for __VALIST
4558 if (!pp->is_unresolved && g_func_pp != NULL
4559 && pp->arg[arg].type.is_va_list)
4562 ret = resolve_origin(j, &ops[j].operand[0],
4563 magic + 1, &k, NULL);
4564 if (ret == 1 && k >= 0)
4566 if (ops[k].op == OP_LEA) {
4567 if (!g_func_pp->is_vararg)
4568 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
4571 snprintf(buf, sizeof(buf), "arg_%X",
4572 g_func_pp->argc_stack * 4);
4573 if (strstr(ops[k].operand[1].name, buf)
4574 || strstr(ops[k].operand[1].name, "arglist"))
4576 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
4577 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
4578 save_args &= ~(1 << arg);
4582 ferr(&ops[k], "va_list arg detection failed\n");
4584 // check for va_list from g_func_pp arg too
4585 else if (ops[k].op == OP_MOV
4586 && is_stack_access(&ops[k], &ops[k].operand[1]))
4588 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
4589 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
4591 ops[k].flags |= OPF_RMD | OPF_DONE;
4592 ops[j].flags |= OPF_RMD;
4593 ops[j].p_argpass = ret + 1;
4594 save_args &= ~(1 << arg);
4601 *save_arg_vars |= save_args;
4603 // tracking reg usage
4605 *regmask |= 1 << reg;
4608 if (!pp->is_unresolved) {
4610 for (; arg < pp->argc; arg++)
4611 if (pp->arg[arg].reg == NULL)
4614 magic = (magic & 0xffffff) | (arg << 24);
4617 if (ops[j].p_arggrp > arg_grp_current) {
4619 arg_grp_current = ops[j].p_arggrp;
4621 if (ops[j].p_argnum > 0)
4622 save_args_seen |= 1 << (ops[j].p_argnum - 1);
4625 if (arg < pp->argc) {
4626 ferr(po, "arg collect failed for '%s': %d/%d\n",
4627 pp->name, arg, pp->argc);
4631 if (arg_grp_current > *arg_grp)
4632 *arg_grp = arg_grp_current;
4637 static int collect_call_args(struct parsed_op *po, int i,
4638 struct parsed_proto *pp, int *regmask, int *save_arg_vars,
4641 // arg group is for cases when pushes for
4642 // multiple funcs are going on
4643 struct parsed_op *po_tmp;
4644 int save_arg_vars_current = 0;
4649 ret = collect_call_args_r(po, i, pp, regmask,
4650 &save_arg_vars_current, &arg_grp, 0, magic, 0, 0);
4655 // propagate arg_grp
4656 for (a = 0; a < pp->argc; a++) {
4657 if (pp->arg[a].reg != NULL)
4660 po_tmp = pp->arg[a].datap;
4661 while (po_tmp != NULL) {
4662 po_tmp->p_arggrp = arg_grp;
4663 if (po_tmp->p_argnext > 0)
4664 po_tmp = &ops[po_tmp->p_argnext];
4670 save_arg_vars[arg_grp] |= save_arg_vars_current;
4672 if (pp->is_unresolved) {
4674 pp->argc_stack += ret;
4675 for (a = 0; a < pp->argc; a++)
4676 if (pp->arg[a].type.name == NULL)
4677 pp->arg[a].type.name = strdup("int");
4683 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
4684 int regmask_now, int *regmask,
4685 int regmask_save_now, int *regmask_save,
4686 int *regmask_init, int regmask_arg)
4688 struct parsed_op *po;
4696 for (; i < opcnt; i++)
4699 if (cbits[i >> 3] & (1 << (i & 7)))
4701 cbits[i >> 3] |= (1 << (i & 7));
4703 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4704 if (po->flags & (OPF_RMD|OPF_DONE))
4706 if (po->btj != NULL) {
4707 for (j = 0; j < po->btj->count; j++) {
4708 check_i(po, po->btj->d[j].bt_i);
4709 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
4710 regmask_now, regmask, regmask_save_now, regmask_save,
4711 regmask_init, regmask_arg);
4716 check_i(po, po->bt_i);
4717 if (po->flags & OPF_CJMP)
4718 reg_use_pass(po->bt_i, opcnt, cbits,
4719 regmask_now, regmask, regmask_save_now, regmask_save,
4720 regmask_init, regmask_arg);
4726 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
4727 && !g_func_pp->is_userstack
4728 && po->operand[0].type == OPT_REG)
4730 reg = po->operand[0].reg;
4731 ferr_assert(po, reg >= 0);
4734 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
4735 if (regmask_now & (1 << reg)) {
4736 already_saved = regmask_save_now & (1 << reg);
4737 flags_set = OPF_RSAVE | OPF_DONE;
4740 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0);
4742 scan_for_pop(i + 1, opcnt, i + opcnt * 4, reg, 0, flags_set);
4745 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
4747 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
4752 ferr_assert(po, !already_saved);
4753 po->flags |= flags_set;
4755 if (regmask_now & (1 << reg)) {
4756 regmask_save_now |= (1 << reg);
4757 *regmask_save |= regmask_save_now;
4762 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
4763 reg = po->operand[0].reg;
4764 ferr_assert(po, reg >= 0);
4766 if (regmask_save_now & (1 << reg))
4767 regmask_save_now &= ~(1 << reg);
4769 regmask_now &= ~(1 << reg);
4772 else if (po->op == OP_CALL) {
4773 if ((po->regmask_dst & (1 << xAX))
4774 && !(po->regmask_dst & (1 << xDX)))
4776 if (po->flags & OPF_TAIL)
4777 // don't need eax, will do "return f();" or "f(); return;"
4778 po->regmask_dst &= ~(1 << xAX);
4780 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
4782 find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
4785 po->regmask_dst &= ~(1 << xAX);
4789 // not "full stack" mode and have something in stack
4790 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
4791 ferr(po, "float stack is not empty on func call\n");
4794 if (po->flags & OPF_NOREGS)
4797 if (po->flags & OPF_FPUSH) {
4798 if (regmask_now & mxST1)
4799 regmask_now |= mxSTa; // switch to "full stack" mode
4800 if (regmask_now & mxSTa)
4801 po->flags |= OPF_FSHIFT;
4802 if (!(regmask_now & mxST7_2)) {
4804 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
4808 // if incomplete register is used, clear it on init to avoid
4809 // later use of uninitialized upper part in some situations
4810 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
4811 && po->operand[0].lmod != OPLM_DWORD)
4813 reg = po->operand[0].reg;
4814 ferr_assert(po, reg >= 0);
4816 if (!(regmask_now & (1 << reg)))
4817 *regmask_init |= 1 << reg;
4820 regmask_op = po->regmask_src | po->regmask_dst;
4822 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
4823 regmask_new &= ~(1 << xSP);
4824 if (g_bp_frame && !(po->flags & OPF_EBP_S))
4825 regmask_new &= ~(1 << xBP);
4827 if (regmask_new != 0)
4828 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
4830 if (regmask_op & (1 << xBP)) {
4831 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
4832 if (po->regmask_dst & (1 << xBP))
4833 // compiler decided to drop bp frame and use ebp as scratch
4834 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
4836 regmask_op &= ~(1 << xBP);
4840 regmask_now |= regmask_op;
4841 *regmask |= regmask_now;
4844 if (po->flags & OPF_FPOP) {
4845 if ((regmask_now & mxSTa) == 0)
4846 ferr(po, "float pop on empty stack?\n");
4847 if (regmask_now & (mxST7_2 | mxST1))
4848 po->flags |= OPF_FSHIFT;
4849 if (!(regmask_now & mxST7_2)) {
4851 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
4855 if (po->flags & OPF_TAIL) {
4856 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
4857 ferr(po, "float regs on tail: %x\n", regmask_now);
4859 // there is support for "conditional tailcall", sort of
4860 if (!(po->flags & OPF_CC))
4866 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
4870 for (i = 0; i < pp->argc; i++)
4871 if (pp->arg[i].reg == NULL)
4875 memmove(&pp->arg[i + 1], &pp->arg[i],
4876 sizeof(pp->arg[0]) * pp->argc_stack);
4877 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
4878 pp->arg[i].reg = strdup(reg);
4879 pp->arg[i].type.name = strdup("int");
4884 static void output_std_flags(FILE *fout, struct parsed_op *po,
4885 int *pfomask, const char *dst_opr_text)
4887 if (*pfomask & (1 << PFO_Z)) {
4888 fprintf(fout, "\n cond_z = (%s%s == 0);",
4889 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
4890 *pfomask &= ~(1 << PFO_Z);
4892 if (*pfomask & (1 << PFO_S)) {
4893 fprintf(fout, "\n cond_s = (%s%s < 0);",
4894 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
4895 *pfomask &= ~(1 << PFO_S);
4900 OPP_FORCE_NORETURN = (1 << 0),
4901 OPP_SIMPLE_ARGS = (1 << 1),
4902 OPP_ALIGN = (1 << 2),
4905 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
4908 const char *cconv = "";
4910 if (pp->is_fastcall)
4911 cconv = "__fastcall ";
4912 else if (pp->is_stdcall && pp->argc_reg == 0)
4913 cconv = "__stdcall ";
4915 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
4917 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
4918 fprintf(fout, "noreturn ");
4921 static void output_pp(FILE *fout, const struct parsed_proto *pp,
4926 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
4930 output_pp_attrs(fout, pp, flags);
4933 fprintf(fout, "%s", pp->name);
4938 for (i = 0; i < pp->argc; i++) {
4940 fprintf(fout, ", ");
4941 if (pp->arg[i].fptr != NULL && !(flags & OPP_SIMPLE_ARGS)) {
4943 output_pp(fout, pp->arg[i].fptr, 0);
4945 else if (pp->arg[i].type.is_retreg) {
4946 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
4949 fprintf(fout, "%s", pp->arg[i].type.name);
4951 fprintf(fout, " a%d", i + 1);
4954 if (pp->is_vararg) {
4956 fprintf(fout, ", ");
4957 fprintf(fout, "...");
4962 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
4968 snprintf(buf1, sizeof(buf1), "%d", grp);
4969 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
4974 static void gen_x_cleanup(int opcnt);
4976 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
4978 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
4979 struct parsed_opr *last_arith_dst = NULL;
4980 char buf1[256], buf2[256], buf3[256], cast[64];
4981 struct parsed_proto *pp, *pp_tmp;
4982 struct parsed_data *pd;
4984 int save_arg_vars[MAX_ARG_GRP] = { 0, };
4985 unsigned char cbits[MAX_OPS / 8];
4986 const char *float_type;
4987 const char *float_st0;
4988 const char *float_st1;
4989 int need_float_stack = 0;
4990 int need_tmp_var = 0;
4994 int label_pending = 0;
4995 int need_double = 0;
4996 int regmask_save = 0; // regs saved/restored in this func
4997 int regmask_arg; // regs from this function args (fastcall, etc)
4998 int regmask_ret; // regs needed on ret
4999 int regmask_now; // temp
5000 int regmask_init = 0; // regs that need zero initialization
5001 int regmask_pp = 0; // regs used in complex push-pop graph
5002 int regmask = 0; // used regs
5012 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
5013 g_stack_frame_used = 0;
5014 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
5015 regmask_init = g_regmask_init;
5017 g_func_pp = proto_parse(fhdr, funcn, 0);
5018 if (g_func_pp == NULL)
5019 ferr(ops, "proto_parse failed for '%s'\n", funcn);
5021 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
5022 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
5025 // - resolve all branches
5026 // - parse calls with labels
5027 resolve_branches_parse_calls(opcnt);
5030 // - handle ebp/esp frame, remove ops related to it
5031 scan_prologue_epilogue(opcnt);
5034 // - remove dead labels
5035 // - set regs needed at ret
5036 for (i = 0; i < opcnt; i++)
5038 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
5043 if (ops[i].op == OP_RET)
5044 ops[i].regmask_src |= regmask_ret;
5048 // - process trivial calls
5049 for (i = 0; i < opcnt; i++)
5052 if (po->flags & (OPF_RMD|OPF_DONE))
5055 if (po->op == OP_CALL)
5057 pp = process_call_early(i, opcnt, &j);
5059 if (!(po->flags & OPF_ATAIL))
5060 // since we know the args, try to collect them
5061 if (collect_call_args_early(po, i, pp, ®mask) != 0)
5067 // commit esp adjust
5068 if (ops[j].op != OP_POP)
5069 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5071 for (l = 0; l < pp->argc_stack; l++)
5072 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
5076 if (strstr(pp->ret_type.name, "int64"))
5079 po->flags |= OPF_DONE;
5085 // - process calls, stage 2
5086 // - handle some push/pop pairs
5087 // - scan for STD/CLD, propagate DF
5088 for (i = 0; i < opcnt; i++)
5091 if (po->flags & OPF_RMD)
5094 if (po->op == OP_CALL)
5096 if (!(po->flags & OPF_DONE)) {
5097 pp = process_call(i, opcnt);
5099 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
5100 // since we know the args, collect them
5101 collect_call_args(po, i, pp, ®mask, save_arg_vars,
5104 // for unresolved, collect after other passes
5108 ferr_assert(po, pp != NULL);
5110 po->regmask_src |= get_pp_arg_regmask_src(pp);
5111 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
5113 if (po->regmask_dst & mxST0)
5114 po->flags |= OPF_FPUSH;
5116 if (strstr(pp->ret_type.name, "int64"))
5122 if (po->flags & OPF_DONE)
5125 if (po->op == OP_PUSH && !(po->flags & OPF_FARG)
5126 && !(po->flags & OPF_RSAVE) && po->operand[0].type == OPT_CONST)
5128 scan_for_pop_const(i, opcnt, i + opcnt * 12);
5130 else if (po->op == OP_POP)
5131 scan_pushes_for_pop(i, opcnt, ®mask_pp);
5132 else if (po->op == OP_STD) {
5133 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
5134 scan_propagate_df(i + 1, opcnt);
5139 // - find POPs for PUSHes, rm both
5140 // - scan for all used registers
5141 memset(cbits, 0, sizeof(cbits));
5142 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
5143 0, ®mask_save, ®mask_init, regmask_arg);
5146 // - find flag set ops for their users
5147 // - do unresolved calls
5148 // - declare indirect functions
5149 for (i = 0; i < opcnt; i++)
5152 if (po->flags & (OPF_RMD|OPF_DONE))
5155 if (po->flags & OPF_CC)
5157 int setters[16], cnt = 0, branched = 0;
5159 ret = scan_for_flag_set(i, i + opcnt * 6,
5160 &branched, setters, &cnt);
5161 if (ret < 0 || cnt <= 0)
5162 ferr(po, "unable to trace flag setter(s)\n");
5163 if (cnt > ARRAY_SIZE(setters))
5164 ferr(po, "too many flag setters\n");
5166 for (j = 0; j < cnt; j++)
5168 tmp_op = &ops[setters[j]]; // flag setter
5171 // to get nicer code, we try to delay test and cmp;
5172 // if we can't because of operand modification, or if we
5173 // have arith op, or branch, make it calculate flags explicitly
5174 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
5176 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
5177 pfomask = 1 << po->pfo;
5179 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
5180 pfomask = 1 << po->pfo;
5183 // see if we'll be able to handle based on op result
5184 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
5185 && po->pfo != PFO_Z && po->pfo != PFO_S
5186 && po->pfo != PFO_P)
5188 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
5190 pfomask = 1 << po->pfo;
5193 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
5194 propagate_lmod(tmp_op, &tmp_op->operand[0],
5195 &tmp_op->operand[1]);
5196 if (tmp_op->operand[0].lmod == OPLM_DWORD)
5201 tmp_op->pfomask |= pfomask;
5202 cond_vars |= pfomask;
5204 // note: may overwrite, currently not a problem
5208 if (po->op == OP_RCL || po->op == OP_RCR
5209 || po->op == OP_ADC || po->op == OP_SBB)
5210 cond_vars |= 1 << PFO_C;
5213 if (po->op == OP_CMPS || po->op == OP_SCAS) {
5214 cond_vars |= 1 << PFO_Z;
5216 else if (po->op == OP_MUL
5217 || (po->op == OP_IMUL && po->operand_cnt == 1))
5219 if (po->operand[0].lmod == OPLM_DWORD)
5222 else if (po->op == OP_CALL) {
5223 // note: resolved non-reg calls are OPF_DONE already
5225 ferr_assert(po, pp != NULL);
5227 if (pp->is_unresolved) {
5228 int regmask_stack = 0;
5229 collect_call_args(po, i, pp, ®mask, save_arg_vars,
5232 // this is pretty rough guess:
5233 // see ecx and edx were pushed (and not their saved versions)
5234 for (arg = 0; arg < pp->argc; arg++) {
5235 if (pp->arg[arg].reg != NULL)
5238 tmp_op = pp->arg[arg].datap;
5240 ferr(po, "parsed_op missing for arg%d\n", arg);
5241 if (tmp_op->p_argnum == 0 && tmp_op->operand[0].type == OPT_REG)
5242 regmask_stack |= 1 << tmp_op->operand[0].reg;
5245 if (!((regmask_stack & (1 << xCX))
5246 && (regmask_stack & (1 << xDX))))
5248 if (pp->argc_stack != 0
5249 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
5251 pp_insert_reg_arg(pp, "ecx");
5252 pp->is_fastcall = 1;
5253 regmask_init |= 1 << xCX;
5254 regmask |= 1 << xCX;
5256 if (pp->argc_stack != 0
5257 || ((regmask | regmask_arg) & (1 << xDX)))
5259 pp_insert_reg_arg(pp, "edx");
5260 regmask_init |= 1 << xDX;
5261 regmask |= 1 << xDX;
5265 // note: __cdecl doesn't fall into is_unresolved category
5266 if (pp->argc_stack > 0)
5270 else if (po->op == OP_MOV && po->operand[0].pp != NULL
5271 && po->operand[1].pp != NULL)
5273 // <var> = offset <something>
5274 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
5275 && !IS_START(po->operand[1].name, "off_"))
5277 if (!po->operand[0].pp->is_fptr)
5278 ferr(po, "%s not declared as fptr when it should be\n",
5279 po->operand[0].name);
5280 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
5281 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
5282 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
5283 fnote(po, "var: %s\n", buf1);
5284 fnote(po, "func: %s\n", buf2);
5285 ferr(po, "^ mismatch\n");
5289 else if (po->op == OP_DIV || po->op == OP_IDIV) {
5290 if (po->operand[0].lmod == OPLM_DWORD) {
5291 // 32bit division is common, look for it
5292 if (po->op == OP_DIV)
5293 ret = scan_for_reg_clear(i, xDX);
5295 ret = scan_for_cdq_edx(i);
5297 po->flags |= OPF_32BIT;
5304 else if (po->op == OP_CLD)
5305 po->flags |= OPF_RMD | OPF_DONE;
5306 else if (po->op == OPP_FTOL) {
5307 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
5309 find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
5311 po->flags |= OPF_32BIT;
5313 else if (po->op == OP_FLD && po->operand[0].lmod == OPLM_QWORD)
5316 if (po->op == OP_RCL || po->op == OP_RCR || po->op == OP_XCHG)
5320 float_type = need_double ? "double" : "float";
5321 need_float_stack = !!(regmask & mxST7_2);
5322 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
5323 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
5325 // output starts here
5327 // define userstack size
5328 if (g_func_pp->is_userstack) {
5329 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
5330 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
5331 fprintf(fout, "#endif\n");
5334 // the function itself
5335 ferr_assert(ops, !g_func_pp->is_fptr);
5336 output_pp(fout, g_func_pp,
5337 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
5338 fprintf(fout, "\n{\n");
5340 // declare indirect functions
5341 for (i = 0; i < opcnt; i++) {
5343 if (po->flags & OPF_RMD)
5346 if (po->op == OP_CALL) {
5349 ferr(po, "NULL pp\n");
5351 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
5352 if (pp->name[0] != 0) {
5353 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
5354 memcpy(pp->name, "i_", 2);
5356 // might be declared already
5358 for (j = 0; j < i; j++) {
5359 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
5360 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
5370 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
5373 output_pp(fout, pp, OPP_SIMPLE_ARGS);
5374 fprintf(fout, ";\n");
5379 // output LUTs/jumptables
5380 for (i = 0; i < g_func_pd_cnt; i++) {
5382 fprintf(fout, " static const ");
5383 if (pd->type == OPT_OFFSET) {
5384 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
5386 for (j = 0; j < pd->count; j++) {
5388 fprintf(fout, ", ");
5389 fprintf(fout, "&&%s", pd->d[j].u.label);
5393 fprintf(fout, "%s %s[] =\n { ",
5394 lmod_type_u(ops, pd->lmod), pd->label);
5396 for (j = 0; j < pd->count; j++) {
5398 fprintf(fout, ", ");
5399 fprintf(fout, "%u", pd->d[j].u.val);
5402 fprintf(fout, " };\n");
5406 // declare stack frame, va_arg
5408 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
5409 if (g_func_lmods & (1 << OPLM_WORD))
5410 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
5411 if (g_func_lmods & (1 << OPLM_BYTE))
5412 fprintf(fout, " u8 b[%d];", g_stack_fsz);
5413 if (g_func_lmods & (1 << OPLM_QWORD))
5414 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
5415 fprintf(fout, " } sf;\n");
5419 if (g_func_pp->is_userstack) {
5420 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
5421 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
5425 if (g_func_pp->is_vararg) {
5426 fprintf(fout, " va_list ap;\n");
5430 // declare arg-registers
5431 for (i = 0; i < g_func_pp->argc; i++) {
5432 if (g_func_pp->arg[i].reg != NULL) {
5433 reg = char_array_i(regs_r32,
5434 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
5435 if (regmask & (1 << reg)) {
5436 if (g_func_pp->arg[i].type.is_retreg)
5437 fprintf(fout, " u32 %s = *r_%s;\n",
5438 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
5440 fprintf(fout, " u32 %s = (u32)a%d;\n",
5441 g_func_pp->arg[i].reg, i + 1);
5444 if (g_func_pp->arg[i].type.is_retreg)
5445 ferr(ops, "retreg '%s' is unused?\n",
5446 g_func_pp->arg[i].reg);
5447 fprintf(fout, " // %s = a%d; // unused\n",
5448 g_func_pp->arg[i].reg, i + 1);
5454 // declare normal registers
5455 regmask_now = regmask & ~regmask_arg;
5456 regmask_now &= ~(1 << xSP);
5457 if (regmask_now & 0x00ff) {
5458 for (reg = 0; reg < 8; reg++) {
5459 if (regmask_now & (1 << reg)) {
5460 fprintf(fout, " u32 %s", regs_r32[reg]);
5461 if (regmask_init & (1 << reg))
5462 fprintf(fout, " = 0");
5463 fprintf(fout, ";\n");
5469 if (regmask_now & 0xff00) {
5470 for (reg = 8; reg < 16; reg++) {
5471 if (regmask_now & (1 << reg)) {
5472 fprintf(fout, " mmxr %s", regs_r32[reg]);
5473 if (regmask_init & (1 << reg))
5474 fprintf(fout, " = { 0, }");
5475 fprintf(fout, ";\n");
5481 if (need_float_stack) {
5482 fprintf(fout, " %s f_st[8];\n", float_type);
5483 fprintf(fout, " int f_stp = 0;\n");
5487 if (regmask_now & 0xff0000) {
5488 for (reg = 16; reg < 24; reg++) {
5489 if (regmask_now & (1 << reg)) {
5490 fprintf(fout, " %s f_st%d", float_type, reg - 16);
5491 if (regmask_init & (1 << reg))
5492 fprintf(fout, " = 0");
5493 fprintf(fout, ";\n");
5501 for (reg = 0; reg < 8; reg++) {
5502 if (regmask_save & (1 << reg)) {
5503 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
5509 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
5510 if (save_arg_vars[i] == 0)
5512 for (reg = 0; reg < 32; reg++) {
5513 if (save_arg_vars[i] & (1 << reg)) {
5514 fprintf(fout, " u32 %s;\n",
5515 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
5521 // declare push-pop temporaries
5523 for (reg = 0; reg < 8; reg++) {
5524 if (regmask_pp & (1 << reg)) {
5525 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
5532 for (i = 0; i < 8; i++) {
5533 if (cond_vars & (1 << i)) {
5534 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
5541 fprintf(fout, " u32 tmp;\n");
5546 fprintf(fout, " u64 tmp64;\n");
5551 fprintf(fout, "\n");
5553 // do stack clear, if needed
5554 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
5556 if (g_stack_clear_len != 0) {
5557 if (g_stack_clear_len <= 4) {
5558 for (i = 0; i < g_stack_clear_len; i++)
5559 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
5560 fprintf(fout, "0;\n");
5563 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
5564 g_stack_clear_start, g_stack_clear_len * 4);
5568 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
5571 if (g_func_pp->is_vararg) {
5572 if (g_func_pp->argc_stack == 0)
5573 ferr(ops, "vararg func without stack args?\n");
5574 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
5578 for (i = 0; i < opcnt; i++)
5580 if (g_labels[i] != NULL) {
5581 fprintf(fout, "\n%s:\n", g_labels[i]);
5584 delayed_flag_op = NULL;
5585 last_arith_dst = NULL;
5589 if (po->flags & OPF_RMD)
5594 #define assert_operand_cnt(n_) \
5595 if (po->operand_cnt != n_) \
5596 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
5598 // conditional/flag using op?
5599 if (po->flags & OPF_CC)
5605 // we go through all this trouble to avoid using parsed_flag_op,
5606 // which makes generated code much nicer
5607 if (delayed_flag_op != NULL)
5609 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
5610 po->pfo, po->pfo_inv);
5613 else if (last_arith_dst != NULL
5614 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
5615 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
5618 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
5619 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
5620 last_arith_dst->lmod, buf3);
5623 else if (tmp_op != NULL) {
5624 // use preprocessed flag calc results
5625 if (!(tmp_op->pfomask & (1 << po->pfo)))
5626 ferr(po, "not prepared for pfo %d\n", po->pfo);
5628 // note: pfo_inv was not yet applied
5629 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
5630 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
5633 ferr(po, "all methods of finding comparison failed\n");
5636 if (po->flags & OPF_JMP) {
5637 fprintf(fout, " if %s", buf1);
5639 else if (po->op == OP_RCL || po->op == OP_RCR
5640 || po->op == OP_ADC || po->op == OP_SBB)
5643 fprintf(fout, " cond_%s = %s;\n",
5644 parsed_flag_op_names[po->pfo], buf1);
5646 else if (po->flags & OPF_DATA) { // SETcc
5647 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
5648 fprintf(fout, " %s = %s;", buf2, buf1);
5651 ferr(po, "unhandled conditional op\n");
5655 pfomask = po->pfomask;
5657 if (po->flags & (OPF_REPZ|OPF_REPNZ)) {
5658 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
5659 ret = try_resolve_const(i, &opr, opcnt * 7 + i, &uval);
5661 if (ret != 1 || uval == 0) {
5662 // we need initial flags for ecx=0 case..
5663 if (i > 0 && ops[i - 1].op == OP_XOR
5664 && IS(ops[i - 1].operand[0].name,
5665 ops[i - 1].operand[1].name))
5667 fprintf(fout, " cond_z = ");
5668 if (pfomask & (1 << PFO_C))
5669 fprintf(fout, "cond_c = ");
5670 fprintf(fout, "0;\n");
5672 else if (last_arith_dst != NULL) {
5673 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
5674 out_test_for_cc(buf1, sizeof(buf1), po, PFO_Z, 0,
5675 last_arith_dst->lmod, buf3);
5676 fprintf(fout, " cond_z = %s;\n", buf1);
5679 ferr(po, "missing initial ZF\n");
5686 assert_operand_cnt(2);
5687 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5688 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5689 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
5690 fprintf(fout, " %s = %s;", buf1,
5691 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5696 assert_operand_cnt(2);
5697 po->operand[1].lmod = OPLM_DWORD; // always
5698 fprintf(fout, " %s = %s;",
5699 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5700 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5705 assert_operand_cnt(2);
5706 fprintf(fout, " %s = %s;",
5707 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5708 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5712 assert_operand_cnt(2);
5713 switch (po->operand[1].lmod) {
5715 strcpy(buf3, "(s8)");
5718 strcpy(buf3, "(s16)");
5721 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
5723 fprintf(fout, " %s = %s;",
5724 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5725 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5730 assert_operand_cnt(2);
5731 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5732 fprintf(fout, " tmp = %s;",
5733 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
5734 fprintf(fout, " %s = %s;",
5735 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5736 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5737 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
5738 fprintf(fout, " %s = %stmp;",
5739 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
5740 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
5741 snprintf(g_comment, sizeof(g_comment), "xchg");
5745 assert_operand_cnt(1);
5746 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5747 fprintf(fout, " %s = ~%s;", buf1, buf1);
5751 assert_operand_cnt(2);
5752 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5753 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
5754 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
5755 strcpy(g_comment, "xlat");
5759 assert_operand_cnt(2);
5760 fprintf(fout, " %s = (s32)%s >> 31;",
5761 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5762 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5763 strcpy(g_comment, "cdq");
5767 if (po->flags & OPF_REP) {
5768 assert_operand_cnt(3);
5773 assert_operand_cnt(2);
5774 fprintf(fout, " %s = %sesi; esi %c= %d;",
5775 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
5776 lmod_cast_u_ptr(po, po->operand[1].lmod),
5777 (po->flags & OPF_DF) ? '-' : '+',
5778 lmod_bytes(po, po->operand[1].lmod));
5779 strcpy(g_comment, "lods");
5784 if (po->flags & OPF_REP) {
5785 assert_operand_cnt(3);
5786 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
5787 (po->flags & OPF_DF) ? '-' : '+',
5788 lmod_bytes(po, po->operand[1].lmod));
5789 fprintf(fout, " %sedi = eax;",
5790 lmod_cast_u_ptr(po, po->operand[1].lmod));
5791 strcpy(g_comment, "rep stos");
5794 assert_operand_cnt(2);
5795 fprintf(fout, " %sedi = eax; edi %c= %d;",
5796 lmod_cast_u_ptr(po, po->operand[1].lmod),
5797 (po->flags & OPF_DF) ? '-' : '+',
5798 lmod_bytes(po, po->operand[1].lmod));
5799 strcpy(g_comment, "stos");
5804 j = lmod_bytes(po, po->operand[0].lmod);
5805 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
5806 l = (po->flags & OPF_DF) ? '-' : '+';
5807 if (po->flags & OPF_REP) {
5808 assert_operand_cnt(3);
5810 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
5813 " %sedi = %sesi;", buf1, buf1);
5814 strcpy(g_comment, "rep movs");
5817 assert_operand_cnt(2);
5818 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
5819 buf1, buf1, l, j, l, j);
5820 strcpy(g_comment, "movs");
5825 // repe ~ repeat while ZF=1
5826 j = lmod_bytes(po, po->operand[0].lmod);
5827 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
5828 l = (po->flags & OPF_DF) ? '-' : '+';
5829 if (po->flags & OPF_REP) {
5830 assert_operand_cnt(3);
5832 " for (; ecx != 0; ecx--) {\n");
5833 if (pfomask & (1 << PFO_C)) {
5836 " cond_c = %sesi < %sedi;\n", buf1, buf1);
5837 pfomask &= ~(1 << PFO_C);
5840 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
5841 buf1, buf1, l, j, l, j);
5843 " if (cond_z %s 0) break;\n",
5844 (po->flags & OPF_REPZ) ? "==" : "!=");
5847 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
5848 (po->flags & OPF_REPZ) ? "e" : "ne");
5851 assert_operand_cnt(2);
5853 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
5854 buf1, buf1, l, j, l, j);
5855 strcpy(g_comment, "cmps");
5857 pfomask &= ~(1 << PFO_Z);
5858 last_arith_dst = NULL;
5859 delayed_flag_op = NULL;
5863 // only does ZF (for now)
5864 // repe ~ repeat while ZF=1
5865 j = lmod_bytes(po, po->operand[1].lmod);
5866 l = (po->flags & OPF_DF) ? '-' : '+';
5867 if (po->flags & OPF_REP) {
5868 assert_operand_cnt(3);
5870 " for (; ecx != 0; ecx--) {\n");
5872 " cond_z = (%seax == %sedi); edi %c= %d;\n",
5873 lmod_cast_u(po, po->operand[1].lmod),
5874 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
5876 " if (cond_z %s 0) break;\n",
5877 (po->flags & OPF_REPZ) ? "==" : "!=");
5880 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
5881 (po->flags & OPF_REPZ) ? "e" : "ne");
5884 assert_operand_cnt(2);
5885 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
5886 lmod_cast_u(po, po->operand[1].lmod),
5887 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
5888 strcpy(g_comment, "scas");
5890 pfomask &= ~(1 << PFO_Z);
5891 last_arith_dst = NULL;
5892 delayed_flag_op = NULL;
5895 // arithmetic w/flags
5897 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
5898 goto dualop_arith_const;
5899 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5903 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5904 if (po->operand[1].type == OPT_CONST) {
5905 j = lmod_bytes(po, po->operand[0].lmod);
5906 if (((1ull << j * 8) - 1) == po->operand[1].val)
5907 goto dualop_arith_const;
5912 assert_operand_cnt(2);
5913 fprintf(fout, " %s %s= %s;",
5914 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5916 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5917 output_std_flags(fout, po, &pfomask, buf1);
5918 last_arith_dst = &po->operand[0];
5919 delayed_flag_op = NULL;
5923 // and 0, or ~0 used instead mov
5924 assert_operand_cnt(2);
5925 fprintf(fout, " %s = %s;",
5926 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5927 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5928 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
5929 output_std_flags(fout, po, &pfomask, buf1);
5930 last_arith_dst = &po->operand[0];
5931 delayed_flag_op = NULL;
5936 assert_operand_cnt(2);
5937 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5938 if (pfomask & (1 << PFO_C)) {
5939 if (po->operand[1].type == OPT_CONST) {
5940 l = lmod_bytes(po, po->operand[0].lmod) * 8;
5941 j = po->operand[1].val;
5944 if (po->op == OP_SHL)
5948 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
5952 ferr(po, "zero shift?\n");
5956 pfomask &= ~(1 << PFO_C);
5958 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
5959 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5960 if (po->operand[1].type != OPT_CONST)
5961 fprintf(fout, " & 0x1f");
5963 output_std_flags(fout, po, &pfomask, buf1);
5964 last_arith_dst = &po->operand[0];
5965 delayed_flag_op = NULL;
5969 assert_operand_cnt(2);
5970 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5971 fprintf(fout, " %s = %s%s >> %s;", buf1,
5972 lmod_cast_s(po, po->operand[0].lmod), buf1,
5973 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5974 output_std_flags(fout, po, &pfomask, buf1);
5975 last_arith_dst = &po->operand[0];
5976 delayed_flag_op = NULL;
5981 assert_operand_cnt(3);
5982 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5983 l = lmod_bytes(po, po->operand[0].lmod) * 8;
5984 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
5985 if (po->operand[2].type != OPT_CONST) {
5986 // no handling for "undefined" case, hopefully not needed
5987 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
5990 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
5991 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5992 if (po->op == OP_SHLD) {
5993 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
5994 buf1, buf3, buf1, buf2, l, buf3);
5995 strcpy(g_comment, "shld");
5998 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
5999 buf1, buf3, buf1, buf2, l, buf3);
6000 strcpy(g_comment, "shrd");
6002 output_std_flags(fout, po, &pfomask, buf1);
6003 last_arith_dst = &po->operand[0];
6004 delayed_flag_op = NULL;
6009 assert_operand_cnt(2);
6010 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6011 if (po->operand[1].type == OPT_CONST) {
6012 j = po->operand[1].val;
6013 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
6014 fprintf(fout, po->op == OP_ROL ?
6015 " %s = (%s << %d) | (%s >> %d);" :
6016 " %s = (%s >> %d) | (%s << %d);",
6017 buf1, buf1, j, buf1,
6018 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
6022 output_std_flags(fout, po, &pfomask, buf1);
6023 last_arith_dst = &po->operand[0];
6024 delayed_flag_op = NULL;
6029 assert_operand_cnt(2);
6030 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6031 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6032 if (po->operand[1].type == OPT_CONST) {
6033 j = po->operand[1].val % l;
6035 ferr(po, "zero rotate\n");
6036 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
6037 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
6038 if (po->op == OP_RCL) {
6040 " %s = (%s << %d) | (cond_c << %d)",
6041 buf1, buf1, j, j - 1);
6043 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
6047 " %s = (%s >> %d) | (cond_c << %d)",
6048 buf1, buf1, j, l - j);
6050 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
6052 fprintf(fout, ";\n");
6053 fprintf(fout, " cond_c = tmp;");
6057 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
6058 output_std_flags(fout, po, &pfomask, buf1);
6059 last_arith_dst = &po->operand[0];
6060 delayed_flag_op = NULL;
6064 assert_operand_cnt(2);
6065 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6066 if (IS(opr_name(po, 0), opr_name(po, 1))) {
6067 // special case for XOR
6068 if (pfomask & (1 << PFO_BE)) { // weird, but it happens..
6069 fprintf(fout, " cond_be = 1;\n");
6070 pfomask &= ~(1 << PFO_BE);
6072 fprintf(fout, " %s = 0;",
6073 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6074 last_arith_dst = &po->operand[0];
6075 delayed_flag_op = NULL;
6081 assert_operand_cnt(2);
6082 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6083 if (pfomask & (1 << PFO_C)) {
6084 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6085 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6086 if (po->operand[0].lmod == OPLM_DWORD) {
6087 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
6088 fprintf(fout, " cond_c = tmp64 >> 32;\n");
6089 fprintf(fout, " %s = (u32)tmp64;",
6090 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6091 strcat(g_comment, " add64");
6094 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
6095 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
6096 fprintf(fout, " %s += %s;",
6097 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6100 pfomask &= ~(1 << PFO_C);
6101 output_std_flags(fout, po, &pfomask, buf1);
6102 last_arith_dst = &po->operand[0];
6103 delayed_flag_op = NULL;
6109 assert_operand_cnt(2);
6110 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6111 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
6112 for (j = 0; j <= PFO_LE; j++) {
6113 if (!(pfomask & (1 << j)))
6115 if (j == PFO_Z || j == PFO_S)
6118 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0);
6119 fprintf(fout, " cond_%s = %s;\n",
6120 parsed_flag_op_names[j], buf1);
6121 pfomask &= ~(1 << j);
6128 assert_operand_cnt(2);
6129 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6130 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6131 if (po->op == OP_SBB
6132 && IS(po->operand[0].name, po->operand[1].name))
6134 // avoid use of unitialized var
6135 fprintf(fout, " %s = -cond_c;", buf1);
6136 // carry remains what it was
6137 pfomask &= ~(1 << PFO_C);
6140 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
6141 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6143 output_std_flags(fout, po, &pfomask, buf1);
6144 last_arith_dst = &po->operand[0];
6145 delayed_flag_op = NULL;
6149 assert_operand_cnt(2);
6150 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6151 fprintf(fout, " %s = %s ? __builtin_ffs(%s) - 1 : 0;",
6152 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6154 output_std_flags(fout, po, &pfomask, buf1);
6155 last_arith_dst = &po->operand[0];
6156 delayed_flag_op = NULL;
6157 strcat(g_comment, " bsf");
6161 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
6162 for (j = 0; j <= PFO_LE; j++) {
6163 if (!(pfomask & (1 << j)))
6165 if (j == PFO_Z || j == PFO_S || j == PFO_C)
6168 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0);
6169 fprintf(fout, " cond_%s = %s;\n",
6170 parsed_flag_op_names[j], buf1);
6171 pfomask &= ~(1 << j);
6177 if (pfomask & (1 << PFO_C))
6178 // carry is unaffected by inc/dec.. wtf?
6179 ferr(po, "carry propagation needed\n");
6181 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6182 if (po->operand[0].type == OPT_REG) {
6183 strcpy(buf2, po->op == OP_INC ? "++" : "--");
6184 fprintf(fout, " %s%s;", buf1, buf2);
6187 strcpy(buf2, po->op == OP_INC ? "+" : "-");
6188 fprintf(fout, " %s %s= 1;", buf1, buf2);
6190 output_std_flags(fout, po, &pfomask, buf1);
6191 last_arith_dst = &po->operand[0];
6192 delayed_flag_op = NULL;
6196 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6197 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
6198 fprintf(fout, " %s = -%s%s;", buf1,
6199 lmod_cast_s(po, po->operand[0].lmod), buf2);
6200 last_arith_dst = &po->operand[0];
6201 delayed_flag_op = NULL;
6202 if (pfomask & (1 << PFO_C)) {
6203 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
6204 pfomask &= ~(1 << PFO_C);
6209 if (po->operand_cnt == 2) {
6210 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6213 if (po->operand_cnt == 3)
6214 ferr(po, "TODO imul3\n");
6217 assert_operand_cnt(1);
6218 switch (po->operand[0].lmod) {
6220 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
6221 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
6222 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
6223 fprintf(fout, " edx = tmp64 >> 32;\n");
6224 fprintf(fout, " eax = tmp64;");
6227 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
6228 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
6229 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
6233 ferr(po, "TODO: unhandled mul type\n");
6236 last_arith_dst = NULL;
6237 delayed_flag_op = NULL;
6242 assert_operand_cnt(1);
6243 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6244 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
6245 po->op == OP_IDIV));
6246 switch (po->operand[0].lmod) {
6248 if (po->flags & OPF_32BIT)
6249 snprintf(buf2, sizeof(buf2), "%seax", cast);
6251 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
6252 snprintf(buf2, sizeof(buf2), "%stmp64",
6253 (po->op == OP_IDIV) ? "(s64)" : "");
6255 if (po->operand[0].type == OPT_REG
6256 && po->operand[0].reg == xDX)
6258 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
6259 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
6262 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
6263 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
6267 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
6268 snprintf(buf2, sizeof(buf2), "%stmp",
6269 (po->op == OP_IDIV) ? "(s32)" : "");
6270 if (po->operand[0].type == OPT_REG
6271 && po->operand[0].reg == xDX)
6273 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
6275 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
6279 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
6281 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
6284 strcat(g_comment, " div16");
6287 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
6289 last_arith_dst = NULL;
6290 delayed_flag_op = NULL;
6295 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6297 for (j = 0; j < 8; j++) {
6298 if (pfomask & (1 << j)) {
6299 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
6300 fprintf(fout, " cond_%s = %s;",
6301 parsed_flag_op_names[j], buf1);
6308 last_arith_dst = NULL;
6309 delayed_flag_op = po;
6313 // SETcc - should already be handled
6316 // note: we reuse OP_Jcc for SETcc, only flags differ
6318 fprintf(fout, "\n goto %s;", po->operand[0].name);
6322 fprintf(fout, " if (ecx == 0)\n");
6323 fprintf(fout, " goto %s;", po->operand[0].name);
6324 strcat(g_comment, " jecxz");
6328 fprintf(fout, " if (--ecx != 0)\n");
6329 fprintf(fout, " goto %s;", po->operand[0].name);
6330 strcat(g_comment, " loop");
6334 assert_operand_cnt(1);
6335 last_arith_dst = NULL;
6336 delayed_flag_op = NULL;
6338 if (po->operand[0].type == OPT_REGMEM) {
6339 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
6342 ferr(po, "parse failure for jmp '%s'\n",
6343 po->operand[0].name);
6344 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
6347 else if (po->operand[0].type != OPT_LABEL)
6348 ferr(po, "unhandled jmp type\n");
6350 fprintf(fout, " goto %s;", po->operand[0].name);
6354 assert_operand_cnt(1);
6356 my_assert_not(pp, NULL);
6359 if (po->flags & OPF_CC) {
6360 // we treat conditional branch to another func
6361 // (yes such code exists..) as conditional tailcall
6363 fprintf(fout, " {\n");
6366 if (pp->is_fptr && !pp->is_arg) {
6367 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
6368 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6370 if (pp->is_unresolved)
6371 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
6372 buf3, asmfn, po->asmln, pp->name);
6375 fprintf(fout, "%s", buf3);
6376 if (strstr(pp->ret_type.name, "int64")) {
6377 if (po->flags & OPF_TAIL)
6378 ferr(po, "int64 and tail?\n");
6379 fprintf(fout, "tmp64 = ");
6381 else if (!IS(pp->ret_type.name, "void")) {
6382 if (po->flags & OPF_TAIL) {
6383 if (regmask_ret & mxAX) {
6384 fprintf(fout, "return ");
6385 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
6386 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
6388 else if (regmask_ret & mxST0)
6389 ferr(po, "float tailcall\n");
6391 else if (po->regmask_dst & mxAX) {
6392 fprintf(fout, "eax = ");
6393 if (pp->ret_type.is_ptr)
6394 fprintf(fout, "(u32)");
6396 else if (po->regmask_dst & mxST0) {
6397 ferr_assert(po, po->flags & OPF_FPUSH);
6398 if (need_float_stack)
6399 fprintf(fout, "f_st[--f_stp & 7] = ");
6401 fprintf(fout, "f_st0 = ");
6405 if (pp->name[0] == 0)
6406 ferr(po, "missing pp->name\n");
6407 fprintf(fout, "%s%s(", pp->name,
6408 pp->has_structarg ? "_sa" : "");
6410 if (po->flags & OPF_ATAIL) {
6411 if (pp->argc_stack != g_func_pp->argc_stack
6412 || (pp->argc_stack > 0
6413 && pp->is_stdcall != g_func_pp->is_stdcall))
6414 ferr(po, "incompatible tailcall\n");
6415 if (g_func_pp->has_retreg)
6416 ferr(po, "TODO: retreg+tailcall\n");
6418 for (arg = j = 0; arg < pp->argc; arg++) {
6420 fprintf(fout, ", ");
6423 if (pp->arg[arg].type.is_ptr)
6424 snprintf(cast, sizeof(cast), "(%s)",
6425 pp->arg[arg].type.name);
6427 if (pp->arg[arg].reg != NULL) {
6428 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6432 for (; j < g_func_pp->argc; j++)
6433 if (g_func_pp->arg[j].reg == NULL)
6435 fprintf(fout, "%sa%d", cast, j + 1);
6440 for (arg = 0; arg < pp->argc; arg++) {
6442 fprintf(fout, ", ");
6445 if (pp->arg[arg].type.is_ptr)
6446 snprintf(cast, sizeof(cast), "(%s)",
6447 pp->arg[arg].type.name);
6449 if (pp->arg[arg].reg != NULL) {
6450 if (pp->arg[arg].type.is_retreg)
6451 fprintf(fout, "&%s", pp->arg[arg].reg);
6453 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6458 tmp_op = pp->arg[arg].datap;
6460 ferr(po, "parsed_op missing for arg%d\n", arg);
6462 if (tmp_op->flags & OPF_VAPUSH) {
6463 fprintf(fout, "ap");
6465 else if (tmp_op->p_argpass != 0) {
6466 fprintf(fout, "a%d", tmp_op->p_argpass);
6468 else if (tmp_op->p_argnum != 0) {
6469 fprintf(fout, "%s%s", cast,
6470 saved_arg_name(buf1, sizeof(buf1),
6471 tmp_op->p_arggrp, tmp_op->p_argnum));
6475 out_src_opr(buf1, sizeof(buf1),
6476 tmp_op, &tmp_op->operand[0], cast, 0));
6480 fprintf(fout, ");");
6482 if (strstr(pp->ret_type.name, "int64")) {
6483 fprintf(fout, "\n");
6484 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
6485 fprintf(fout, "%seax = tmp64;", buf3);
6488 if (pp->is_unresolved) {
6489 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
6491 strcat(g_comment, buf2);
6494 if (po->flags & OPF_TAIL) {
6496 if (i == opcnt - 1 || pp->is_noreturn)
6498 else if (IS(pp->ret_type.name, "void"))
6500 else if (!(regmask_ret & (1 << xAX)))
6502 // else already handled as 'return f()'
6505 fprintf(fout, "\n%sreturn;", buf3);
6506 strcat(g_comment, " ^ tailcall");
6509 strcat(g_comment, " tailcall");
6511 if ((regmask_ret & (1 << xAX))
6512 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
6514 ferr(po, "int func -> void func tailcall?\n");
6517 if (pp->is_noreturn)
6518 strcat(g_comment, " noreturn");
6519 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
6520 strcat(g_comment, " argframe");
6521 if (po->flags & OPF_CC)
6522 strcat(g_comment, " cond");
6524 if (po->flags & OPF_CC)
6525 fprintf(fout, "\n }");
6527 delayed_flag_op = NULL;
6528 last_arith_dst = NULL;
6532 if (g_func_pp->is_vararg)
6533 fprintf(fout, " va_end(ap);\n");
6534 if (g_func_pp->has_retreg) {
6535 for (arg = 0; arg < g_func_pp->argc; arg++)
6536 if (g_func_pp->arg[arg].type.is_retreg)
6537 fprintf(fout, " *r_%s = %s;\n",
6538 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
6541 if (!(regmask_ret & (1 << xAX))) {
6542 if (i != opcnt - 1 || label_pending)
6543 fprintf(fout, " return;");
6545 else if (g_func_pp->ret_type.is_ptr) {
6546 fprintf(fout, " return (%s)eax;",
6547 g_func_pp->ret_type.name);
6549 else if (IS(g_func_pp->ret_type.name, "__int64"))
6550 fprintf(fout, " return ((u64)edx << 32) | eax;");
6552 fprintf(fout, " return eax;");
6554 last_arith_dst = NULL;
6555 delayed_flag_op = NULL;
6559 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6560 if (po->p_argnum != 0) {
6561 // special case - saved func arg
6562 fprintf(fout, " %s = %s;",
6563 saved_arg_name(buf2, sizeof(buf2),
6564 po->p_arggrp, po->p_argnum), buf1);
6567 else if (po->flags & OPF_RSAVE) {
6568 fprintf(fout, " s_%s = %s;", buf1, buf1);
6571 else if (po->flags & OPF_PPUSH) {
6573 ferr_assert(po, tmp_op != NULL);
6574 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
6575 fprintf(fout, " pp_%s = %s;", buf2, buf1);
6578 else if (g_func_pp->is_userstack) {
6579 fprintf(fout, " *(--esp) = %s;", buf1);
6582 if (!(g_ida_func_attr & IDAFA_NORETURN))
6583 ferr(po, "stray push encountered\n");
6588 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6589 if (po->flags & OPF_RSAVE) {
6590 fprintf(fout, " %s = s_%s;", buf1, buf1);
6593 else if (po->flags & OPF_PPUSH) {
6594 // push/pop graph / non-const
6595 ferr_assert(po, po->datap == NULL);
6596 fprintf(fout, " %s = pp_%s;", buf1, buf1);
6599 else if (po->datap != NULL) {
6602 fprintf(fout, " %s = %s;", buf1,
6603 out_src_opr(buf2, sizeof(buf2),
6604 tmp_op, &tmp_op->operand[0],
6605 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6608 else if (g_func_pp->is_userstack) {
6609 fprintf(fout, " %s = *esp++;", buf1);
6613 ferr(po, "stray pop encountered\n");
6622 if (need_float_stack) {
6623 out_src_opr_float(buf1, sizeof(buf1),
6624 po, &po->operand[0], 1);
6625 if (po->regmask_src & mxSTa) {
6626 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
6630 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
6633 if (po->flags & OPF_FSHIFT)
6634 fprintf(fout, " f_st1 = f_st0;");
6635 if (po->operand[0].type == OPT_REG
6636 && po->operand[0].reg == xST0)
6638 strcat(g_comment, " fld st");
6641 fprintf(fout, " f_st0 = %s;",
6642 out_src_opr_float(buf1, sizeof(buf1),
6643 po, &po->operand[0], 0));
6645 strcat(g_comment, " fld");
6649 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6650 lmod_cast(po, po->operand[0].lmod, 1), 0);
6651 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
6652 if (need_float_stack) {
6653 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
6656 if (po->flags & OPF_FSHIFT)
6657 fprintf(fout, " f_st1 = f_st0;");
6658 fprintf(fout, " f_st0 = %s;", buf2);
6660 strcat(g_comment, " fild");
6664 if (need_float_stack)
6665 fprintf(fout, " f_st[--f_stp & 7] = ");
6667 if (po->flags & OPF_FSHIFT)
6668 fprintf(fout, " f_st1 = f_st0;");
6669 fprintf(fout, " f_st0 = ");
6671 switch (po->operand[0].val) {
6672 case X87_CONST_1: fprintf(fout, "1.0;"); break;
6673 case X87_CONST_LN2: fprintf(fout, "0.693147180559945;"); break;
6674 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
6675 default: ferr(po, "TODO\n"); break;
6680 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
6682 dead_dst = po->operand[0].type == OPT_REG
6683 && po->operand[0].reg == xST0;
6684 if (need_float_stack) {
6686 fprintf(fout, " %s = f_st[f_stp & 7];", buf1);
6687 if (po->flags & OPF_FSHIFT)
6688 fprintf(fout, " f_stp++;");
6692 fprintf(fout, " %s = f_st0;", buf1);
6693 if (po->flags & OPF_FSHIFT)
6694 fprintf(fout, " f_st0 = f_st1;");
6696 if (dead_dst && !(po->flags & OPF_FSHIFT))
6699 strcat(g_comment, " fst");
6706 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
6708 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
6710 dead_dst = (po->flags & OPF_FPOP)
6711 && po->operand[0].type == OPT_REG
6712 && po->operand[0].reg == xST0;
6714 case OP_FADD: j = '+'; break;
6715 case OP_FDIV: j = '/'; break;
6716 case OP_FMUL: j = '*'; break;
6717 case OP_FSUB: j = '-'; break;
6718 default: j = 'x'; break;
6720 if (need_float_stack) {
6722 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
6723 if (po->flags & OPF_FSHIFT)
6724 fprintf(fout, " f_stp++;");
6727 if (po->flags & OPF_FSHIFT) {
6728 // note: assumes only 2 regs handled
6730 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
6732 fprintf(fout, " f_st0 = f_st1;");
6735 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
6737 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
6742 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
6744 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
6746 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
6748 dead_dst = (po->flags & OPF_FPOP)
6749 && po->operand[0].type == OPT_REG
6750 && po->operand[0].reg == xST0;
6751 j = po->op == OP_FDIVR ? '/' : '-';
6752 if (need_float_stack) {
6754 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
6755 if (po->flags & OPF_FSHIFT)
6756 fprintf(fout, " f_stp++;");
6759 if (po->flags & OPF_FSHIFT) {
6761 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
6763 fprintf(fout, " f_st0 = f_st1;");
6766 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
6768 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
6776 case OP_FIADD: j = '+'; break;
6777 case OP_FIDIV: j = '/'; break;
6778 case OP_FIMUL: j = '*'; break;
6779 case OP_FISUB: j = '-'; break;
6780 default: j = 'x'; break;
6782 fprintf(fout, " %s %c= (%s)%s;", float_st0,
6784 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6785 lmod_cast(po, po->operand[0].lmod, 1), 0));
6790 fprintf(fout, " %s = %s %c %s;", float_st0,
6791 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
6793 po->op == OP_FIDIVR ? '/' : '-', float_st0);
6797 fprintf(fout, " %s = -%s;", float_st0, float_st0);
6801 fprintf(fout, " %s = cos%s(%s);", float_st0,
6802 need_double ? "" : "f", float_st0);
6806 if (need_float_stack) {
6807 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
6808 need_double ? "" : "f", float_st1, float_st0);
6809 fprintf(fout, " f_stp++;");
6812 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
6813 need_double ? "" : "f");
6818 if (need_float_stack) {
6819 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
6820 float_st1, need_double ? "" : "f", float_st0);
6821 fprintf(fout, " f_stp++;");
6824 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
6825 need_double ? "" : "f");
6830 fprintf(fout, " %s = sin%s(%s);", float_st0,
6831 need_double ? "" : "f", float_st0);
6835 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
6836 need_double ? "" : "f", float_st0);
6840 dead_dst = po->operand[0].type == OPT_REG
6841 && po->operand[0].reg == xST0;
6843 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
6845 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
6846 float_st0, float_st0, buf1, buf1);
6847 strcat(g_comment, " fxch");
6854 ferr_assert(po, po->flags & OPF_32BIT);
6855 fprintf(fout, " eax = (s32)%s;", float_st0);
6856 if (po->flags & OPF_FSHIFT) {
6857 if (need_float_stack)
6858 fprintf(fout, " f_stp++;");
6860 fprintf(fout, " f_st0 = f_st1;");
6862 strcat(g_comment, " ftol");
6867 strcpy(g_comment, " (emms)");
6872 ferr(po, "unhandled op type %d, flags %x\n",
6877 if (g_comment[0] != 0) {
6878 char *p = g_comment;
6879 while (my_isblank(*p))
6881 fprintf(fout, " // %s", p);
6886 fprintf(fout, "\n");
6888 // some sanity checking
6889 if (po->flags & OPF_REP) {
6890 if (po->op != OP_STOS && po->op != OP_MOVS
6891 && po->op != OP_CMPS && po->op != OP_SCAS)
6892 ferr(po, "unexpected rep\n");
6893 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
6894 && (po->op == OP_CMPS || po->op == OP_SCAS))
6895 ferr(po, "cmps/scas with plain rep\n");
6897 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
6898 && po->op != OP_CMPS && po->op != OP_SCAS)
6899 ferr(po, "unexpected repz/repnz\n");
6902 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
6904 // see is delayed flag stuff is still valid
6905 if (delayed_flag_op != NULL && delayed_flag_op != po) {
6906 if (is_any_opr_modified(delayed_flag_op, po, 0))
6907 delayed_flag_op = NULL;
6910 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
6911 if (is_opr_modified(last_arith_dst, po))
6912 last_arith_dst = NULL;
6918 if (g_stack_fsz && !g_stack_frame_used)
6919 fprintf(fout, " (void)sf;\n");
6921 fprintf(fout, "}\n\n");
6923 gen_x_cleanup(opcnt);
6926 static void gen_x_cleanup(int opcnt)
6930 for (i = 0; i < opcnt; i++) {
6931 struct label_ref *lr, *lr_del;
6933 lr = g_label_refs[i].next;
6934 while (lr != NULL) {
6939 g_label_refs[i].i = -1;
6940 g_label_refs[i].next = NULL;
6942 if (ops[i].op == OP_CALL) {
6944 proto_release(ops[i].pp);
6950 struct func_proto_dep;
6952 struct func_prototype {
6957 int has_ret:3; // -1, 0, 1: unresolved, no, yes
6958 unsigned int dep_resolved:1;
6959 unsigned int is_stdcall:1;
6960 struct func_proto_dep *dep_func;
6962 const struct parsed_proto *pp; // seed pp, if any
6965 struct func_proto_dep {
6967 struct func_prototype *proto;
6968 int regmask_live; // .. at the time of call
6969 unsigned int ret_dep:1; // return from this is caller's return
6972 static struct func_prototype *hg_fp;
6973 static int hg_fp_cnt;
6975 static struct scanned_var {
6977 enum opr_lenmod lmod;
6978 unsigned int is_seeded:1;
6979 unsigned int is_c_str:1;
6980 const struct parsed_proto *pp; // seed pp, if any
6982 static int hg_var_cnt;
6984 static char **hg_refs;
6985 static int hg_ref_cnt;
6987 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
6990 static struct func_prototype *hg_fp_add(const char *funcn)
6992 struct func_prototype *fp;
6994 if ((hg_fp_cnt & 0xff) == 0) {
6995 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
6996 my_assert_not(hg_fp, NULL);
6997 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
7000 fp = &hg_fp[hg_fp_cnt];
7001 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
7003 fp->argc_stack = -1;
7009 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
7014 for (i = 0; i < fp->dep_func_cnt; i++)
7015 if (IS(fp->dep_func[i].name, name))
7016 return &fp->dep_func[i];
7021 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
7024 if (hg_fp_find_dep(fp, name))
7027 if ((fp->dep_func_cnt & 0xff) == 0) {
7028 fp->dep_func = realloc(fp->dep_func,
7029 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
7030 my_assert_not(fp->dep_func, NULL);
7031 memset(&fp->dep_func[fp->dep_func_cnt], 0,
7032 sizeof(fp->dep_func[0]) * 0x100);
7034 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
7038 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
7040 const struct func_prototype *p1 = p1_, *p2 = p2_;
7041 return strcmp(p1->name, p2->name);
7045 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
7047 const struct func_prototype *p1 = p1_, *p2 = p2_;
7048 return p1->id - p2->id;
7052 static void hg_ref_add(const char *name)
7054 if ((hg_ref_cnt & 0xff) == 0) {
7055 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
7056 my_assert_not(hg_refs, NULL);
7057 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
7060 hg_refs[hg_ref_cnt] = strdup(name);
7061 my_assert_not(hg_refs[hg_ref_cnt], NULL);
7065 // recursive register dep pass
7066 // - track saved regs (part 2)
7067 // - try to figure out arg-regs
7068 // - calculate reg deps
7069 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
7070 struct func_prototype *fp, int regmask_save, int regmask_dst,
7071 int *regmask_dep, int *has_ret)
7073 struct func_proto_dep *dep;
7074 struct parsed_op *po;
7075 int from_caller = 0;
7080 for (; i < opcnt; i++)
7082 if (cbits[i >> 3] & (1 << (i & 7)))
7084 cbits[i >> 3] |= (1 << (i & 7));
7088 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
7089 if (po->flags & OPF_RMD)
7092 if (po->btj != NULL) {
7094 for (j = 0; j < po->btj->count; j++) {
7095 check_i(po, po->btj->d[j].bt_i);
7096 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
7097 regmask_save, regmask_dst, regmask_dep, has_ret);
7102 check_i(po, po->bt_i);
7103 if (po->flags & OPF_CJMP) {
7104 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
7105 regmask_save, regmask_dst, regmask_dep, has_ret);
7113 if (po->flags & OPF_FARG)
7114 /* (just calculate register deps) */;
7115 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
7117 reg = po->operand[0].reg;
7118 ferr_assert(po, reg >= 0);
7120 if (po->flags & OPF_RSAVE) {
7121 regmask_save |= 1 << reg;
7124 if (po->flags & OPF_DONE)
7127 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0);
7129 regmask_save |= 1 << reg;
7130 po->flags |= OPF_RMD;
7131 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, OPF_RMD);
7135 else if (po->flags & OPF_RMD)
7137 else if (po->op == OP_CALL) {
7138 po->regmask_dst |= 1 << xAX;
7140 dep = hg_fp_find_dep(fp, po->operand[0].name);
7142 dep->regmask_live = regmask_save | regmask_dst;
7144 else if (po->op == OP_RET) {
7145 if (po->operand_cnt > 0) {
7147 if (fp->argc_stack >= 0
7148 && fp->argc_stack != po->operand[0].val / 4)
7149 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
7150 fp->argc_stack = po->operand[0].val / 4;
7154 // if has_ret is 0, there is uninitialized eax path,
7155 // which means it's most likely void func
7156 if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
7157 if (po->op == OP_CALL) {
7162 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
7165 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
7168 if (ret != 1 && from_caller) {
7169 // unresolved eax - probably void func
7173 if (j >= 0 && ops[j].op == OP_CALL) {
7174 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
7185 l = regmask_save | regmask_dst;
7186 if (g_bp_frame && !(po->flags & OPF_EBP_S))
7189 l = po->regmask_src & ~l;
7192 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
7193 l, regmask_dst, regmask_save, po->flags);
7196 regmask_dst |= po->regmask_dst;
7198 if (po->flags & OPF_TAIL)
7203 static void gen_hdr(const char *funcn, int opcnt)
7205 int save_arg_vars[MAX_ARG_GRP] = { 0, };
7206 unsigned char cbits[MAX_OPS / 8];
7207 const struct parsed_proto *pp_c;
7208 struct parsed_proto *pp;
7209 struct func_prototype *fp;
7210 struct parsed_op *po;
7211 int regmask_dummy = 0;
7213 int max_bp_offset = 0;
7218 pp_c = proto_parse(g_fhdr, funcn, 1);
7220 // already in seed, will add to hg_fp later
7223 fp = hg_fp_add(funcn);
7225 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
7226 g_stack_frame_used = 0;
7229 // - resolve all branches
7230 // - parse calls with labels
7231 resolve_branches_parse_calls(opcnt);
7234 // - handle ebp/esp frame, remove ops related to it
7235 scan_prologue_epilogue(opcnt);
7238 // - remove dead labels
7240 for (i = 0; i < opcnt; i++)
7242 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7248 if (po->flags & (OPF_RMD|OPF_DONE))
7251 if (po->op == OP_CALL) {
7252 if (po->operand[0].type == OPT_LABEL)
7253 hg_fp_add_dep(fp, opr_name(po, 0));
7254 else if (po->pp != NULL)
7255 hg_fp_add_dep(fp, po->pp->name);
7260 // - remove dead labels
7261 // - handle push <const>/pop pairs
7262 for (i = 0; i < opcnt; i++)
7264 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7270 if (po->flags & (OPF_RMD|OPF_DONE))
7273 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
7274 scan_for_pop_const(i, opcnt, i + opcnt * 13);
7278 // - process trivial calls
7279 for (i = 0; i < opcnt; i++)
7282 if (po->flags & (OPF_RMD|OPF_DONE))
7285 if (po->op == OP_CALL)
7287 pp = process_call_early(i, opcnt, &j);
7289 if (!(po->flags & OPF_ATAIL))
7290 // since we know the args, try to collect them
7291 if (collect_call_args_early(po, i, pp, ®mask_dummy) != 0)
7297 // commit esp adjust
7298 if (ops[j].op != OP_POP)
7299 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
7301 for (l = 0; l < pp->argc_stack; l++)
7302 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
7306 po->flags |= OPF_DONE;
7312 // - track saved regs (simple)
7314 for (i = 0; i < opcnt; i++)
7317 if (po->flags & (OPF_RMD|OPF_DONE))
7320 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
7321 && po->operand[0].reg != xCX)
7323 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
7325 // regmask_save |= 1 << po->operand[0].reg; // do it later
7326 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
7327 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
7330 else if (po->op == OP_CALL)
7332 pp = process_call(i, opcnt);
7334 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
7335 // since we know the args, collect them
7336 ret = collect_call_args(po, i, pp, ®mask_dummy, save_arg_vars,
7343 memset(cbits, 0, sizeof(cbits));
7347 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, ®mask_dep, &has_ret);
7349 // find unreachable code - must be fixed in IDA
7350 for (i = 0; i < opcnt; i++)
7352 if (cbits[i >> 3] & (1 << (i & 7)))
7355 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
7356 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
7358 // the compiler sometimes still generates code after
7359 // noreturn OS functions
7362 if (ops[i].op != OP_NOP)
7363 ferr(&ops[i], "unreachable code\n");
7366 for (i = 0; i < g_eqcnt; i++) {
7367 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
7368 max_bp_offset = g_eqs[i].offset;
7371 if (fp->argc_stack < 0) {
7372 max_bp_offset = (max_bp_offset + 3) & ~3;
7373 fp->argc_stack = max_bp_offset / 4;
7374 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
7378 fp->regmask_dep = regmask_dep & ~(1 << xSP);
7379 fp->has_ret = has_ret;
7381 printf("// has_ret %d, regmask_dep %x\n",
7382 fp->has_ret, fp->regmask_dep);
7383 output_hdr_fp(stdout, fp, 1);
7384 if (IS(funcn, "sub_10007F72")) exit(1);
7387 gen_x_cleanup(opcnt);
7390 static void hg_fp_resolve_deps(struct func_prototype *fp)
7392 struct func_prototype fp_s;
7396 // this thing is recursive, so mark first..
7397 fp->dep_resolved = 1;
7399 for (i = 0; i < fp->dep_func_cnt; i++) {
7400 strcpy(fp_s.name, fp->dep_func[i].name);
7401 fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
7402 sizeof(hg_fp[0]), hg_fp_cmp_name);
7403 if (fp->dep_func[i].proto != NULL) {
7404 if (!fp->dep_func[i].proto->dep_resolved)
7405 hg_fp_resolve_deps(fp->dep_func[i].proto);
7407 dep = ~fp->dep_func[i].regmask_live
7408 & fp->dep_func[i].proto->regmask_dep;
7409 fp->regmask_dep |= dep;
7410 // printf("dep %s %s |= %x\n", fp->name,
7411 // fp->dep_func[i].name, dep);
7413 if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
7414 fp->has_ret = fp->dep_func[i].proto->has_ret;
7419 // make all thiscall/edx arg functions referenced from .data fastcall
7420 static void do_func_refs_from_data(void)
7422 struct func_prototype *fp, fp_s;
7425 for (i = 0; i < hg_ref_cnt; i++) {
7426 strcpy(fp_s.name, hg_refs[i]);
7427 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
7428 sizeof(hg_fp[0]), hg_fp_cmp_name);
7432 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
7433 fp->regmask_dep |= mxCX | mxDX;
7437 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7440 const struct parsed_proto *pp;
7441 char *p, namebuf[NAMELEN];
7447 for (; count > 0; count--, fp++) {
7448 if (fp->has_ret == -1)
7449 fprintf(fout, "// ret unresolved\n");
7451 fprintf(fout, "// dep:");
7452 for (j = 0; j < fp->dep_func_cnt; j++) {
7453 fprintf(fout, " %s/", fp->dep_func[j].name);
7454 if (fp->dep_func[j].proto != NULL)
7455 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
7456 fp->dep_func[j].proto->has_ret);
7458 fprintf(fout, "\n");
7461 p = strchr(fp->name, '@');
7463 memcpy(namebuf, fp->name, p - fp->name);
7464 namebuf[p - fp->name] = 0;
7472 pp = proto_parse(g_fhdr, name, 1);
7473 if (pp != NULL && pp->is_include)
7476 if (fp->pp != NULL) {
7477 // part of seed, output later
7481 regmask_dep = fp->regmask_dep;
7482 argc_normal = fp->argc_stack;
7484 fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
7485 (fp->has_ret ? "int" : "void"));
7486 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
7487 && (regmask_dep & ~mxCX) == 0)
7489 fprintf(fout, "/*__thiscall*/ ");
7493 else if (regmask_dep && (fp->is_stdcall || fp->argc_stack == 0)
7494 && (regmask_dep & ~(mxCX | mxDX)) == 0)
7496 fprintf(fout, " __fastcall ");
7497 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
7503 else if (regmask_dep && !fp->is_stdcall) {
7504 fprintf(fout, "/*__usercall*/ ");
7506 else if (regmask_dep) {
7507 fprintf(fout, "/*__userpurge*/ ");
7509 else if (fp->is_stdcall)
7510 fprintf(fout, " __stdcall ");
7512 fprintf(fout, " __cdecl ");
7514 fprintf(fout, "%s(", name);
7517 for (j = 0; j < xSP; j++) {
7518 if (regmask_dep & (1 << j)) {
7521 fprintf(fout, ", ");
7523 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
7525 fprintf(fout, "int");
7526 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
7530 for (j = 0; j < argc_normal; j++) {
7533 fprintf(fout, ", ");
7534 if (fp->pp != NULL) {
7535 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
7536 if (!fp->pp->arg[arg - 1].type.is_ptr)
7540 fprintf(fout, "int ");
7541 fprintf(fout, "a%d", arg);
7544 fprintf(fout, ");\n");
7548 static void output_hdr(FILE *fout)
7550 static const char *lmod_c_names[] = {
7551 [OPLM_UNSPEC] = "???",
7552 [OPLM_BYTE] = "uint8_t",
7553 [OPLM_WORD] = "uint16_t",
7554 [OPLM_DWORD] = "uint32_t",
7555 [OPLM_QWORD] = "uint64_t",
7557 const struct scanned_var *var;
7558 struct func_prototype *fp;
7559 char line[256] = { 0, };
7563 // add stuff from headers
7564 for (i = 0; i < pp_cache_size; i++) {
7565 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
7566 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
7568 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
7569 fp = hg_fp_add(name);
7570 fp->pp = &pp_cache[i];
7571 fp->argc_stack = fp->pp->argc_stack;
7572 fp->is_stdcall = fp->pp->is_stdcall;
7573 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
7574 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
7578 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
7579 for (i = 0; i < hg_fp_cnt; i++)
7580 hg_fp_resolve_deps(&hg_fp[i]);
7582 // adjust functions referenced from data segment
7583 do_func_refs_from_data();
7585 // note: messes up .proto ptr, don't use
7586 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
7589 for (i = 0; i < hg_var_cnt; i++) {
7592 if (var->pp != NULL)
7595 else if (var->is_c_str)
7596 fprintf(fout, "extern %-8s %s[];", "char", var->name);
7598 fprintf(fout, "extern %-8s %s;",
7599 lmod_c_names[var->lmod], var->name);
7602 fprintf(fout, " // seeded");
7603 fprintf(fout, "\n");
7606 fprintf(fout, "\n");
7608 // output function prototypes
7609 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
7612 fprintf(fout, "\n// - seed -\n");
7615 while (fgets(line, sizeof(line), g_fhdr))
7616 fwrite(line, 1, strlen(line), fout);
7619 // '=' needs special treatment
7621 static char *next_word_s(char *w, size_t wsize, char *s)
7628 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
7630 for (i = 1; i < wsize - 1; i++) {
7632 printf("warning: missing closing quote: \"%s\"\n", s);
7641 for (; i < wsize - 1; i++) {
7642 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
7648 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
7649 printf("warning: '%s' truncated\n", w);
7654 static int cmpstringp(const void *p1, const void *p2)
7656 return strcmp(*(char * const *)p1, *(char * const *)p2);
7659 static int is_xref_needed(char *p, char **rlist, int rlist_len)
7664 if (strstr(p, "..."))
7665 // unable to determine, assume needed
7668 if (*p == '.') // .text, .data, ...
7669 // ref from other data or non-function -> no
7672 p2 = strpbrk(p, "+:\r\n\x18");
7675 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
7676 // referenced from removed code
7682 static int ida_xrefs_show_need(FILE *fasm, char *p,
7683 char **rlist, int rlist_len)
7689 p = strrchr(p, ';');
7690 if (p != NULL && *p == ';' && IS_START(p + 2, "DATA XREF: ")) {
7692 if (is_xref_needed(p, rlist, rlist_len))
7699 if (!my_fgets(line, sizeof(line), fasm))
7701 // non-first line is always indented
7702 if (!my_isblank(line[0]))
7705 // should be no content, just comment
7710 p = strrchr(p, ';');
7712 // it's printed once, but no harm to check again
7713 if (IS_START(p, "DATA XREF: "))
7716 if (is_xref_needed(p, rlist, rlist_len)) {
7721 fseek(fasm, pos, SEEK_SET);
7725 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
7727 struct scanned_var *var;
7728 char line[256] = { 0, };
7737 // skip to next data section
7738 while (my_fgets(line, sizeof(line), fasm))
7743 if (*p == 0 || *p == ';')
7746 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
7747 if (*p == 0 || *p == ';')
7750 if (*p != 's' || !IS_START(p, "segment para public"))
7756 if (p == NULL || !IS_START(p, "segment para public"))
7760 if (!IS_START(p, "'DATA'"))
7764 while (my_fgets(line, sizeof(line), fasm))
7769 no_identifier = my_isblank(*p);
7772 if (*p == 0 || *p == ';')
7775 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
7776 words[wordc][0] = 0;
7777 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
7778 if (*p == 0 || *p == ';') {
7784 if (wordc == 2 && IS(words[1], "ends"))
7789 if (no_identifier) {
7790 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
7791 hg_ref_add(words[2]);
7795 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
7796 // when this starts, we don't need anything from this section
7800 // check refs comment(s)
7801 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
7804 if ((hg_var_cnt & 0xff) == 0) {
7805 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
7806 * (hg_var_cnt + 0x100));
7807 my_assert_not(hg_vars, NULL);
7808 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
7811 var = &hg_vars[hg_var_cnt++];
7812 snprintf(var->name, sizeof(var->name), "%s", words[0]);
7814 // maybe already in seed header?
7815 var->pp = proto_parse(g_fhdr, var->name, 1);
7816 if (var->pp != NULL) {
7817 if (var->pp->is_fptr) {
7818 var->lmod = OPLM_DWORD;
7821 else if (var->pp->is_func)
7823 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
7824 aerr("unhandled C type '%s' for '%s'\n",
7825 var->pp->type.name, var->name);
7831 if (IS(words[1], "dd")) {
7832 var->lmod = OPLM_DWORD;
7833 if (wordc >= 4 && IS(words[2], "offset"))
7834 hg_ref_add(words[3]);
7836 else if (IS(words[1], "dw"))
7837 var->lmod = OPLM_WORD;
7838 else if (IS(words[1], "db")) {
7839 var->lmod = OPLM_BYTE;
7840 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
7841 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
7845 else if (IS(words[1], "dq"))
7846 var->lmod = OPLM_QWORD;
7847 //else if (IS(words[1], "dt"))
7849 aerr("type '%s' not known\n", words[1]);
7857 static void set_label(int i, const char *name)
7863 p = strchr(name, ':');
7867 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
7868 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
7869 g_labels[i] = realloc(g_labels[i], len + 1);
7870 my_assert_not(g_labels[i], NULL);
7871 memcpy(g_labels[i], name, len);
7872 g_labels[i][len] = 0;
7881 static struct chunk_item *func_chunks;
7882 static int func_chunk_cnt;
7883 static int func_chunk_alloc;
7885 static void add_func_chunk(FILE *fasm, const char *name, int line)
7887 if (func_chunk_cnt >= func_chunk_alloc) {
7888 func_chunk_alloc *= 2;
7889 func_chunks = realloc(func_chunks,
7890 func_chunk_alloc * sizeof(func_chunks[0]));
7891 my_assert_not(func_chunks, NULL);
7893 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
7894 func_chunks[func_chunk_cnt].name = strdup(name);
7895 func_chunks[func_chunk_cnt].asmln = line;
7899 static int cmp_chunks(const void *p1, const void *p2)
7901 const struct chunk_item *c1 = p1, *c2 = p2;
7902 return strcmp(c1->name, c2->name);
7905 static void scan_ahead(FILE *fasm)
7915 oldpos = ftell(fasm);
7918 while (my_fgets(line, sizeof(line), fasm))
7929 // get rid of random tabs
7930 for (i = 0; line[i] != 0; i++)
7931 if (line[i] == '\t')
7934 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
7937 next_word(words[0], sizeof(words[0]), p);
7938 if (words[0][0] == 0)
7939 aerr("missing name for func chunk?\n");
7941 add_func_chunk(fasm, words[0], asmln);
7943 else if (IS_START(p, "; sctend"))
7949 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
7950 words[wordc][0] = 0;
7951 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
7952 if (*p == 0 || *p == ';') {
7958 if (wordc == 2 && IS(words[1], "ends"))
7962 fseek(fasm, oldpos, SEEK_SET);
7966 int main(int argc, char *argv[])
7968 FILE *fout, *fasm, *frlist;
7969 struct parsed_data *pd = NULL;
7971 char **rlist = NULL;
7973 int rlist_alloc = 0;
7974 int func_chunks_used = 0;
7975 int func_chunks_sorted = 0;
7976 int func_chunk_i = -1;
7977 long func_chunk_ret = 0;
7978 int func_chunk_ret_ln = 0;
7979 int scanned_ahead = 0;
7981 char words[20][256];
7982 enum opr_lenmod lmod;
7983 char *sctproto = NULL;
7985 int pending_endp = 0;
7987 int skip_warned = 0;
8000 for (arg = 1; arg < argc; arg++) {
8001 if (IS(argv[arg], "-v"))
8003 else if (IS(argv[arg], "-rf"))
8004 g_allow_regfunc = 1;
8005 else if (IS(argv[arg], "-m"))
8007 else if (IS(argv[arg], "-hdr"))
8008 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
8013 if (argc < arg + 3) {
8014 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
8015 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
8017 " -hdr - header generation mode\n"
8018 " -rf - allow unannotated indirect calls\n"
8019 " -m - allow multiple .text sections\n"
8020 "[rlist] is a file with function names to skip,"
8028 asmfn = argv[arg++];
8029 fasm = fopen(asmfn, "r");
8030 my_assert_not(fasm, NULL);
8032 hdrfn = argv[arg++];
8033 g_fhdr = fopen(hdrfn, "r");
8034 my_assert_not(g_fhdr, NULL);
8037 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
8038 my_assert_not(rlist, NULL);
8039 // needs special handling..
8040 rlist[rlist_len++] = "__alloca_probe";
8042 func_chunk_alloc = 32;
8043 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
8044 my_assert_not(func_chunks, NULL);
8046 memset(words, 0, sizeof(words));
8048 for (; arg < argc; arg++) {
8049 frlist = fopen(argv[arg], "r");
8050 my_assert_not(frlist, NULL);
8052 while (my_fgets(line, sizeof(line), frlist)) {
8054 if (*p == 0 || *p == ';')
8057 if (IS_START(p, "#if 0")
8058 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
8062 else if (IS_START(p, "#endif"))
8069 p = next_word(words[0], sizeof(words[0]), p);
8070 if (words[0][0] == 0)
8073 if (rlist_len >= rlist_alloc) {
8074 rlist_alloc = rlist_alloc * 2 + 64;
8075 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
8076 my_assert_not(rlist, NULL);
8078 rlist[rlist_len++] = strdup(words[0]);
8087 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
8089 fout = fopen(argv[arg_out], "w");
8090 my_assert_not(fout, NULL);
8093 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
8094 my_assert_not(g_eqs, NULL);
8096 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
8097 g_label_refs[i].i = -1;
8098 g_label_refs[i].next = NULL;
8102 scan_variables(fasm, rlist, rlist_len);
8104 while (my_fgets(line, sizeof(line), fasm))
8113 // get rid of random tabs
8114 for (i = 0; line[i] != 0; i++)
8115 if (line[i] == '\t')
8120 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
8121 goto do_pending_endp; // eww..
8123 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
8125 static const char *attrs[] = {
8134 // parse IDA's attribute-list comment
8135 g_ida_func_attr = 0;
8138 for (; *p != 0; p = sskip(p)) {
8139 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8140 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8141 g_ida_func_attr |= 1 << i;
8142 p += strlen(attrs[i]);
8146 if (i == ARRAY_SIZE(attrs)) {
8147 anote("unparsed IDA attr: %s\n", p);
8150 if (IS(attrs[i], "fpd=")) {
8151 p = next_word(words[0], sizeof(words[0]), p);
8156 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
8158 static const char *attrs[] = {
8163 // parse manual attribute-list comment
8164 g_sct_func_attr = 0;
8167 for (; *p != 0; p = sskip(p)) {
8168 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8169 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8170 g_sct_func_attr |= 1 << i;
8171 p += strlen(attrs[i]);
8178 // clear_sf=start,len (in dwords)
8179 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
8180 &g_stack_clear_len, &j);
8182 // clear_regmask=<mask>
8183 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
8185 anote("unparsed attr value: %s\n", p);
8190 else if (i == ARRAY_SIZE(attrs)) {
8191 anote("unparsed sct attr: %s\n", p);
8196 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8199 next_word(words[0], sizeof(words[0]), p);
8200 if (words[0][0] == 0)
8201 aerr("missing name for func chunk?\n");
8203 if (!scanned_ahead) {
8204 add_func_chunk(fasm, words[0], asmln);
8205 func_chunks_sorted = 0;
8208 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
8210 if (func_chunk_i >= 0) {
8211 if (func_chunk_i < func_chunk_cnt
8212 && IS(func_chunks[func_chunk_i].name, g_func))
8214 // move on to next chunk
8215 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
8217 aerr("seek failed for '%s' chunk #%d\n",
8218 g_func, func_chunk_i);
8219 asmln = func_chunks[func_chunk_i].asmln;
8223 if (func_chunk_ret == 0)
8224 aerr("no return from chunk?\n");
8225 fseek(fasm, func_chunk_ret, SEEK_SET);
8226 asmln = func_chunk_ret_ln;
8232 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
8233 func_chunks_used = 1;
8235 if (IS_START(g_func, "sub_")) {
8236 unsigned long addr = strtoul(p, NULL, 16);
8237 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
8238 if (addr > f_addr && !scanned_ahead) {
8239 //anote("scan_ahead caused by '%s', addr %lx\n",
8243 func_chunks_sorted = 0;
8251 for (i = wordc; i < ARRAY_SIZE(words); i++)
8253 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8254 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8255 if (*p == 0 || *p == ';') {
8260 if (*p != 0 && *p != ';')
8261 aerr("too many words\n");
8263 // alow asm patches in comments
8265 if (IS_START(p, "; sctpatch:")) {
8267 if (*p == 0 || *p == ';')
8269 goto parse_words; // lame
8271 if (IS_START(p, "; sctproto:")) {
8272 sctproto = strdup(p + 11);
8274 else if (IS_START(p, "; sctend")) {
8283 awarn("wordc == 0?\n");
8287 // don't care about this:
8288 if (words[0][0] == '.'
8289 || IS(words[0], "include")
8290 || IS(words[0], "assume") || IS(words[1], "segment")
8291 || IS(words[0], "align"))
8297 // do delayed endp processing to collect switch jumptables
8299 if (in_func && !g_skip_func && !end && wordc >= 2
8300 && ((words[0][0] == 'd' && words[0][2] == 0)
8301 || (words[1][0] == 'd' && words[1][2] == 0)))
8304 if (words[1][0] == 'd' && words[1][2] == 0) {
8306 if (g_func_pd_cnt >= pd_alloc) {
8307 pd_alloc = pd_alloc * 2 + 16;
8308 g_func_pd = realloc(g_func_pd,
8309 sizeof(g_func_pd[0]) * pd_alloc);
8310 my_assert_not(g_func_pd, NULL);
8312 pd = &g_func_pd[g_func_pd_cnt];
8314 memset(pd, 0, sizeof(*pd));
8315 strcpy(pd->label, words[0]);
8316 pd->type = OPT_CONST;
8317 pd->lmod = lmod_from_directive(words[1]);
8323 anote("skipping alignment byte?\n");
8326 lmod = lmod_from_directive(words[0]);
8327 if (lmod != pd->lmod)
8328 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
8331 if (pd->count_alloc < pd->count + wordc) {
8332 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
8333 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
8334 my_assert_not(pd->d, NULL);
8336 for (; i < wordc; i++) {
8337 if (IS(words[i], "offset")) {
8338 pd->type = OPT_OFFSET;
8341 p = strchr(words[i], ',');
8344 if (pd->type == OPT_OFFSET)
8345 pd->d[pd->count].u.label = strdup(words[i]);
8347 pd->d[pd->count].u.val = parse_number(words[i]);
8348 pd->d[pd->count].bt_i = -1;
8354 if (in_func && !g_skip_func) {
8356 gen_hdr(g_func, pi);
8358 gen_func(fout, g_fhdr, g_func, pi);
8363 g_ida_func_attr = 0;
8364 g_sct_func_attr = 0;
8365 g_stack_clear_start = 0;
8366 g_stack_clear_len = 0;
8371 func_chunks_used = 0;
8374 memset(&ops, 0, pi * sizeof(ops[0]));
8379 for (i = 0; i < g_func_pd_cnt; i++) {
8381 if (pd->type == OPT_OFFSET) {
8382 for (j = 0; j < pd->count; j++)
8383 free(pd->d[j].u.label);
8398 if (IS(words[1], "proc")) {
8400 aerr("proc '%s' while in_func '%s'?\n",
8403 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8405 strcpy(g_func, words[0]);
8406 set_label(0, words[0]);
8411 if (IS(words[1], "endp"))
8414 aerr("endp '%s' while not in_func?\n", words[0]);
8415 if (!IS(g_func, words[0]))
8416 aerr("endp '%s' while in_func '%s'?\n",
8419 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
8420 && ops[0].op == OP_JMP && ops[0].operand[0].had_ds)
8426 if (!g_skip_func && func_chunks_used) {
8427 // start processing chunks
8428 struct chunk_item *ci, key = { g_func, 0 };
8430 func_chunk_ret = ftell(fasm);
8431 func_chunk_ret_ln = asmln;
8432 if (!func_chunks_sorted) {
8433 qsort(func_chunks, func_chunk_cnt,
8434 sizeof(func_chunks[0]), cmp_chunks);
8435 func_chunks_sorted = 1;
8437 ci = bsearch(&key, func_chunks, func_chunk_cnt,
8438 sizeof(func_chunks[0]), cmp_chunks);
8440 aerr("'%s' needs chunks, but none found\n", g_func);
8441 func_chunk_i = ci - func_chunks;
8442 for (; func_chunk_i > 0; func_chunk_i--)
8443 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
8446 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
8448 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
8449 asmln = func_chunks[func_chunk_i].asmln;
8457 if (wordc == 2 && IS(words[1], "ends")) {
8461 goto do_pending_endp;
8465 // scan for next text segment
8466 while (my_fgets(line, sizeof(line), fasm)) {
8469 if (*p == 0 || *p == ';')
8472 if (strstr(p, "segment para public 'CODE' use32"))
8479 p = strchr(words[0], ':');
8481 set_label(pi, words[0]);
8485 if (!in_func || g_skip_func) {
8486 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
8488 anote("skipping from '%s'\n", g_labels[pi]);
8492 g_labels[pi] = NULL;
8496 if (wordc > 1 && IS(words[1], "="))
8499 aerr("unhandled equ, wc=%d\n", wordc);
8500 if (g_eqcnt >= eq_alloc) {
8502 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
8503 my_assert_not(g_eqs, NULL);
8506 len = strlen(words[0]);
8507 if (len > sizeof(g_eqs[0].name) - 1)
8508 aerr("equ name too long: %d\n", len);
8509 strcpy(g_eqs[g_eqcnt].name, words[0]);
8511 if (!IS(words[3], "ptr"))
8512 aerr("unhandled equ\n");
8513 if (IS(words[2], "dword"))
8514 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
8515 else if (IS(words[2], "word"))
8516 g_eqs[g_eqcnt].lmod = OPLM_WORD;
8517 else if (IS(words[2], "byte"))
8518 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
8519 else if (IS(words[2], "qword"))
8520 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
8522 aerr("bad lmod: '%s'\n", words[2]);
8524 g_eqs[g_eqcnt].offset = parse_number(words[4]);
8529 if (pi >= ARRAY_SIZE(ops))
8530 aerr("too many ops\n");
8532 parse_op(&ops[pi], words, wordc);
8534 ops[pi].datap = sctproto;
8549 // vim:ts=2:shiftwidth=2:expandtab