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 */
141 // pseudo-ops for lib calls
156 // must be sorted (larger len must be further in enum)
165 #define MAX_EXITS 128
167 #define MAX_OPERANDS 3
170 #define OPR_INIT(type_, lmod_, reg_) \
171 { type_, lmod_, reg_, }
175 enum opr_lenmod lmod;
177 unsigned int is_ptr:1; // pointer in C
178 unsigned int is_array:1; // array in C
179 unsigned int type_from_var:1; // .. in header, sometimes wrong
180 unsigned int size_mismatch:1; // type override differs from C
181 unsigned int size_lt:1; // type override is larger than C
182 unsigned int had_ds:1; // had ds: prefix
183 const struct parsed_proto *pp; // for OPT_LABEL
190 struct parsed_opr operand[MAX_OPERANDS];
193 unsigned char pfo_inv;
194 unsigned char operand_cnt;
195 unsigned char p_argnum; // arg push: altered before call arg #
196 unsigned char p_arggrp; // arg push: arg group # for above
197 unsigned char p_argpass;// arg push: arg of host func
198 short p_argnext;// arg push: same arg pushed elsewhere or -1
199 int regmask_src; // all referensed regs
201 int pfomask; // flagop: parsed_flag_op that can't be delayed
202 int cc_scratch; // scratch storage during analysis
203 int bt_i; // branch target for branches
204 struct parsed_data *btj;// branch targets for jumptables
205 struct parsed_proto *pp;// parsed_proto for OP_CALL
211 // on start: function/data type hint (sctproto)
213 // (OPF_CC) - points to one of (OPF_FLAGS) that affects cc op
214 // OP_PUSH - points to OP_POP in complex push/pop graph
215 // OP_POP - points to OP_PUSH in simple push/pop pair
219 enum opr_lenmod lmod;
226 enum opr_lenmod lmod;
240 struct label_ref *next;
244 IDAFA_BP_FRAME = (1 << 0),
245 IDAFA_LIB_FUNC = (1 << 1),
246 IDAFA_STATIC = (1 << 2),
247 IDAFA_NORETURN = (1 << 3),
248 IDAFA_THUNK = (1 << 4),
249 IDAFA_FPD = (1 << 5),
253 SCTFA_CLEAR_SF = (1 << 0), // clear stack frame
254 SCTFA_CLEAR_REGS = (1 << 1), // clear registers (mask)
267 // note: limited to 32k due to p_argnext
269 #define MAX_ARG_GRP 2
271 static struct parsed_op ops[MAX_OPS];
272 static struct parsed_equ *g_eqs;
274 static char *g_labels[MAX_OPS];
275 static struct label_ref g_label_refs[MAX_OPS];
276 static const struct parsed_proto *g_func_pp;
277 static struct parsed_data *g_func_pd;
278 static int g_func_pd_cnt;
279 static int g_func_lmods;
280 static char g_func[256];
281 static char g_comment[256];
282 static int g_bp_frame;
283 static int g_sp_frame;
284 static int g_stack_frame_used;
285 static int g_stack_fsz;
286 static int g_ida_func_attr;
287 static int g_sct_func_attr;
288 static int g_stack_clear_start; // in dwords
289 static int g_stack_clear_len;
290 static int g_regmask_init;
291 static int g_skip_func;
292 static int g_allow_regfunc;
293 static int g_quiet_pp;
294 static int g_header_mode;
296 #define ferr(op_, fmt, ...) do { \
297 printf("%s:%d: error %u: [%s] '%s': " fmt, asmfn, (op_)->asmln, \
298 __LINE__, g_func, dump_op(op_), ##__VA_ARGS__); \
302 #define fnote(op_, fmt, ...) \
303 printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
304 dump_op(op_), ##__VA_ARGS__)
306 #define ferr_assert(op_, cond) do { \
307 if (!(cond)) ferr(op_, "assertion '%s' failed\n", #cond); \
310 const char *regs_r32[] = {
311 "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
312 // not r32, but list here for easy parsing and printing
313 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
314 "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"
316 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
317 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
318 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
324 xMM0, xMM1, xMM2, xMM3, // mmx
325 xMM4, xMM5, xMM6, xMM7,
326 xST0, xST1, xST2, xST3, // x87
327 xST4, xST5, xST6, xST7,
330 #define mxAX (1 << xAX)
331 #define mxCX (1 << xCX)
332 #define mxDX (1 << xDX)
333 #define mxST0 (1 << xST0)
334 #define mxST1 (1 << xST1)
336 // possible basic comparison types (without inversion)
337 enum parsed_flag_op {
341 PFO_BE, // 6 CF=1||ZF=1
345 PFO_LE, // e ZF=1||SF!=OF
348 #define PFOB_O (1 << PFO_O)
349 #define PFOB_C (1 << PFO_C)
350 #define PFOB_Z (1 << PFO_Z)
351 #define PFOB_S (1 << PFO_S)
353 static const char *parsed_flag_op_names[] = {
354 "o", "c", "z", "be", "s", "p", "l", "le"
357 static int char_array_i(const char *array[], size_t len, const char *s)
361 for (i = 0; i < len; i++)
368 static void printf_number(char *buf, size_t buf_size,
369 unsigned long number)
371 // output in C-friendly form
372 snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
375 static int check_segment_prefix(const char *s)
377 if (s[0] == 0 || s[1] != 's' || s[2] != ':')
391 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
395 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
397 *reg_lmod = OPLM_QWORD;
401 *reg_lmod = OPLM_DWORD;
404 reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
406 *reg_lmod = OPLM_WORD;
409 reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
411 *reg_lmod = OPLM_BYTE;
414 reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
416 *reg_lmod = OPLM_BYTE;
423 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
425 enum opr_lenmod lmod;
438 while (my_isblank(*s))
440 for (; my_issep(*s); d++, s++)
442 while (my_isblank(*s))
446 // skip '?s:' prefixes
447 if (check_segment_prefix(s))
450 s = next_idt(w, sizeof(w), s);
455 reg = parse_reg(&lmod, w);
457 *regmask |= 1 << reg;
461 if ('0' <= w[0] && w[0] <= '9') {
462 number = parse_number(w);
463 printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
467 // probably some label/identifier - pass
470 snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
474 strcpy(name, cvtbuf);
479 static int is_reg_in_str(const char *s)
483 if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
486 for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
487 if (!strncmp(s, regs_r32[i], 3))
493 static const char *parse_stack_el(const char *name, char *extra_reg,
496 const char *p, *p2, *s;
502 if (g_bp_frame || early_try)
505 if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
507 if (extra_reg != NULL) {
508 strncpy(extra_reg, name, 3);
513 if (IS_START(p, "ebp+")) {
517 if (p2 != NULL && is_reg_in_str(p)) {
518 if (extra_reg != NULL) {
519 strncpy(extra_reg, p, p2 - p);
520 extra_reg[p2 - p] = 0;
525 if (!('0' <= *p && *p <= '9'))
532 if (!IS_START(name, "esp+"))
538 if (is_reg_in_str(s)) {
539 if (extra_reg != NULL) {
540 strncpy(extra_reg, s, p - s);
541 extra_reg[p - s] = 0;
546 aerr("%s IDA stackvar not set?\n", __func__);
548 if (!('0' <= *s && *s <= '9')) {
549 aerr("%s IDA stackvar offset not set?\n", __func__);
552 if (s[0] == '0' && s[1] == 'x')
555 if (len < sizeof(buf) - 1) {
556 strncpy(buf, s, len);
558 val = strtol(buf, &endp, 16);
559 if (val == 0 || *endp != 0) {
560 aerr("%s num parse fail for '%s'\n", __func__, buf);
569 if ('0' <= *p && *p <= '9')
575 static int guess_lmod_from_name(struct parsed_opr *opr)
577 if (IS_START(opr->name, "dword_") || IS_START(opr->name, "off_")) {
578 opr->lmod = OPLM_DWORD;
581 if (IS_START(opr->name, "word_")) {
582 opr->lmod = OPLM_WORD;
585 if (IS_START(opr->name, "byte_")) {
586 opr->lmod = OPLM_BYTE;
589 if (IS_START(opr->name, "qword_")) {
590 opr->lmod = OPLM_QWORD;
596 static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
597 const struct parsed_type *c_type)
599 static const char *dword_types[] = {
600 "uint32_t", "int", "_DWORD", "UINT_PTR", "DWORD",
601 "WPARAM", "LPARAM", "UINT", "__int32",
602 "LONG", "HIMC", "BOOL", "size_t",
605 static const char *word_types[] = {
606 "uint16_t", "int16_t", "_WORD", "WORD",
607 "unsigned __int16", "__int16",
609 static const char *byte_types[] = {
610 "uint8_t", "int8_t", "char",
611 "unsigned __int8", "__int8", "BYTE", "_BYTE",
613 // structures.. deal the same as with _UNKNOWN for now
619 if (c_type->is_ptr) {
624 n = skip_type_mod(c_type->name);
626 for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
627 if (IS(n, dword_types[i])) {
633 for (i = 0; i < ARRAY_SIZE(word_types); i++) {
634 if (IS(n, word_types[i])) {
640 for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
641 if (IS(n, byte_types[i])) {
650 static char *default_cast_to(char *buf, size_t buf_size,
651 struct parsed_opr *opr)
655 if (!opr->is_ptr || strchr(opr->name, '['))
657 if (opr->pp == NULL || opr->pp->type.name == NULL
660 snprintf(buf, buf_size, "%s", "(void *)");
664 snprintf(buf, buf_size, "(%s)", opr->pp->type.name);
668 static enum opr_type lmod_from_directive(const char *d)
672 else if (IS(d, "dw"))
674 else if (IS(d, "db"))
677 aerr("unhandled directive: '%s'\n", d);
681 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
687 *regmask |= 1 << reg;
690 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
693 static int parse_operand(struct parsed_opr *opr,
694 int *regmask, int *regmask_indirect,
695 char words[16][256], int wordc, int w, unsigned int op_flags)
697 const struct parsed_proto *pp = NULL;
698 enum opr_lenmod tmplmod;
699 unsigned long number;
707 aerr("parse_operand w %d, wordc %d\n", w, wordc);
711 for (i = w; i < wordc; i++) {
712 len = strlen(words[i]);
713 if (words[i][len - 1] == ',') {
714 words[i][len - 1] = 0;
720 wordc_in = wordc - w;
722 if ((op_flags & OPF_JMP) && wordc_in > 0
723 && !('0' <= words[w][0] && words[w][0] <= '9'))
725 const char *label = NULL;
727 if (wordc_in == 3 && !strncmp(words[w], "near", 4)
728 && IS(words[w + 1], "ptr"))
729 label = words[w + 2];
730 else if (wordc_in == 2 && IS(words[w], "short"))
731 label = words[w + 1];
732 else if (wordc_in == 1
733 && strchr(words[w], '[') == NULL
734 && parse_reg(&tmplmod, words[w]) < 0)
738 opr->type = OPT_LABEL;
739 ret = check_segment_prefix(label);
742 aerr("fs/gs used\n");
746 strcpy(opr->name, label);
752 if (IS(words[w + 1], "ptr")) {
753 if (IS(words[w], "dword"))
754 opr->lmod = OPLM_DWORD;
755 else if (IS(words[w], "word"))
756 opr->lmod = OPLM_WORD;
757 else if (IS(words[w], "byte"))
758 opr->lmod = OPLM_BYTE;
759 else if (IS(words[w], "qword"))
760 opr->lmod = OPLM_QWORD;
762 aerr("type parsing failed\n");
764 wordc_in = wordc - w;
769 if (IS(words[w], "offset")) {
770 opr->type = OPT_OFFSET;
771 opr->lmod = OPLM_DWORD;
772 strcpy(opr->name, words[w + 1]);
773 pp = proto_parse(g_fhdr, opr->name, 1);
776 if (IS(words[w], "(offset")) {
777 p = strchr(words[w + 1], ')');
779 aerr("parse of bracketed offset failed\n");
781 opr->type = OPT_OFFSET;
782 strcpy(opr->name, words[w + 1]);
788 aerr("parse_operand 1 word expected\n");
790 ret = check_segment_prefix(words[w]);
793 aerr("fs/gs used\n");
795 memmove(words[w], words[w] + 3, strlen(words[w]) - 2);
797 strcpy(opr->name, words[w]);
799 if (words[w][0] == '[') {
800 opr->type = OPT_REGMEM;
801 ret = sscanf(words[w], "[%[^]]]", opr->name);
803 aerr("[] parse failure\n");
805 parse_indmode(opr->name, regmask_indirect, 1);
806 if (opr->lmod == OPLM_UNSPEC && parse_stack_el(opr->name, NULL, 1))
809 struct parsed_equ *eq =
810 equ_find(NULL, parse_stack_el(opr->name, NULL, 1), &i);
812 opr->lmod = eq->lmod;
814 // might be unaligned access
815 g_func_lmods |= 1 << OPLM_BYTE;
819 else if (strchr(words[w], '[')) {
821 p = strchr(words[w], '[');
822 opr->type = OPT_REGMEM;
823 parse_indmode(p, regmask_indirect, 0);
824 strncpy(buf, words[w], p - words[w]);
825 buf[p - words[w]] = 0;
826 pp = proto_parse(g_fhdr, buf, 1);
829 else if (('0' <= words[w][0] && words[w][0] <= '9')
830 || words[w][0] == '-')
832 number = parse_number(words[w]);
833 opr->type = OPT_CONST;
835 printf_number(opr->name, sizeof(opr->name), number);
839 ret = parse_reg(&tmplmod, opr->name);
841 setup_reg_opr(opr, ret, tmplmod, regmask);
845 // most likely var in data segment
846 opr->type = OPT_LABEL;
847 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
851 if (pp->is_fptr || pp->is_func) {
852 opr->lmod = OPLM_DWORD;
856 tmplmod = OPLM_UNSPEC;
857 if (!guess_lmod_from_c_type(&tmplmod, &pp->type))
858 anote("unhandled C type '%s' for '%s'\n",
859 pp->type.name, opr->name);
861 if (opr->lmod == OPLM_UNSPEC) {
863 opr->type_from_var = 1;
865 else if (opr->lmod != tmplmod) {
866 opr->size_mismatch = 1;
867 if (tmplmod < opr->lmod)
870 opr->is_ptr = pp->type.is_ptr;
872 opr->is_array = pp->type.is_array;
876 if (opr->lmod == OPLM_UNSPEC)
877 guess_lmod_from_name(opr);
881 static const struct {
886 { "repe", OPF_REP|OPF_REPZ },
887 { "repz", OPF_REP|OPF_REPZ },
888 { "repne", OPF_REP|OPF_REPNZ },
889 { "repnz", OPF_REP|OPF_REPNZ },
890 { "lock", OPF_LOCK }, // ignored for now..
893 #define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
895 static const struct {
898 unsigned short minopr;
899 unsigned short maxopr;
902 unsigned char pfo_inv;
904 { "nop", OP_NOP, 0, 0, 0 },
905 { "push", OP_PUSH, 1, 1, 0 },
906 { "pop", OP_POP, 1, 1, OPF_DATA },
907 { "leave",OP_LEAVE, 0, 0, OPF_DATA },
908 { "mov" , OP_MOV, 2, 2, OPF_DATA },
909 { "lea", OP_LEA, 2, 2, OPF_DATA },
910 { "movzx",OP_MOVZX, 2, 2, OPF_DATA },
911 { "movsx",OP_MOVSX, 2, 2, OPF_DATA },
912 { "xchg", OP_XCHG, 2, 2, OPF_DATA },
913 { "not", OP_NOT, 1, 1, OPF_DATA },
914 { "xlat", OP_XLAT, 0, 0, OPF_DATA },
915 { "cdq", OP_CDQ, 0, 0, OPF_DATA },
916 { "lodsb",OP_LODS, 0, 0, OPF_DATA },
917 { "lodsw",OP_LODS, 0, 0, OPF_DATA },
918 { "lodsd",OP_LODS, 0, 0, OPF_DATA },
919 { "stosb",OP_STOS, 0, 0, OPF_DATA },
920 { "stosw",OP_STOS, 0, 0, OPF_DATA },
921 { "stosd",OP_STOS, 0, 0, OPF_DATA },
922 { "movsb",OP_MOVS, 0, 0, OPF_DATA },
923 { "movsw",OP_MOVS, 0, 0, OPF_DATA },
924 { "movsd",OP_MOVS, 0, 0, OPF_DATA },
925 { "cmpsb",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
926 { "cmpsw",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
927 { "cmpsd",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
928 { "scasb",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
929 { "scasw",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
930 { "scasd",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
931 { "std", OP_STD, 0, 0, OPF_DATA }, // special flag
932 { "cld", OP_CLD, 0, 0, OPF_DATA },
933 { "add", OP_ADD, 2, 2, OPF_DATA|OPF_FLAGS },
934 { "sub", OP_SUB, 2, 2, OPF_DATA|OPF_FLAGS },
935 { "and", OP_AND, 2, 2, OPF_DATA|OPF_FLAGS },
936 { "or", OP_OR, 2, 2, OPF_DATA|OPF_FLAGS },
937 { "xor", OP_XOR, 2, 2, OPF_DATA|OPF_FLAGS },
938 { "shl", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
939 { "shr", OP_SHR, 2, 2, OPF_DATA|OPF_FLAGS },
940 { "sal", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
941 { "sar", OP_SAR, 2, 2, OPF_DATA|OPF_FLAGS },
942 { "shld", OP_SHLD, 3, 3, OPF_DATA|OPF_FLAGS },
943 { "shrd", OP_SHRD, 3, 3, OPF_DATA|OPF_FLAGS },
944 { "rol", OP_ROL, 2, 2, OPF_DATA|OPF_FLAGS },
945 { "ror", OP_ROR, 2, 2, OPF_DATA|OPF_FLAGS },
946 { "rcl", OP_RCL, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
947 { "rcr", OP_RCR, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
948 { "adc", OP_ADC, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
949 { "sbb", OP_SBB, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
950 { "bsf", OP_BSF, 2, 2, OPF_DATA|OPF_FLAGS },
951 { "inc", OP_INC, 1, 1, OPF_DATA|OPF_FLAGS },
952 { "dec", OP_DEC, 1, 1, OPF_DATA|OPF_FLAGS },
953 { "neg", OP_NEG, 1, 1, OPF_DATA|OPF_FLAGS },
954 { "mul", OP_MUL, 1, 1, OPF_DATA|OPF_FLAGS },
955 { "imul", OP_IMUL, 1, 3, OPF_DATA|OPF_FLAGS },
956 { "div", OP_DIV, 1, 1, OPF_DATA|OPF_FLAGS },
957 { "idiv", OP_IDIV, 1, 1, OPF_DATA|OPF_FLAGS },
958 { "test", OP_TEST, 2, 2, OPF_FLAGS },
959 { "cmp", OP_CMP, 2, 2, OPF_FLAGS },
960 { "retn", OP_RET, 0, 1, OPF_TAIL },
961 { "call", OP_CALL, 1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
962 { "jmp", OP_JMP, 1, 1, OPF_JMP },
963 { "jecxz",OP_JECXZ, 1, 1, OPF_JMP|OPF_CJMP },
964 { "loop", OP_LOOP, 1, 1, OPF_JMP|OPF_CJMP|OPF_DATA },
965 { "jo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 0 }, // 70 OF=1
966 { "jno", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 1 }, // 71 OF=0
967 { "jc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72 CF=1
968 { "jb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72
969 { "jnc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73 CF=0
970 { "jnb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
971 { "jae", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
972 { "jz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74 ZF=1
973 { "je", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74
974 { "jnz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75 ZF=0
975 { "jne", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75
976 { "jbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76 CF=1||ZF=1
977 { "jna", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76
978 { "ja", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77 CF=0&&ZF=0
979 { "jnbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77
980 { "js", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 0 }, // 78 SF=1
981 { "jns", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 1 }, // 79 SF=0
982 { "jp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a PF=1
983 { "jpe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a
984 { "jnp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b PF=0
985 { "jpo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b
986 { "jl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c SF!=OF
987 { "jnge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c
988 { "jge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d SF=OF
989 { "jnl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d
990 { "jle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e ZF=1||SF!=OF
991 { "jng", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e
992 { "jg", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f ZF=0&&SF=OF
993 { "jnle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f
994 { "seto", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 0 },
995 { "setno", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 1 },
996 { "setc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
997 { "setb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
998 { "setnc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
999 { "setae", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1000 { "setnb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1001 { "setz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1002 { "sete", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1003 { "setnz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1004 { "setne", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1005 { "setbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1006 { "setna", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1007 { "seta", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1008 { "setnbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1009 { "sets", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 0 },
1010 { "setns", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 1 },
1011 { "setp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1012 { "setpe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1013 { "setnp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1014 { "setpo", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1015 { "setl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1016 { "setnge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1017 { "setge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1018 { "setnl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1019 { "setle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1020 { "setng", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1021 { "setg", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1022 { "setnle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1024 { "fld", OP_FLD, 1, 1, OPF_FPUSH },
1025 { "fild", OP_FILD, 1, 1, OPF_FPUSH },
1026 { "fld1", OP_FLDc, 0, 0, OPF_FPUSH },
1027 { "fldz", OP_FLDc, 0, 0, OPF_FPUSH },
1028 { "fstp", OP_FST, 1, 1, OPF_FPOP },
1029 { "fst", OP_FST, 1, 1, 0 },
1030 { "fadd", OP_FADD, 0, 2, 0 },
1031 { "faddp", OP_FADD, 0, 2, OPF_FPOP },
1032 { "fdiv", OP_FDIV, 0, 2, 0 },
1033 { "fdivp", OP_FDIV, 0, 2, OPF_FPOP },
1034 { "fmul", OP_FMUL, 0, 2, 0 },
1035 { "fmulp", OP_FMUL, 0, 2, OPF_FPOP },
1036 { "fsub", OP_FSUB, 0, 2, 0 },
1037 { "fsubp", OP_FSUB, 0, 2, OPF_FPOP },
1038 { "fdivr", OP_FDIVR, 0, 2, 0 },
1039 { "fdivrp", OP_FDIVR, 0, 2, OPF_FPOP },
1040 { "fsubr", OP_FSUBR, 0, 2, 0 },
1041 { "fsubrp", OP_FSUBR, 0, 2, OPF_FPOP },
1042 { "fiadd", OP_FIADD, 1, 1, 0 },
1043 { "fidiv", OP_FIDIV, 1, 1, 0 },
1044 { "fimul", OP_FIMUL, 1, 1, 0 },
1045 { "fisub", OP_FISUB, 1, 1, 0 },
1046 { "fidivr", OP_FIDIVR, 1, 1, 0 },
1047 { "fisubr", OP_FISUBR, 1, 1, 0 },
1049 { "emms", OP_EMMS, 0, 0, OPF_DATA },
1050 { "movq", OP_MOV, 2, 2, OPF_DATA },
1051 // pseudo-ops for lib calls
1052 { "_ftol", OPP_FTOL },
1057 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
1059 enum opr_lenmod lmod = OPLM_UNSPEC;
1060 int prefix_flags = 0;
1068 for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
1069 if (IS(words[w], pref_table[i].name)) {
1070 prefix_flags = pref_table[i].flags;
1077 aerr("lone prefix: '%s'\n", words[0]);
1082 for (i = 0; i < ARRAY_SIZE(op_table); i++) {
1083 if (IS(words[w], op_table[i].name))
1087 if (i == ARRAY_SIZE(op_table)) {
1089 aerr("unhandled op: '%s'\n", words[0]);
1094 op->op = op_table[i].op;
1095 op->flags = op_table[i].flags | prefix_flags;
1096 op->pfo = op_table[i].pfo;
1097 op->pfo_inv = op_table[i].pfo_inv;
1098 op->regmask_src = op->regmask_dst = 0;
1101 if (op->op == OP_UD2)
1104 for (opr = 0; opr < op_table[i].maxopr; opr++) {
1105 if (opr >= op_table[i].minopr && w >= wordc)
1108 regmask = regmask_ind = 0;
1109 w = parse_operand(&op->operand[opr], ®mask, ®mask_ind,
1110 words, wordc, w, op->flags);
1112 if (opr == 0 && (op->flags & OPF_DATA))
1113 op->regmask_dst = regmask;
1115 op->regmask_src |= regmask;
1116 op->regmask_src |= regmask_ind;
1118 if (op->operand[opr].lmod != OPLM_UNSPEC)
1119 g_func_lmods |= 1 << op->operand[opr].lmod;
1123 aerr("parse_op %s incomplete: %d/%d\n",
1124 words[0], w, wordc);
1127 op->operand_cnt = opr;
1128 if (!strncmp(op_table[i].name, "set", 3))
1129 op->operand[0].lmod = OPLM_BYTE;
1132 // first operand is not dst
1135 op->regmask_src |= op->regmask_dst;
1136 op->regmask_dst = 0;
1139 // first operand is src too
1151 op->regmask_src |= op->regmask_dst;
1156 op->regmask_src |= op->regmask_dst;
1157 op->regmask_dst |= op->regmask_src;
1163 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1164 && op->operand[0].lmod == op->operand[1].lmod
1165 && op->operand[0].reg == op->operand[1].reg
1166 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1168 op->regmask_src = 0;
1171 op->regmask_src |= op->regmask_dst;
1174 // ops with implicit argumets
1176 op->operand_cnt = 2;
1177 setup_reg_opr(&op->operand[0], xAX, OPLM_BYTE, &op->regmask_src);
1178 op->regmask_dst = op->regmask_src;
1179 setup_reg_opr(&op->operand[1], xBX, OPLM_DWORD, &op->regmask_src);
1183 op->operand_cnt = 2;
1184 setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
1185 setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
1191 if (words[op_w][4] == 'b')
1193 else if (words[op_w][4] == 'w')
1195 else if (words[op_w][4] == 'd')
1198 op->regmask_src = 0;
1199 setup_reg_opr(&op->operand[j++], op->op == OP_LODS ? xSI : xDI,
1200 OPLM_DWORD, &op->regmask_src);
1201 op->regmask_dst = op->regmask_src;
1202 setup_reg_opr(&op->operand[j++], xAX, lmod,
1203 op->op == OP_LODS ? &op->regmask_dst : &op->regmask_src);
1204 if (op->flags & OPF_REP) {
1205 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1206 op->regmask_dst |= 1 << xCX;
1208 op->operand_cnt = j;
1213 if (words[op_w][4] == 'b')
1215 else if (words[op_w][4] == 'w')
1217 else if (words[op_w][4] == 'd')
1220 op->regmask_src = 0;
1221 // note: lmod is not correct, don't have where to place it
1222 setup_reg_opr(&op->operand[j++], xDI, lmod, &op->regmask_src);
1223 setup_reg_opr(&op->operand[j++], xSI, OPLM_DWORD, &op->regmask_src);
1224 if (op->flags & OPF_REP)
1225 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1226 op->operand_cnt = j;
1227 op->regmask_dst = op->regmask_src;
1231 op->regmask_dst = 1 << xCX;
1234 op->operand_cnt = 2;
1235 op->regmask_src = 1 << xCX;
1236 op->operand[1].type = OPT_REG;
1237 op->operand[1].reg = xCX;
1238 op->operand[1].lmod = OPLM_DWORD;
1242 if (op->operand_cnt == 2) {
1243 if (op->operand[0].type != OPT_REG)
1244 aerr("reg expected\n");
1245 op->regmask_src |= 1 << op->operand[0].reg;
1247 if (op->operand_cnt != 1)
1252 op->regmask_src |= op->regmask_dst;
1253 op->regmask_dst = (1 << xDX) | (1 << xAX);
1254 if (op->operand[0].lmod == OPLM_UNSPEC)
1255 op->operand[0].lmod = OPLM_DWORD;
1260 // we could set up operands for edx:eax, but there is no real need to
1261 // (see is_opr_modified())
1262 op->regmask_src |= op->regmask_dst;
1263 op->regmask_dst = (1 << xDX) | (1 << xAX);
1264 if (op->operand[0].lmod == OPLM_UNSPEC)
1265 op->operand[0].lmod = OPLM_DWORD;
1273 op->regmask_src |= op->regmask_dst;
1274 if (op->operand[1].lmod == OPLM_UNSPEC)
1275 op->operand[1].lmod = OPLM_BYTE;
1280 op->regmask_src |= op->regmask_dst;
1281 if (op->operand[2].lmod == OPLM_UNSPEC)
1282 op->operand[2].lmod = OPLM_BYTE;
1286 op->regmask_src |= op->regmask_dst;
1287 op->regmask_dst = 0;
1288 if (op->operand[0].lmod == OPLM_UNSPEC
1289 && (op->operand[0].type == OPT_CONST
1290 || op->operand[0].type == OPT_OFFSET
1291 || op->operand[0].type == OPT_LABEL))
1292 op->operand[0].lmod = OPLM_DWORD;
1298 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1299 && op->operand[0].lmod == op->operand[1].lmod
1300 && op->operand[0].reg == op->operand[1].reg
1301 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1303 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1304 op->regmask_src = op->regmask_dst = 0;
1309 if (op->operand[0].type == OPT_REG
1310 && op->operand[1].type == OPT_REGMEM)
1313 snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1314 if (IS(buf, op->operand[1].name))
1315 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1320 // trashed regs must be explicitly detected later
1321 op->regmask_dst = 0;
1325 op->regmask_dst = (1 << xBP) | (1 << xSP);
1326 op->regmask_src = 1 << xBP;
1331 op->regmask_dst |= mxST0;
1335 op->regmask_dst |= mxST0;
1336 if (IS(words[op_w] + 3, "1"))
1337 op->operand[0].val = X87_CONST_1;
1338 else if (IS(words[op_w] + 3, "z"))
1339 op->operand[0].val = X87_CONST_Z;
1345 op->regmask_src |= mxST0;
1354 op->regmask_src |= mxST0;
1355 if (op->operand_cnt == 2)
1356 op->regmask_src |= op->regmask_dst;
1357 else if (op->operand_cnt == 1) {
1358 memcpy(&op->operand[1], &op->operand[0], sizeof(op->operand[1]));
1359 op->operand[0].type = OPT_REG;
1360 op->operand[0].lmod = OPLM_QWORD;
1361 op->operand[0].reg = xST0;
1362 op->regmask_dst |= mxST0;
1365 // IDA doesn't use this
1366 aerr("no operands?\n");
1375 op->regmask_src |= mxST0;
1376 op->regmask_dst |= mxST0;
1383 if (op->operand[0].type == OPT_REG
1384 && op->operand[1].type == OPT_CONST)
1386 struct parsed_opr *op1 = &op->operand[1];
1387 if ((op->op == OP_AND && op1->val == 0)
1390 || (op->operand[0].lmod == OPLM_WORD && op1->val == 0xffff)
1391 || (op->operand[0].lmod == OPLM_BYTE && op1->val == 0xff))))
1393 op->regmask_src = 0;
1398 static const char *op_name(struct parsed_op *po)
1400 static char buf[16];
1404 if (po->op == OP_JCC || po->op == OP_SCC) {
1406 *p++ = (po->op == OP_JCC) ? 'j' : 's';
1409 strcpy(p, parsed_flag_op_names[po->pfo]);
1413 for (i = 0; i < ARRAY_SIZE(op_table); i++)
1414 if (op_table[i].op == po->op)
1415 return op_table[i].name;
1421 static const char *dump_op(struct parsed_op *po)
1423 static char out[128];
1430 snprintf(out, sizeof(out), "%s", op_name(po));
1431 for (i = 0; i < po->operand_cnt; i++) {
1435 snprintf(p, sizeof(out) - (p - out),
1436 po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1437 po->operand[i].name);
1443 static const char *lmod_type_u(struct parsed_op *po,
1444 enum opr_lenmod lmod)
1456 ferr(po, "invalid lmod: %d\n", lmod);
1457 return "(_invalid_)";
1461 static const char *lmod_cast_u(struct parsed_op *po,
1462 enum opr_lenmod lmod)
1474 ferr(po, "invalid lmod: %d\n", lmod);
1475 return "(_invalid_)";
1479 static const char *lmod_cast_u_ptr(struct parsed_op *po,
1480 enum opr_lenmod lmod)
1492 ferr(po, "invalid lmod: %d\n", lmod);
1493 return "(_invalid_)";
1497 static const char *lmod_cast_s(struct parsed_op *po,
1498 enum opr_lenmod lmod)
1510 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1511 return "(_invalid_)";
1515 static const char *lmod_cast(struct parsed_op *po,
1516 enum opr_lenmod lmod, int is_signed)
1519 lmod_cast_s(po, lmod) :
1520 lmod_cast_u(po, lmod);
1523 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1535 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1540 static const char *opr_name(struct parsed_op *po, int opr_num)
1542 if (opr_num >= po->operand_cnt)
1543 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1544 return po->operand[opr_num].name;
1547 static unsigned int opr_const(struct parsed_op *po, int opr_num)
1549 if (opr_num >= po->operand_cnt)
1550 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1551 if (po->operand[opr_num].type != OPT_CONST)
1552 ferr(po, "opr %d: const expected\n", opr_num);
1553 return po->operand[opr_num].val;
1556 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1558 if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
1559 ferr(po, "invalid reg: %d\n", popr->reg);
1560 return regs_r32[popr->reg];
1563 static int check_simple_cast(const char *cast, int *bits, int *is_signed)
1565 if (IS_START(cast, "(s8)") || IS_START(cast, "(u8)"))
1567 else if (IS_START(cast, "(s16)") || IS_START(cast, "(u16)"))
1569 else if (IS_START(cast, "(s32)") || IS_START(cast, "(u32)"))
1571 else if (IS_START(cast, "(s64)") || IS_START(cast, "(u64)"))
1576 *is_signed = cast[1] == 's' ? 1 : 0;
1580 static int check_deref_cast(const char *cast, int *bits)
1582 if (IS_START(cast, "*(u8 *)"))
1584 else if (IS_START(cast, "*(u16 *)"))
1586 else if (IS_START(cast, "*(u32 *)"))
1588 else if (IS_START(cast, "*(u64 *)"))
1596 // cast1 is the "final" cast
1597 static const char *simplify_cast(const char *cast1, const char *cast2)
1599 static char buf[256];
1607 if (IS(cast1, cast2))
1610 if (check_simple_cast(cast1, &bits1, &s1) == 0
1611 && check_simple_cast(cast2, &bits2, &s2) == 0)
1616 if (check_simple_cast(cast1, &bits1, &s1) == 0
1617 && check_deref_cast(cast2, &bits2) == 0)
1619 if (bits1 == bits2) {
1620 snprintf(buf, sizeof(buf), "*(%c%d *)", s1 ? 's' : 'u', bits1);
1625 if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1628 snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1632 static const char *simplify_cast_num(const char *cast, unsigned int val)
1634 if (IS(cast, "(u8)") && val < 0x100)
1636 if (IS(cast, "(s8)") && val < 0x80)
1638 if (IS(cast, "(u16)") && val < 0x10000)
1640 if (IS(cast, "(s16)") && val < 0x8000)
1642 if (IS(cast, "(s32)") && val < 0x80000000)
1648 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1657 namelen = strlen(name);
1659 p = strchr(name, '+');
1663 ferr(po, "equ parse failed for '%s'\n", name);
1665 if (IS_START(p, "0x"))
1667 *extra_offs = strtol(p, &endp, 16);
1669 ferr(po, "equ parse failed for '%s'\n", name);
1672 for (i = 0; i < g_eqcnt; i++)
1673 if (strncmp(g_eqs[i].name, name, namelen) == 0
1674 && g_eqs[i].name[namelen] == 0)
1678 ferr(po, "unresolved equ name: '%s'\n", name);
1685 static int is_stack_access(struct parsed_op *po,
1686 const struct parsed_opr *popr)
1688 return (parse_stack_el(popr->name, NULL, 0)
1689 || (g_bp_frame && !(po->flags & OPF_EBP_S)
1690 && IS_START(popr->name, "ebp")));
1693 static void parse_stack_access(struct parsed_op *po,
1694 const char *name, char *ofs_reg, int *offset_out,
1695 int *stack_ra_out, const char **bp_arg_out, int is_lea)
1697 const char *bp_arg = "";
1698 const char *p = NULL;
1699 struct parsed_equ *eq;
1706 if (IS_START(name, "ebp-")
1707 || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1710 if (IS_START(p, "0x"))
1712 offset = strtoul(p, &endp, 16);
1716 ferr(po, "ebp- parse of '%s' failed\n", name);
1719 bp_arg = parse_stack_el(name, ofs_reg, 0);
1720 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1721 eq = equ_find(po, bp_arg, &offset);
1723 ferr(po, "detected but missing eq\n");
1724 offset += eq->offset;
1727 if (!strncmp(name, "ebp", 3))
1730 // yes it sometimes LEAs ra for compares..
1731 if (!is_lea && ofs_reg[0] == 0
1732 && stack_ra <= offset && offset < stack_ra + 4)
1734 ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1737 *offset_out = offset;
1738 *stack_ra_out = stack_ra;
1740 *bp_arg_out = bp_arg;
1743 static int stack_frame_access(struct parsed_op *po,
1744 struct parsed_opr *popr, char *buf, size_t buf_size,
1745 const char *name, const char *cast, int is_src, int is_lea)
1747 enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1748 const char *prefix = "";
1749 const char *bp_arg = NULL;
1750 char ofs_reg[16] = { 0, };
1751 int i, arg_i, arg_s;
1759 if (po->flags & OPF_EBP_S)
1760 ferr(po, "stack_frame_access while ebp is scratch\n");
1762 parse_stack_access(po, name, ofs_reg, &offset,
1763 &stack_ra, &bp_arg, is_lea);
1765 if (offset > stack_ra)
1767 arg_i = (offset - stack_ra - 4) / 4;
1768 if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1770 if (g_func_pp->is_vararg
1771 && arg_i == g_func_pp->argc_stack && is_lea)
1773 // should be va_list
1776 snprintf(buf, buf_size, "%sap", cast);
1779 ferr(po, "offset %d (%s,%d) doesn't map to any arg\n",
1780 offset, bp_arg, arg_i);
1782 if (ofs_reg[0] != 0)
1783 ferr(po, "offset reg on arg access?\n");
1785 for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1786 if (g_func_pp->arg[i].reg != NULL)
1792 if (i == g_func_pp->argc)
1793 ferr(po, "arg %d not in prototype?\n", arg_i);
1795 popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
1802 ferr(po, "lea/byte to arg?\n");
1803 if (is_src && (offset & 3) == 0)
1804 snprintf(buf, buf_size, "%sa%d",
1805 simplify_cast(cast, "(u8)"), i + 1);
1807 snprintf(buf, buf_size, "%sBYTE%d(a%d)",
1808 cast, offset & 3, i + 1);
1813 ferr(po, "lea/word to arg?\n");
1818 ferr(po, "problematic arg store\n");
1819 snprintf(buf, buf_size, "%s((char *)&a%d + 1)",
1820 simplify_cast(cast, "*(u16 *)"), i + 1);
1823 ferr(po, "unaligned arg word load\n");
1825 else if (is_src && (offset & 2) == 0)
1826 snprintf(buf, buf_size, "%sa%d",
1827 simplify_cast(cast, "(u16)"), i + 1);
1829 snprintf(buf, buf_size, "%s%sWORD(a%d)",
1830 cast, (offset & 2) ? "HI" : "LO", i + 1);
1842 snprintf(buf, buf_size, "(u32)&a%d + %d",
1845 ferr(po, "unaligned arg store\n");
1847 // mov edx, [ebp+arg_4+2]; movsx ecx, dx
1848 snprintf(buf, buf_size, "%s(a%d >> %d)",
1849 prefix, i + 1, (offset & 3) * 8);
1853 snprintf(buf, buf_size, "%s%sa%d",
1854 prefix, is_lea ? "&" : "", i + 1);
1859 ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
1863 snprintf(g_comment, sizeof(g_comment), "%s unaligned", bp_arg);
1866 guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
1867 if (tmp_lmod != OPLM_DWORD
1868 && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
1869 < lmod_bytes(po, popr->lmod) + (offset & 3))))
1871 ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
1872 i + 1, offset, g_func_pp->arg[i].type.name);
1874 // can't check this because msvc likes to reuse
1875 // arg space for scratch..
1876 //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
1877 // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
1881 if (g_stack_fsz == 0)
1882 ferr(po, "stack var access without stackframe\n");
1883 g_stack_frame_used = 1;
1885 sf_ofs = g_stack_fsz + offset;
1886 lim = (ofs_reg[0] != 0) ? -4 : 0;
1887 if (offset > 0 || sf_ofs < lim)
1888 ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
1898 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1899 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1903 if ((sf_ofs & 1) || ofs_reg[0] != 0) {
1904 // known unaligned or possibly unaligned
1905 strcat(g_comment, " unaligned");
1907 prefix = "*(u16 *)&";
1908 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1909 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1912 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
1916 if ((sf_ofs & 3) || ofs_reg[0] != 0) {
1917 // known unaligned or possibly unaligned
1918 strcat(g_comment, " unaligned");
1920 prefix = "*(u32 *)&";
1921 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1922 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1925 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
1929 ferr_assert(po, !(sf_ofs & 7));
1930 ferr_assert(po, ofs_reg[0] == 0);
1931 // float callers set is_lea
1932 ferr_assert(po, is_lea);
1933 snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
1937 ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
1944 static void check_func_pp(struct parsed_op *po,
1945 const struct parsed_proto *pp, const char *pfx)
1947 enum opr_lenmod tmp_lmod;
1951 if (pp->argc_reg != 0) {
1952 if (/*!g_allow_regfunc &&*/ !pp->is_fastcall) {
1953 pp_print(buf, sizeof(buf), pp);
1954 ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
1956 if (pp->argc_stack > 0 && pp->argc_reg != 2)
1957 ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
1958 pfx, pp->argc_reg, pp->argc_stack);
1961 // fptrs must use 32bit args, callsite might have no information and
1962 // lack a cast to smaller types, which results in incorrectly masked
1963 // args passed (callee may assume masked args, it does on ARM)
1964 if (!pp->is_osinc) {
1965 for (i = 0; i < pp->argc; i++) {
1966 ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
1967 if (ret && tmp_lmod != OPLM_DWORD)
1968 ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
1969 i + 1, pp->arg[i].type.name);
1974 static const char *check_label_read_ref(struct parsed_op *po,
1977 const struct parsed_proto *pp;
1979 pp = proto_parse(g_fhdr, name, 0);
1981 ferr(po, "proto_parse failed for ref '%s'\n", name);
1984 check_func_pp(po, pp, "ref");
1989 static char *out_src_opr(char *buf, size_t buf_size,
1990 struct parsed_op *po, struct parsed_opr *popr, const char *cast,
1993 char tmp1[256], tmp2[256];
2002 switch (popr->type) {
2005 ferr(po, "lea from reg?\n");
2007 switch (popr->lmod) {
2009 snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2012 snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2015 snprintf(buf, buf_size, "%s%s",
2016 simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2019 if (popr->name[1] == 'h') // XXX..
2020 snprintf(buf, buf_size, "%s(%s >> 8)",
2021 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2023 snprintf(buf, buf_size, "%s%s",
2024 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2027 ferr(po, "invalid src lmod: %d\n", popr->lmod);
2032 if (is_stack_access(po, popr)) {
2033 stack_frame_access(po, popr, buf, buf_size,
2034 popr->name, cast, 1, is_lea);
2038 strcpy(expr, popr->name);
2039 if (strchr(expr, '[')) {
2040 // special case: '[' can only be left for label[reg] form
2041 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2043 ferr(po, "parse failure for '%s'\n", expr);
2044 if (tmp1[0] == '(') {
2045 // (off_4FFF50+3)[eax]
2046 p = strchr(tmp1 + 1, ')');
2047 if (p == NULL || p[1] != 0)
2048 ferr(po, "parse failure (2) for '%s'\n", expr);
2050 memmove(tmp1, tmp1 + 1, strlen(tmp1));
2052 snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2055 // XXX: do we need more parsing?
2057 snprintf(buf, buf_size, "%s", expr);
2061 snprintf(buf, buf_size, "%s(%s)",
2062 simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2066 name = check_label_read_ref(po, popr->name);
2067 if (cast[0] == 0 && popr->is_ptr)
2071 snprintf(buf, buf_size, "(u32)&%s", name);
2072 else if (popr->size_lt)
2073 snprintf(buf, buf_size, "%s%s%s%s", cast,
2074 lmod_cast_u_ptr(po, popr->lmod),
2075 popr->is_array ? "" : "&", name);
2077 snprintf(buf, buf_size, "%s%s%s", cast, name,
2078 popr->is_array ? "[0]" : "");
2082 name = check_label_read_ref(po, popr->name);
2086 ferr(po, "lea an offset?\n");
2087 snprintf(buf, buf_size, "%s&%s", cast, name);
2092 ferr(po, "lea from const?\n");
2094 printf_number(tmp1, sizeof(tmp1), popr->val);
2095 if (popr->val == 0 && strchr(cast, '*'))
2096 snprintf(buf, buf_size, "NULL");
2098 snprintf(buf, buf_size, "%s%s",
2099 simplify_cast_num(cast, popr->val), tmp1);
2103 ferr(po, "invalid src type: %d\n", popr->type);
2109 // note: may set is_ptr (we find that out late for ebp frame..)
2110 static char *out_dst_opr(char *buf, size_t buf_size,
2111 struct parsed_op *po, struct parsed_opr *popr)
2113 switch (popr->type) {
2115 switch (popr->lmod) {
2117 snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2120 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2124 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2128 if (popr->name[1] == 'h') // XXX..
2129 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2131 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2134 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2139 if (is_stack_access(po, popr)) {
2140 stack_frame_access(po, popr, buf, buf_size,
2141 popr->name, "", 0, 0);
2145 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2148 if (popr->size_mismatch)
2149 snprintf(buf, buf_size, "%s%s%s",
2150 lmod_cast_u_ptr(po, popr->lmod),
2151 popr->is_array ? "" : "&", popr->name);
2153 snprintf(buf, buf_size, "%s%s", popr->name,
2154 popr->is_array ? "[0]" : "");
2158 ferr(po, "invalid dst type: %d\n", popr->type);
2164 static char *out_src_opr_u32(char *buf, size_t buf_size,
2165 struct parsed_op *po, struct parsed_opr *popr)
2167 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2170 static char *out_src_opr_float(char *buf, size_t buf_size,
2171 struct parsed_op *po, struct parsed_opr *popr)
2173 const char *cast = NULL;
2176 switch (popr->type) {
2178 if (popr->reg < xST0 || popr->reg > xST7)
2179 ferr(po, "bad reg: %d\n", popr->reg);
2181 snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2187 switch (popr->lmod) {
2195 ferr(po, "unhandled lmod: %d\n", popr->lmod);
2198 out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2199 snprintf(buf, buf_size, "*((%s *)%s)", cast, tmp);
2203 ferr(po, "invalid float type: %d\n", popr->type);
2209 static char *out_dst_opr_float(char *buf, size_t buf_size,
2210 struct parsed_op *po, struct parsed_opr *popr)
2213 return out_src_opr_float(buf, buf_size, po, popr);
2216 static void out_test_for_cc(char *buf, size_t buf_size,
2217 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2218 enum opr_lenmod lmod, const char *expr)
2220 const char *cast, *scast;
2222 cast = lmod_cast_u(po, lmod);
2223 scast = lmod_cast_s(po, lmod);
2227 case PFO_BE: // CF=1||ZF=1; CF=0
2228 snprintf(buf, buf_size, "(%s%s %s 0)",
2229 cast, expr, is_inv ? "!=" : "==");
2233 case PFO_L: // SF!=OF; OF=0
2234 snprintf(buf, buf_size, "(%s%s %s 0)",
2235 scast, expr, is_inv ? ">=" : "<");
2238 case PFO_LE: // ZF=1||SF!=OF; OF=0
2239 snprintf(buf, buf_size, "(%s%s %s 0)",
2240 scast, expr, is_inv ? ">" : "<=");
2244 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2248 static void out_cmp_for_cc(char *buf, size_t buf_size,
2249 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2251 const char *cast, *scast, *cast_use;
2252 char buf1[256], buf2[256];
2253 enum opr_lenmod lmod;
2255 if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2256 ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2257 po->operand[0].lmod, po->operand[1].lmod);
2258 lmod = po->operand[0].lmod;
2260 cast = lmod_cast_u(po, lmod);
2261 scast = lmod_cast_s(po, lmod);
2277 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2280 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2281 if (po->op == OP_DEC)
2282 snprintf(buf2, sizeof(buf2), "1");
2284 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_use, 0);
2288 // note: must be unsigned compare
2289 snprintf(buf, buf_size, "(%s %s %s)",
2290 buf1, is_inv ? ">=" : "<", buf2);
2294 snprintf(buf, buf_size, "(%s %s %s)",
2295 buf1, is_inv ? "!=" : "==", buf2);
2299 // note: must be unsigned compare
2300 snprintf(buf, buf_size, "(%s %s %s)",
2301 buf1, is_inv ? ">" : "<=", buf2);
2304 if (is_inv && lmod == OPLM_BYTE
2305 && po->operand[1].type == OPT_CONST
2306 && po->operand[1].val == 0xff)
2308 snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2309 snprintf(buf, buf_size, "(0)");
2313 // note: must be signed compare
2315 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2316 scast, buf1, buf2, is_inv ? ">=" : "<");
2320 snprintf(buf, buf_size, "(%s %s %s)",
2321 buf1, is_inv ? ">=" : "<", buf2);
2325 snprintf(buf, buf_size, "(%s %s %s)",
2326 buf1, is_inv ? ">" : "<=", buf2);
2334 static void out_cmp_test(char *buf, size_t buf_size,
2335 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2337 char buf1[256], buf2[256], buf3[256];
2339 if (po->op == OP_TEST) {
2340 if (IS(opr_name(po, 0), opr_name(po, 1))) {
2341 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2344 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2345 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2346 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2348 out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2349 po->operand[0].lmod, buf3);
2351 else if (po->op == OP_CMP) {
2352 out_cmp_for_cc(buf, buf_size, po, pfo, is_inv);
2355 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2358 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2359 struct parsed_opr *popr2)
2361 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2362 ferr(po, "missing lmod for both operands\n");
2364 if (popr1->lmod == OPLM_UNSPEC)
2365 popr1->lmod = popr2->lmod;
2366 else if (popr2->lmod == OPLM_UNSPEC)
2367 popr2->lmod = popr1->lmod;
2368 else if (popr1->lmod != popr2->lmod) {
2369 if (popr1->type_from_var) {
2370 popr1->size_mismatch = 1;
2371 if (popr1->lmod < popr2->lmod)
2373 popr1->lmod = popr2->lmod;
2375 else if (popr2->type_from_var) {
2376 popr2->size_mismatch = 1;
2377 if (popr2->lmod < popr1->lmod)
2379 popr2->lmod = popr1->lmod;
2382 ferr(po, "conflicting lmods: %d vs %d\n",
2383 popr1->lmod, popr2->lmod);
2387 static const char *op_to_c(struct parsed_op *po)
2411 ferr(po, "op_to_c was supplied with %d\n", po->op);
2415 // last op in stream - unconditional branch or ret
2416 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2417 || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2418 && ops[_i].op != OP_CALL))
2420 #define check_i(po, i) \
2422 ferr(po, "bad " #i ": %d\n", i)
2424 // note: this skips over calls and rm'd stuff assuming they're handled
2425 // so it's intended to use at one of final passes
2426 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2427 int depth, int flags_set)
2429 struct parsed_op *po;
2434 for (; i < opcnt; i++) {
2436 if (po->cc_scratch == magic)
2437 return ret; // already checked
2438 po->cc_scratch = magic;
2440 if (po->flags & OPF_TAIL) {
2441 if (po->op == OP_CALL) {
2442 if (po->pp != NULL && po->pp->is_noreturn)
2443 // assume no stack cleanup for noreturn
2446 return -1; // deadend
2449 if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
2452 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2453 if (po->btj != NULL) {
2455 for (j = 0; j < po->btj->count; j++) {
2456 check_i(po, po->btj->d[j].bt_i);
2457 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2460 return ret; // dead end
2465 check_i(po, po->bt_i);
2466 if (po->flags & OPF_CJMP) {
2467 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2470 return ret; // dead end
2479 if ((po->op == OP_POP || po->op == OP_PUSH)
2480 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2485 if (po->op == OP_PUSH) {
2488 else if (po->op == OP_POP) {
2489 if (relevant && depth == 0) {
2490 po->flags |= flags_set;
2500 // scan for 'reg' pop backwards starting from i
2501 // intended to use for register restore search, so other reg
2502 // references are considered an error
2503 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2505 struct parsed_op *po;
2506 struct label_ref *lr;
2509 ops[i].cc_scratch = magic;
2513 if (g_labels[i] != NULL) {
2514 lr = &g_label_refs[i];
2515 for (; lr != NULL; lr = lr->next) {
2516 check_i(&ops[i], lr->i);
2517 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2521 if (i > 0 && LAST_OP(i - 1))
2529 if (ops[i].cc_scratch == magic)
2531 ops[i].cc_scratch = magic;
2534 if (po->op == OP_POP && po->operand[0].reg == reg) {
2535 if (po->flags & (OPF_RMD|OPF_DONE))
2538 po->flags |= set_flags;
2542 // this also covers the case where we reach corresponding push
2543 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2547 // nothing interesting on this path
2551 static void find_reachable_exits(int i, int opcnt, int magic,
2552 int *exits, int *exit_count)
2554 struct parsed_op *po;
2557 for (; i < opcnt; i++)
2560 if (po->cc_scratch == magic)
2562 po->cc_scratch = magic;
2564 if (po->flags & OPF_TAIL) {
2565 ferr_assert(po, *exit_count < MAX_EXITS);
2566 exits[*exit_count] = i;
2571 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2572 if (po->flags & OPF_RMD)
2575 if (po->btj != NULL) {
2576 for (j = 0; j < po->btj->count; j++) {
2577 check_i(po, po->btj->d[j].bt_i);
2578 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2584 check_i(po, po->bt_i);
2585 if (po->flags & OPF_CJMP)
2586 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2594 // scan for 'reg' pop backwards starting from exits (all paths)
2595 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2597 static int exits[MAX_EXITS];
2598 static int exit_count;
2603 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2605 ferr_assert(&ops[i], exit_count > 0);
2608 for (j = 0; j < exit_count; j++) {
2609 ret = scan_for_rsave_pop_reg(exits[j], i + opcnt * 16 + set_flags,
2618 // scan for one or more pop of push <const>
2619 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2620 int push_i, int is_probe)
2622 struct parsed_op *po;
2623 struct label_ref *lr;
2627 for (; i < opcnt; i++)
2630 if (po->cc_scratch == magic)
2631 return ret; // already checked
2632 po->cc_scratch = magic;
2634 if (po->flags & OPF_JMP) {
2635 if (po->flags & OPF_RMD)
2637 if (po->op == OP_CALL)
2640 if (po->btj != NULL) {
2641 for (j = 0; j < po->btj->count; j++) {
2642 check_i(po, po->btj->d[j].bt_i);
2643 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2651 check_i(po, po->bt_i);
2652 if (po->flags & OPF_CJMP) {
2653 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2664 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2667 if (g_labels[i] != NULL) {
2668 // all refs must be visited
2669 lr = &g_label_refs[i];
2670 for (; lr != NULL; lr = lr->next) {
2672 if (ops[lr->i].cc_scratch != magic)
2675 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2679 if (po->op == OP_POP)
2681 if (po->flags & (OPF_RMD|OPF_DONE))
2685 po->flags |= OPF_DONE;
2686 po->datap = &ops[push_i];
2695 static void scan_for_pop_const(int i, int opcnt, int magic)
2699 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
2701 ops[i].flags |= OPF_RMD | OPF_DONE;
2702 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
2706 // check if all branch targets within a marked path are also marked
2707 // note: the path checked must not be empty or end with a branch
2708 static int check_path_branches(int opcnt, int magic)
2710 struct parsed_op *po;
2713 for (i = 0; i < opcnt; i++) {
2715 if (po->cc_scratch != magic)
2718 if (po->flags & OPF_JMP) {
2719 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
2722 if (po->btj != NULL) {
2723 for (j = 0; j < po->btj->count; j++) {
2724 check_i(po, po->btj->d[j].bt_i);
2725 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
2730 check_i(po, po->bt_i);
2731 if (ops[po->bt_i].cc_scratch != magic)
2733 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
2741 // scan for multiple pushes for given pop
2742 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
2745 int reg = ops[pop_i].operand[0].reg;
2746 struct parsed_op *po;
2747 struct label_ref *lr;
2750 ops[i].cc_scratch = magic;
2754 if (g_labels[i] != NULL) {
2755 lr = &g_label_refs[i];
2756 for (; lr != NULL; lr = lr->next) {
2757 check_i(&ops[i], lr->i);
2758 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
2762 if (i > 0 && LAST_OP(i - 1))
2770 if (ops[i].cc_scratch == magic)
2772 ops[i].cc_scratch = magic;
2775 if (po->op == OP_CALL)
2777 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
2780 if (po->op == OP_PUSH)
2782 if (po->datap != NULL)
2784 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2785 // leave this case for reg save/restore handlers
2789 po->flags |= OPF_PPUSH | OPF_DONE;
2790 po->datap = &ops[pop_i];
2799 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
2801 int magic = i + opcnt * 14;
2804 ret = scan_pushes_for_pop_r(i, magic, i, 1);
2806 ret = check_path_branches(opcnt, magic);
2808 ops[i].flags |= OPF_PPUSH | OPF_DONE;
2809 *regmask_pp |= 1 << ops[i].operand[0].reg;
2810 scan_pushes_for_pop_r(i, magic + 1, i, 0);
2815 static void scan_propagate_df(int i, int opcnt)
2817 struct parsed_op *po = &ops[i];
2820 for (; i < opcnt; i++) {
2822 if (po->flags & OPF_DF)
2823 return; // already resolved
2824 po->flags |= OPF_DF;
2826 if (po->op == OP_CALL)
2827 ferr(po, "call with DF set?\n");
2829 if (po->flags & OPF_JMP) {
2830 if (po->btj != NULL) {
2832 for (j = 0; j < po->btj->count; j++) {
2833 check_i(po, po->btj->d[j].bt_i);
2834 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
2839 if (po->flags & OPF_RMD)
2841 check_i(po, po->bt_i);
2842 if (po->flags & OPF_CJMP)
2843 scan_propagate_df(po->bt_i, opcnt);
2849 if (po->flags & OPF_TAIL)
2852 if (po->op == OP_CLD) {
2853 po->flags |= OPF_RMD | OPF_DONE;
2858 ferr(po, "missing DF clear?\n");
2861 // is operand 'opr' referenced by parsed_op 'po'?
2862 static int is_opr_referenced(const struct parsed_opr *opr,
2863 const struct parsed_op *po)
2867 if (opr->type == OPT_REG) {
2868 mask = po->regmask_dst | po->regmask_src;
2869 if (po->op == OP_CALL)
2870 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
2871 if ((1 << opr->reg) & mask)
2877 for (i = 0; i < po->operand_cnt; i++)
2878 if (IS(po->operand[0].name, opr->name))
2884 // is operand 'opr' read by parsed_op 'po'?
2885 static int is_opr_read(const struct parsed_opr *opr,
2886 const struct parsed_op *po)
2888 if (opr->type == OPT_REG) {
2889 if (po->regmask_src & (1 << opr->reg))
2899 // is operand 'opr' modified by parsed_op 'po'?
2900 static int is_opr_modified(const struct parsed_opr *opr,
2901 const struct parsed_op *po)
2905 if (opr->type == OPT_REG) {
2906 if (po->op == OP_CALL) {
2907 mask = po->regmask_dst;
2908 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
2909 if (mask & (1 << opr->reg))
2915 if (po->regmask_dst & (1 << opr->reg))
2921 return IS(po->operand[0].name, opr->name);
2924 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
2925 static int is_any_opr_modified(const struct parsed_op *po_test,
2926 const struct parsed_op *po, int c_mode)
2931 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
2934 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
2937 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
2940 // in reality, it can wreck any register, but in decompiled C
2941 // version it can only overwrite eax or edx:eax
2942 mask = (1 << xAX) | (1 << xDX);
2946 if (po->op == OP_CALL
2947 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
2950 for (i = 0; i < po_test->operand_cnt; i++)
2951 if (IS(po_test->operand[i].name, po->operand[0].name))
2957 // scan for any po_test operand modification in range given
2958 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
2961 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
2964 for (; i < opcnt; i++) {
2965 if (is_any_opr_modified(po_test, &ops[i], c_mode))
2972 // scan for po_test operand[0] modification in range given
2973 static int scan_for_mod_opr0(struct parsed_op *po_test,
2976 for (; i < opcnt; i++) {
2977 if (is_opr_modified(&po_test->operand[0], &ops[i]))
2984 static int scan_for_flag_set(int i, int magic, int *branched,
2985 int *setters, int *setter_cnt)
2987 struct label_ref *lr;
2991 if (ops[i].cc_scratch == magic) {
2992 // is this a problem?
2993 //ferr(&ops[i], "%s looped\n", __func__);
2996 ops[i].cc_scratch = magic;
2998 if (g_labels[i] != NULL) {
3001 lr = &g_label_refs[i];
3002 for (; lr->next; lr = lr->next) {
3003 check_i(&ops[i], lr->i);
3004 ret = scan_for_flag_set(lr->i, magic,
3005 branched, setters, setter_cnt);
3010 check_i(&ops[i], lr->i);
3011 if (i > 0 && LAST_OP(i - 1)) {
3015 ret = scan_for_flag_set(lr->i, magic,
3016 branched, setters, setter_cnt);
3022 if (ops[i].flags & OPF_FLAGS) {
3023 setters[*setter_cnt] = i;
3028 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3035 // scan back for cdq, if anything modifies edx, fail
3036 static int scan_for_cdq_edx(int i)
3039 if (g_labels[i] != NULL) {
3040 if (g_label_refs[i].next != NULL)
3042 if (i > 0 && LAST_OP(i - 1)) {
3043 i = g_label_refs[i].i;
3050 if (ops[i].op == OP_CDQ)
3053 if (ops[i].regmask_dst & (1 << xDX))
3060 static int scan_for_reg_clear(int i, int reg)
3063 if (g_labels[i] != NULL) {
3064 if (g_label_refs[i].next != NULL)
3066 if (i > 0 && LAST_OP(i - 1)) {
3067 i = g_label_refs[i].i;
3074 if (ops[i].op == OP_XOR
3075 && ops[i].operand[0].lmod == OPLM_DWORD
3076 && ops[i].operand[0].reg == ops[i].operand[1].reg
3077 && ops[i].operand[0].reg == reg)
3080 if (ops[i].regmask_dst & (1 << reg))
3087 static void patch_esp_adjust(struct parsed_op *po, int adj)
3089 ferr_assert(po, po->op == OP_ADD);
3090 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3091 ferr_assert(po, po->operand[1].type == OPT_CONST);
3093 // this is a bit of a hack, but deals with use of
3094 // single adj for multiple calls
3095 po->operand[1].val -= adj;
3096 po->flags |= OPF_RMD;
3097 if (po->operand[1].val == 0)
3098 po->flags |= OPF_DONE;
3099 ferr_assert(po, (int)po->operand[1].val >= 0);
3102 // scan for positive, constant esp adjust
3103 // multipath case is preliminary
3104 static int scan_for_esp_adjust(int i, int opcnt,
3105 int adj_expect, int *adj, int *is_multipath, int do_update)
3107 int adj_expect_unknown = 0;
3108 struct parsed_op *po;
3112 *adj = *is_multipath = 0;
3113 if (adj_expect < 0) {
3114 adj_expect_unknown = 1;
3115 adj_expect = 32 * 4; // enough?
3118 for (; i < opcnt && *adj < adj_expect; i++) {
3119 if (g_labels[i] != NULL)
3123 if (po->flags & OPF_DONE)
3126 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3127 if (po->operand[1].type != OPT_CONST)
3128 ferr(&ops[i], "non-const esp adjust?\n");
3129 *adj += po->operand[1].val;
3131 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3134 patch_esp_adjust(po, adj_expect);
3136 po->flags |= OPF_RMD;
3140 else if (po->op == OP_PUSH) {
3141 //if (first_pop == -1)
3142 // first_pop = -2; // none
3143 *adj -= lmod_bytes(po, po->operand[0].lmod);
3145 else if (po->op == OP_POP) {
3146 if (!(po->flags & OPF_DONE)) {
3147 // seems like msvc only uses 'pop ecx' for stack realignment..
3148 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3150 if (first_pop == -1 && *adj >= 0)
3153 if (do_update && *adj >= 0) {
3154 po->flags |= OPF_RMD;
3156 po->flags |= OPF_DONE | OPF_NOREGS;
3159 *adj += lmod_bytes(po, po->operand[0].lmod);
3160 if (*adj > adj_best)
3163 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3164 if (po->op == OP_JMP && po->btj == NULL) {
3170 if (po->op != OP_CALL)
3172 if (po->operand[0].type != OPT_LABEL)
3174 if (po->pp != NULL && po->pp->is_stdcall)
3176 if (adj_expect_unknown && first_pop >= 0)
3178 // assume it's another cdecl call
3182 if (first_pop >= 0) {
3183 // probably only 'pop ecx' was used
3191 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3193 struct parsed_op *po;
3197 ferr(ops, "%s: followed bad branch?\n", __func__);
3199 for (; i < opcnt; i++) {
3201 if (po->cc_scratch == magic)
3203 po->cc_scratch = magic;
3206 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3207 if (po->btj != NULL) {
3209 for (j = 0; j < po->btj->count; j++)
3210 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3214 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3215 if (!(po->flags & OPF_CJMP))
3218 if (po->flags & OPF_TAIL)
3223 static const struct parsed_proto *try_recover_pp(
3224 struct parsed_op *po, const struct parsed_opr *opr, int *search_instead)
3226 const struct parsed_proto *pp = NULL;
3230 // maybe an arg of g_func?
3231 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3233 char ofs_reg[16] = { 0, };
3234 int arg, arg_s, arg_i;
3241 parse_stack_access(po, opr->name, ofs_reg,
3242 &offset, &stack_ra, NULL, 0);
3243 if (ofs_reg[0] != 0)
3244 ferr(po, "offset reg on arg access?\n");
3245 if (offset <= stack_ra) {
3246 // search who set the stack var instead
3247 if (search_instead != NULL)
3248 *search_instead = 1;
3252 arg_i = (offset - stack_ra - 4) / 4;
3253 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3254 if (g_func_pp->arg[arg].reg != NULL)
3260 if (arg == g_func_pp->argc)
3261 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3263 pp = g_func_pp->arg[arg].fptr;
3265 ferr(po, "icall sa: arg%d is not a fptr?\n", arg + 1);
3266 check_func_pp(po, pp, "icall arg");
3268 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3270 p = strchr(opr->name + 1, '[');
3271 memcpy(buf, opr->name, p - opr->name);
3272 buf[p - opr->name] = 0;
3273 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3275 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3276 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3279 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3282 check_func_pp(po, pp, "reg-fptr ref");
3288 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3289 int magic, const struct parsed_proto **pp_found, int *pp_i,
3292 const struct parsed_proto *pp = NULL;
3293 struct parsed_op *po;
3294 struct label_ref *lr;
3296 ops[i].cc_scratch = magic;
3299 if (g_labels[i] != NULL) {
3300 lr = &g_label_refs[i];
3301 for (; lr != NULL; lr = lr->next) {
3302 check_i(&ops[i], lr->i);
3303 scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3305 if (i > 0 && LAST_OP(i - 1))
3313 if (ops[i].cc_scratch == magic)
3315 ops[i].cc_scratch = magic;
3317 if (!(ops[i].flags & OPF_DATA))
3319 if (!is_opr_modified(opr, &ops[i]))
3321 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3322 // most probably trashed by some processing
3327 opr = &ops[i].operand[1];
3328 if (opr->type != OPT_REG)
3332 po = (i >= 0) ? &ops[i] : ops;
3335 // reached the top - can only be an arg-reg
3336 if (opr->type != OPT_REG || g_func_pp == NULL)
3339 for (i = 0; i < g_func_pp->argc; i++) {
3340 if (g_func_pp->arg[i].reg == NULL)
3342 if (IS(opr->name, g_func_pp->arg[i].reg))
3345 if (i == g_func_pp->argc)
3347 pp = g_func_pp->arg[i].fptr;
3349 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3350 i + 1, g_func_pp->arg[i].reg);
3351 check_func_pp(po, pp, "icall reg-arg");
3354 pp = try_recover_pp(po, opr, NULL);
3356 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3357 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3358 || (*pp_found)->is_stdcall != pp->is_stdcall
3359 || (*pp_found)->is_fptr != pp->is_fptr
3360 || (*pp_found)->argc != pp->argc
3361 || (*pp_found)->argc_reg != pp->argc_reg
3362 || (*pp_found)->argc_stack != pp->argc_stack)
3364 ferr(po, "icall: parsed_proto mismatch\n");
3374 static void add_label_ref(struct label_ref *lr, int op_i)
3376 struct label_ref *lr_new;
3383 lr_new = calloc(1, sizeof(*lr_new));
3385 lr_new->next = lr->next;
3389 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3391 struct parsed_op *po = &ops[i];
3392 struct parsed_data *pd;
3393 char label[NAMELEN], *p;
3396 p = strchr(po->operand[0].name, '[');
3400 len = p - po->operand[0].name;
3401 strncpy(label, po->operand[0].name, len);
3404 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3405 if (IS(g_func_pd[j].label, label)) {
3411 //ferr(po, "label '%s' not parsed?\n", label);
3414 if (pd->type != OPT_OFFSET)
3415 ferr(po, "label '%s' with non-offset data?\n", label);
3417 // find all labels, link
3418 for (j = 0; j < pd->count; j++) {
3419 for (l = 0; l < opcnt; l++) {
3420 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3421 add_label_ref(&g_label_refs[l], i);
3431 static void clear_labels(int count)
3435 for (i = 0; i < count; i++) {
3436 if (g_labels[i] != NULL) {
3443 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3448 for (i = 0; i < pp->argc; i++) {
3449 if (pp->arg[i].reg != NULL) {
3450 reg = char_array_i(regs_r32,
3451 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3453 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3454 pp->arg[i].reg, pp->name);
3455 regmask |= 1 << reg;
3462 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3467 if (pp->has_retreg) {
3468 for (i = 0; i < pp->argc; i++) {
3469 if (pp->arg[i].type.is_retreg) {
3470 reg = char_array_i(regs_r32,
3471 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3472 ferr_assert(ops, reg >= 0);
3473 regmask |= 1 << reg;
3478 if (strstr(pp->ret_type.name, "int64"))
3479 return regmask | (1 << xAX) | (1 << xDX);
3480 if (IS(pp->ret_type.name, "float")
3481 || IS(pp->ret_type.name, "double"))
3483 return regmask | mxST0;
3485 if (strcasecmp(pp->ret_type.name, "void") == 0)
3488 return regmask | mxAX;
3491 static void resolve_branches_parse_calls(int opcnt)
3493 static const struct {
3497 unsigned int regmask_src;
3498 unsigned int regmask_dst;
3500 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3502 const struct parsed_proto *pp_c;
3503 struct parsed_proto *pp;
3504 struct parsed_data *pd;
3505 struct parsed_op *po;
3506 const char *tmpname;
3510 for (i = 0; i < opcnt; i++)
3516 if (po->datap != NULL) {
3517 pp = calloc(1, sizeof(*pp));
3518 my_assert_not(pp, NULL);
3520 ret = parse_protostr(po->datap, pp);
3522 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3528 if (po->op == OP_CALL) {
3533 else if (po->operand[0].type == OPT_LABEL)
3535 tmpname = opr_name(po, 0);
3536 if (IS_START(tmpname, "loc_"))
3537 ferr(po, "call to loc_*\n");
3539 // convert some calls to pseudo-ops
3540 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3541 if (!IS(tmpname, pseudo_ops[l].name))
3544 po->op = pseudo_ops[l].op;
3545 po->operand_cnt = 0;
3546 po->regmask_src = pseudo_ops[l].regmask_src;
3547 po->regmask_dst = pseudo_ops[l].regmask_dst;
3548 po->flags = pseudo_ops[l].flags;
3549 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3552 if (l < ARRAY_SIZE(pseudo_ops))
3555 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3556 if (!g_header_mode && pp_c == NULL)
3557 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3560 pp = proto_clone(pp_c);
3561 my_assert_not(pp, NULL);
3567 check_func_pp(po, pp, "fptr var call");
3568 if (pp->is_noreturn)
3569 po->flags |= OPF_TAIL;
3575 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3578 if (po->operand[0].type == OPT_REGMEM) {
3579 pd = try_resolve_jumptab(i, opcnt);
3587 for (l = 0; l < opcnt; l++) {
3588 if (g_labels[l] != NULL
3589 && IS(po->operand[0].name, g_labels[l]))
3591 if (l == i + 1 && po->op == OP_JMP) {
3592 // yet another alignment type..
3593 po->flags |= OPF_RMD|OPF_DONE;
3596 add_label_ref(&g_label_refs[l], i);
3602 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3605 if (po->operand[0].type == OPT_LABEL)
3609 ferr(po, "unhandled branch\n");
3613 po->flags |= OPF_TAIL;
3614 if (i > 0 && ops[i - 1].op == OP_POP)
3615 po->flags |= OPF_ATAIL;
3620 static void scan_prologue_epilogue(int opcnt)
3622 int ecx_push = 0, esp_sub = 0;
3626 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
3627 && ops[1].op == OP_MOV
3628 && IS(opr_name(&ops[1], 0), "ebp")
3629 && IS(opr_name(&ops[1], 1), "esp"))
3632 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3633 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3636 if (ops[2].op == OP_SUB && IS(opr_name(&ops[2], 0), "esp")) {
3637 g_stack_fsz = opr_const(&ops[2], 1);
3638 ops[2].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3642 // another way msvc builds stack frame..
3644 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3646 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3650 // and another way..
3651 if (i == 2 && ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3652 && ops[i].operand[1].type == OPT_CONST
3653 && ops[i + 1].op == OP_CALL
3654 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3656 g_stack_fsz += ops[i].operand[1].val;
3657 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3659 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3666 for (; i < opcnt; i++)
3667 if (ops[i].flags & OPF_TAIL)
3670 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3671 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3677 if ((ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
3678 || ops[j].op == OP_LEAVE)
3680 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3682 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
3683 && ops[i].pp->is_noreturn)
3685 // on noreturn, msvc sometimes cleans stack, sometimes not
3690 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3691 ferr(&ops[j], "'pop ebp' expected\n");
3693 if (g_stack_fsz != 0) {
3694 if (ops[j].op == OP_LEAVE)
3696 else if (ops[j].op == OP_POP
3697 && ops[j - 1].op == OP_MOV
3698 && IS(opr_name(&ops[j - 1], 0), "esp")
3699 && IS(opr_name(&ops[j - 1], 1), "ebp"))
3701 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3704 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3706 ferr(&ops[j], "esp restore expected\n");
3709 if (ecx_push && j >= 0 && ops[j].op == OP_POP
3710 && IS(opr_name(&ops[j], 0), "ecx"))
3712 ferr(&ops[j], "unexpected ecx pop\n");
3718 } while (i < opcnt);
3721 ferr(ops, "missing ebp epilogue\n");
3727 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3728 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3734 for (; i < opcnt; i++) {
3735 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
3737 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
3738 && ops[i].operand[1].type == OPT_CONST)
3740 g_stack_fsz = ops[i].operand[1].val;
3741 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3747 if (ecx_push && !esp_sub) {
3748 // could actually be args for a call..
3749 for (; i < opcnt; i++)
3750 if (ops[i].op != OP_PUSH)
3753 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
3754 const struct parsed_proto *pp;
3755 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
3756 j = pp ? pp->argc_stack : 0;
3757 while (i > 0 && j > 0) {
3759 if (ops[i].op == OP_PUSH) {
3760 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
3765 ferr(&ops[i], "unhandled prologue\n");
3768 i = g_stack_fsz = ecx_push = 0;
3769 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3770 if (!(ops[i].flags & OPF_RMD))
3780 if (ecx_push || esp_sub)
3786 for (; i < opcnt; i++)
3787 if (ops[i].flags & OPF_TAIL)
3790 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3791 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3798 for (l = 0; l < ecx_push; l++) {
3799 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
3801 else if (ops[j].op == OP_ADD
3802 && IS(opr_name(&ops[j], 0), "esp")
3803 && ops[j].operand[1].type == OPT_CONST)
3806 l += ops[j].operand[1].val / 4 - 1;
3809 ferr(&ops[j], "'pop ecx' expected\n");
3811 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3815 ferr(&ops[j], "epilogue scan failed\n");
3821 if (ops[j].op != OP_ADD
3822 || !IS(opr_name(&ops[j], 0), "esp")
3823 || ops[j].operand[1].type != OPT_CONST
3824 || ops[j].operand[1].val != g_stack_fsz)
3825 ferr(&ops[j], "'add esp' expected\n");
3827 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3828 ops[j].operand[1].val = 0; // hack for stack arg scanner
3833 } while (i < opcnt);
3836 ferr(ops, "missing esp epilogue\n");
3840 // find an instruction that changed opr before i op
3841 // *op_i must be set to -1 by the caller
3842 // *is_caller is set to 1 if one source is determined to be g_func arg
3843 // returns 1 if found, *op_i is then set to origin
3844 // returns -1 if multiple origins are found
3845 static int resolve_origin(int i, const struct parsed_opr *opr,
3846 int magic, int *op_i, int *is_caller)
3848 struct label_ref *lr;
3851 if (ops[i].cc_scratch == magic)
3853 ops[i].cc_scratch = magic;
3856 if (g_labels[i] != NULL) {
3857 lr = &g_label_refs[i];
3858 for (; lr != NULL; lr = lr->next) {
3859 check_i(&ops[i], lr->i);
3860 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
3862 if (i > 0 && LAST_OP(i - 1))
3868 if (is_caller != NULL)
3873 if (ops[i].cc_scratch == magic)
3875 ops[i].cc_scratch = magic;
3877 if (!(ops[i].flags & OPF_DATA))
3879 if (!is_opr_modified(opr, &ops[i]))
3886 // XXX: could check if the other op does the same
3895 // find an instruction that previously referenced opr
3896 // if multiple results are found - fail
3897 // *op_i must be set to -1 by the caller
3898 // returns 1 if found, *op_i is then set to referencer insn
3899 static int resolve_last_ref(int i, const struct parsed_opr *opr,
3900 int magic, int *op_i)
3902 struct label_ref *lr;
3905 if (ops[i].cc_scratch == magic)
3907 ops[i].cc_scratch = magic;
3910 if (g_labels[i] != NULL) {
3911 lr = &g_label_refs[i];
3912 for (; lr != NULL; lr = lr->next) {
3913 check_i(&ops[i], lr->i);
3914 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
3916 if (i > 0 && LAST_OP(i - 1))
3924 if (ops[i].cc_scratch == magic)
3926 ops[i].cc_scratch = magic;
3928 if (!is_opr_referenced(opr, &ops[i]))
3939 // find next instruction that reads opr
3940 // *op_i must be set to -1 by the caller
3941 // on return, *op_i is set to first referencer insn
3942 // returns 1 if exactly 1 referencer is found
3943 static int find_next_read(int i, int opcnt,
3944 const struct parsed_opr *opr, int magic, int *op_i)
3946 struct parsed_op *po;
3949 for (; i < opcnt; i++)
3951 if (ops[i].cc_scratch == magic)
3953 ops[i].cc_scratch = magic;
3956 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3957 if (po->btj != NULL) {
3959 for (j = 0; j < po->btj->count; j++) {
3960 check_i(po, po->btj->d[j].bt_i);
3961 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
3967 if (po->flags & OPF_RMD)
3969 check_i(po, po->bt_i);
3970 if (po->flags & OPF_CJMP) {
3971 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
3980 if (!is_opr_read(opr, po)) {
3981 if (is_opr_modified(opr, po)
3982 && (po->op == OP_CALL
3983 || ((po->flags & OPF_DATA)
3984 && po->operand[0].lmod == OPLM_DWORD)))
3989 if (po->flags & OPF_TAIL)
4004 static int try_resolve_const(int i, const struct parsed_opr *opr,
4005 int magic, unsigned int *val)
4010 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4013 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4016 *val = ops[i].operand[1].val;
4023 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4024 int *pp_i, int *multi_src)
4026 const struct parsed_proto *pp = NULL;
4027 int search_advice = 0;
4037 switch (ops[i].operand[0].type) {
4039 // try to resolve struct member calls
4040 ret = sscanf(ops[i].operand[0].name, "%3s+%x%n",
4041 s_reg, &offset, &len);
4042 if (ret == 2 && len == strlen(ops[i].operand[0].name))
4044 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4046 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, reg);
4048 ret = resolve_origin(i, &opr, i + opcnt * 19, &j, NULL);
4051 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4052 && ops[j].operand[0].lmod == OPLM_DWORD
4053 && ops[j].pp == NULL) // no hint
4055 // allow one simple dereference (directx)
4056 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4057 ops[j].operand[1].name);
4060 struct parsed_opr opr2 = OPR_INIT(OPT_REG, OPLM_DWORD, reg);
4062 ret = resolve_origin(j, &opr2, j + opcnt * 19, &k, NULL);
4067 if (ops[j].op != OP_MOV)
4069 if (ops[j].operand[0].lmod != OPLM_DWORD)
4071 if (ops[j].pp != NULL) {
4075 else if (ops[j].operand[1].type == OPT_REGMEM) {
4076 // allow 'hello[ecx]' - assume array of same type items
4077 ret = sscanf(ops[j].operand[1].name, "%[^[][e%2s]",
4081 pp = proto_parse(g_fhdr, name, g_quiet_pp);
4083 else if (ops[j].operand[1].type == OPT_LABEL)
4084 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4089 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4093 pp = proto_lookup_struct(g_fhdr, pp->type.name, offset);
4100 pp = try_recover_pp(&ops[i], &ops[i].operand[0], &search_advice);
4105 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4113 static struct parsed_proto *process_call_early(int i, int opcnt,
4116 struct parsed_op *po = &ops[i];
4117 struct parsed_proto *pp;
4123 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4127 // look for and make use of esp adjust
4129 if (!pp->is_stdcall && pp->argc_stack > 0)
4130 ret = scan_for_esp_adjust(i + 1, opcnt,
4131 pp->argc_stack * 4, &adj, &multipath, 0);
4133 if (pp->argc_stack > adj / 4)
4137 if (ops[ret].op == OP_POP) {
4138 for (j = 1; j < adj / 4; j++) {
4139 if (ops[ret + j].op != OP_POP
4140 || ops[ret + j].operand[0].reg != xCX)
4152 static struct parsed_proto *process_call(int i, int opcnt)
4154 struct parsed_op *po = &ops[i];
4155 const struct parsed_proto *pp_c;
4156 struct parsed_proto *pp;
4157 const char *tmpname;
4158 int call_i = -1, ref_i = -1;
4159 int adj = 0, multipath = 0;
4162 tmpname = opr_name(po, 0);
4167 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4169 if (!pp_c->is_func && !pp_c->is_fptr)
4170 ferr(po, "call to non-func: %s\n", pp_c->name);
4171 pp = proto_clone(pp_c);
4172 my_assert_not(pp, NULL);
4174 // not resolved just to single func
4177 switch (po->operand[0].type) {
4179 // we resolved this call and no longer need the register
4180 po->regmask_src &= ~(1 << po->operand[0].reg);
4182 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4183 && ops[call_i].operand[1].type == OPT_LABEL)
4185 // no other source users?
4186 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4188 if (ret == 1 && call_i == ref_i) {
4189 // and nothing uses it after us?
4191 find_next_read(i + 1, opcnt, &po->operand[0],
4192 i + opcnt * 11, &ref_i);
4194 // then also don't need the source mov
4195 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4207 pp = calloc(1, sizeof(*pp));
4208 my_assert_not(pp, NULL);
4211 ret = scan_for_esp_adjust(i + 1, opcnt,
4212 -1, &adj, &multipath, 0);
4213 if (ret < 0 || adj < 0) {
4214 if (!g_allow_regfunc)
4215 ferr(po, "non-__cdecl indirect call unhandled yet\n");
4216 pp->is_unresolved = 1;
4220 if (adj > ARRAY_SIZE(pp->arg))
4221 ferr(po, "esp adjust too large: %d\n", adj);
4222 pp->ret_type.name = strdup("int");
4223 pp->argc = pp->argc_stack = adj;
4224 for (arg = 0; arg < pp->argc; arg++)
4225 pp->arg[arg].type.name = strdup("int");
4230 // look for and make use of esp adjust
4233 if (!pp->is_stdcall && pp->argc_stack > 0) {
4234 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
4235 ret = scan_for_esp_adjust(i + 1, opcnt,
4236 adj_expect, &adj, &multipath, 0);
4239 if (pp->is_vararg) {
4240 if (adj / 4 < pp->argc_stack) {
4241 fnote(po, "(this call)\n");
4242 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
4243 adj, pp->argc_stack * 4);
4245 // modify pp to make it have varargs as normal args
4247 pp->argc += adj / 4 - pp->argc_stack;
4248 for (; arg < pp->argc; arg++) {
4249 pp->arg[arg].type.name = strdup("int");
4252 if (pp->argc > ARRAY_SIZE(pp->arg))
4253 ferr(po, "too many args for '%s'\n", tmpname);
4255 if (pp->argc_stack > adj / 4) {
4256 fnote(po, "(this call)\n");
4257 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
4258 tmpname, pp->argc_stack * 4, adj);
4261 scan_for_esp_adjust(i + 1, opcnt,
4262 pp->argc_stack * 4, &adj, &multipath, 1);
4264 else if (pp->is_vararg)
4265 ferr(po, "missing esp_adjust for vararg func '%s'\n",
4271 static int collect_call_args_early(struct parsed_op *po, int i,
4272 struct parsed_proto *pp, int *regmask)
4277 for (arg = 0; arg < pp->argc; arg++)
4278 if (pp->arg[arg].reg == NULL)
4281 // first see if it can be easily done
4282 for (j = i; j > 0 && arg < pp->argc; )
4284 if (g_labels[j] != NULL)
4288 if (ops[j].op == OP_CALL)
4290 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP)
4292 else if (ops[j].op == OP_POP)
4294 else if (ops[j].flags & OPF_CJMP)
4296 else if (ops[j].op == OP_PUSH) {
4297 if (ops[j].flags & (OPF_FARG|OPF_FARGNR))
4299 ret = scan_for_mod(&ops[j], j + 1, i, 1);
4303 if (pp->arg[arg].type.is_va_list)
4307 for (arg++; arg < pp->argc; arg++)
4308 if (pp->arg[arg].reg == NULL)
4317 for (arg = 0; arg < pp->argc; arg++)
4318 if (pp->arg[arg].reg == NULL)
4321 for (j = i; j > 0 && arg < pp->argc; )
4325 if (ops[j].op == OP_PUSH)
4327 ops[j].p_argnext = -1;
4328 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
4329 pp->arg[arg].datap = &ops[j];
4331 if (ops[j].operand[0].type == OPT_REG)
4332 *regmask |= 1 << ops[j].operand[0].reg;
4334 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4335 ops[j].flags &= ~OPF_RSAVE;
4338 for (arg++; arg < pp->argc; arg++)
4339 if (pp->arg[arg].reg == NULL)
4347 static int collect_call_args_r(struct parsed_op *po, int i,
4348 struct parsed_proto *pp, int *regmask, int *save_arg_vars,
4349 int *arg_grp, int arg, int magic, int need_op_saving, int may_reuse)
4351 struct parsed_proto *pp_tmp;
4352 struct parsed_op *po_tmp;
4353 struct label_ref *lr;
4354 int need_to_save_current;
4355 int arg_grp_current = 0;
4356 int save_args_seen = 0;
4364 ferr(po, "dead label encountered\n");
4368 for (; arg < pp->argc; arg++)
4369 if (pp->arg[arg].reg == NULL)
4371 magic = (magic & 0xffffff) | (arg << 24);
4373 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
4375 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
4376 if (ops[j].cc_scratch != magic) {
4377 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
4381 // ok: have already been here
4384 ops[j].cc_scratch = magic;
4386 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
4387 lr = &g_label_refs[j];
4388 if (lr->next != NULL)
4390 for (; lr->next; lr = lr->next) {
4391 check_i(&ops[j], lr->i);
4392 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4394 ret = collect_call_args_r(po, lr->i, pp, regmask, save_arg_vars,
4395 arg_grp, arg, magic, need_op_saving, may_reuse);
4400 check_i(&ops[j], lr->i);
4401 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4403 if (j > 0 && LAST_OP(j - 1)) {
4404 // follow last branch in reverse
4409 ret = collect_call_args_r(po, lr->i, pp, regmask, save_arg_vars,
4410 arg_grp, arg, magic, need_op_saving, may_reuse);
4416 if (ops[j].op == OP_CALL)
4418 if (pp->is_unresolved)
4423 ferr(po, "arg collect hit unparsed call '%s'\n",
4424 ops[j].operand[0].name);
4425 if (may_reuse && pp_tmp->argc_stack > 0)
4426 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
4427 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
4429 // esp adjust of 0 means we collected it before
4430 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
4431 && (ops[j].operand[1].type != OPT_CONST
4432 || ops[j].operand[1].val != 0))
4434 if (pp->is_unresolved)
4437 fnote(po, "(this call)\n");
4438 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
4439 arg, pp->argc, ops[j].operand[1].val);
4441 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
4443 if (pp->is_unresolved)
4446 fnote(po, "(this call)\n");
4447 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
4449 else if (ops[j].flags & OPF_CJMP)
4451 if (pp->is_unresolved)
4456 else if (ops[j].op == OP_PUSH
4457 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
4459 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
4462 ops[j].p_argnext = -1;
4463 po_tmp = pp->arg[arg].datap;
4465 ops[j].p_argnext = po_tmp - ops;
4466 pp->arg[arg].datap = &ops[j];
4468 need_to_save_current = 0;
4471 if (ops[j].operand[0].type == OPT_REG)
4472 reg = ops[j].operand[0].reg;
4474 if (!need_op_saving) {
4475 ret = scan_for_mod(&ops[j], j + 1, i, 1);
4476 need_to_save_current = (ret >= 0);
4478 if (need_op_saving || need_to_save_current) {
4479 // mark this push as one that needs operand saving
4480 ops[j].flags &= ~OPF_RMD;
4481 if (ops[j].p_argnum == 0) {
4482 ops[j].p_argnum = arg + 1;
4483 save_args |= 1 << arg;
4485 else if (ops[j].p_argnum < arg + 1) {
4486 // XXX: might kill valid var..
4487 //*save_arg_vars &= ~(1 << (ops[j].p_argnum - 1));
4488 ops[j].p_argnum = arg + 1;
4489 save_args |= 1 << arg;
4492 if (save_args_seen & (1 << (ops[j].p_argnum - 1))) {
4495 if (arg_grp_current >= MAX_ARG_GRP)
4496 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
4497 ops[j].p_argnum, pp->name);
4500 else if (ops[j].p_argnum == 0)
4501 ops[j].flags |= OPF_RMD;
4503 // some PUSHes are reused by different calls on other branches,
4504 // but that can't happen if we didn't branch, so they
4505 // can be removed from future searches (handles nested calls)
4507 ops[j].flags |= OPF_FARGNR;
4509 ops[j].flags |= OPF_FARG;
4510 ops[j].flags &= ~OPF_RSAVE;
4512 // check for __VALIST
4513 if (!pp->is_unresolved && g_func_pp != NULL
4514 && pp->arg[arg].type.is_va_list)
4517 ret = resolve_origin(j, &ops[j].operand[0],
4518 magic + 1, &k, NULL);
4519 if (ret == 1 && k >= 0)
4521 if (ops[k].op == OP_LEA) {
4522 if (!g_func_pp->is_vararg)
4523 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
4526 snprintf(buf, sizeof(buf), "arg_%X",
4527 g_func_pp->argc_stack * 4);
4528 if (strstr(ops[k].operand[1].name, buf)
4529 || strstr(ops[k].operand[1].name, "arglist"))
4531 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
4532 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
4533 save_args &= ~(1 << arg);
4537 ferr(&ops[k], "va_list arg detection failed\n");
4539 // check for va_list from g_func_pp arg too
4540 else if (ops[k].op == OP_MOV
4541 && is_stack_access(&ops[k], &ops[k].operand[1]))
4543 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
4544 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
4546 ops[k].flags |= OPF_RMD | OPF_DONE;
4547 ops[j].flags |= OPF_RMD;
4548 ops[j].p_argpass = ret + 1;
4549 save_args &= ~(1 << arg);
4556 *save_arg_vars |= save_args;
4558 // tracking reg usage
4560 *regmask |= 1 << reg;
4563 if (!pp->is_unresolved) {
4565 for (; arg < pp->argc; arg++)
4566 if (pp->arg[arg].reg == NULL)
4569 magic = (magic & 0xffffff) | (arg << 24);
4572 if (ops[j].p_arggrp > arg_grp_current) {
4574 arg_grp_current = ops[j].p_arggrp;
4576 if (ops[j].p_argnum > 0)
4577 save_args_seen |= 1 << (ops[j].p_argnum - 1);
4580 if (arg < pp->argc) {
4581 ferr(po, "arg collect failed for '%s': %d/%d\n",
4582 pp->name, arg, pp->argc);
4586 if (arg_grp_current > *arg_grp)
4587 *arg_grp = arg_grp_current;
4592 static int collect_call_args(struct parsed_op *po, int i,
4593 struct parsed_proto *pp, int *regmask, int *save_arg_vars,
4596 // arg group is for cases when pushes for
4597 // multiple funcs are going on
4598 struct parsed_op *po_tmp;
4599 int save_arg_vars_current = 0;
4604 ret = collect_call_args_r(po, i, pp, regmask,
4605 &save_arg_vars_current, &arg_grp, 0, magic, 0, 0);
4610 // propagate arg_grp
4611 for (a = 0; a < pp->argc; a++) {
4612 if (pp->arg[a].reg != NULL)
4615 po_tmp = pp->arg[a].datap;
4616 while (po_tmp != NULL) {
4617 po_tmp->p_arggrp = arg_grp;
4618 if (po_tmp->p_argnext > 0)
4619 po_tmp = &ops[po_tmp->p_argnext];
4625 save_arg_vars[arg_grp] |= save_arg_vars_current;
4627 if (pp->is_unresolved) {
4629 pp->argc_stack += ret;
4630 for (a = 0; a < pp->argc; a++)
4631 if (pp->arg[a].type.name == NULL)
4632 pp->arg[a].type.name = strdup("int");
4638 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
4639 int regmask_now, int *regmask,
4640 int regmask_save_now, int *regmask_save,
4641 int *regmask_init, int regmask_arg)
4643 struct parsed_op *po;
4652 for (; i < opcnt; i++)
4655 if (cbits[i >> 3] & (1 << (i & 7)))
4657 cbits[i >> 3] |= (1 << (i & 7));
4659 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4660 if (po->flags & (OPF_RMD|OPF_DONE))
4662 if (po->btj != NULL) {
4663 for (j = 0; j < po->btj->count; j++) {
4664 check_i(po, po->btj->d[j].bt_i);
4665 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
4666 regmask_now, regmask, regmask_save_now, regmask_save,
4667 regmask_init, regmask_arg);
4672 check_i(po, po->bt_i);
4673 if (po->flags & OPF_CJMP)
4674 reg_use_pass(po->bt_i, opcnt, cbits,
4675 regmask_now, regmask, regmask_save_now, regmask_save,
4676 regmask_init, regmask_arg);
4682 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
4683 && !g_func_pp->is_userstack
4684 && po->operand[0].type == OPT_REG)
4686 reg = po->operand[0].reg;
4687 ferr_assert(po, reg >= 0);
4690 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
4691 if (regmask_now & (1 << reg)) {
4692 already_saved = regmask_save_now & (1 << reg);
4693 flags_set = OPF_RSAVE | OPF_DONE;
4696 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0);
4698 scan_for_pop(i + 1, opcnt, i + opcnt * 4, reg, 0, flags_set);
4701 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
4703 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
4708 ferr_assert(po, !already_saved);
4709 po->flags |= flags_set;
4711 if (regmask_now & (1 << reg)) {
4712 regmask_save_now |= (1 << reg);
4713 *regmask_save |= regmask_save_now;
4718 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
4719 reg = po->operand[0].reg;
4720 ferr_assert(po, reg >= 0);
4722 if (regmask_save_now & (1 << reg))
4723 regmask_save_now &= ~(1 << reg);
4725 regmask_now &= ~(1 << reg);
4728 else if (po->op == OP_CALL) {
4729 if ((po->regmask_dst & (1 << xAX))
4730 && !(po->regmask_dst & (1 << xDX)))
4732 if (po->flags & OPF_TAIL)
4733 // don't need eax, will do "return f();" or "f(); return;"
4734 po->regmask_dst &= ~(1 << xAX);
4736 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
4738 find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
4741 po->regmask_dst &= ~(1 << xAX);
4746 if (po->flags & OPF_NOREGS)
4749 if (po->flags & OPF_FPUSH) {
4750 if (regmask_now & mxST1)
4751 ferr(po, "TODO: FPUSH on active ST1\n");
4752 if (regmask_now & mxST0)
4753 po->flags |= OPF_FSHIFT;
4754 mask = mxST0 | mxST1;
4755 regmask_now = (regmask_now & ~mask) | ((regmask_now & mxST0) << 1);
4758 // if incomplete register is used, clear it on init to avoid
4759 // later use of uninitialized upper part in some situations
4760 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
4761 && po->operand[0].lmod != OPLM_DWORD)
4763 reg = po->operand[0].reg;
4764 ferr_assert(po, reg >= 0);
4766 if (!(regmask_now & (1 << reg)))
4767 *regmask_init |= 1 << reg;
4770 regmask_op = po->regmask_src | po->regmask_dst;
4772 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
4773 regmask_new &= ~(1 << xSP);
4774 if (g_bp_frame && !(po->flags & OPF_EBP_S))
4775 regmask_new &= ~(1 << xBP);
4777 if (regmask_new != 0)
4778 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
4780 if (regmask_op & (1 << xBP)) {
4781 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
4782 if (po->regmask_dst & (1 << xBP))
4783 // compiler decided to drop bp frame and use ebp as scratch
4784 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
4786 regmask_op &= ~(1 << xBP);
4790 regmask_now |= regmask_op;
4791 *regmask |= regmask_now;
4794 if (po->flags & OPF_FPOP) {
4795 mask = mxST0 | mxST1;
4796 if (!(regmask_now & mask))
4797 ferr(po, "float pop on empty stack?\n");
4798 if (regmask_now & mxST1)
4799 po->flags |= OPF_FSHIFT;
4800 regmask_now = (regmask_now & ~mask) | ((regmask_now & mxST1) >> 1);
4803 if (po->flags & OPF_TAIL) {
4804 if (regmask_now & (mxST0 | mxST1))
4805 ferr(po, "float regs on tail: %x\n", regmask_now);
4807 // there is support for "conditional tailcall", sort of
4808 if (!(po->flags & OPF_CC))
4814 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
4818 for (i = 0; i < pp->argc; i++)
4819 if (pp->arg[i].reg == NULL)
4823 memmove(&pp->arg[i + 1], &pp->arg[i],
4824 sizeof(pp->arg[0]) * pp->argc_stack);
4825 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
4826 pp->arg[i].reg = strdup(reg);
4827 pp->arg[i].type.name = strdup("int");
4832 static void output_std_flags(FILE *fout, struct parsed_op *po,
4833 int *pfomask, const char *dst_opr_text)
4835 if (*pfomask & (1 << PFO_Z)) {
4836 fprintf(fout, "\n cond_z = (%s%s == 0);",
4837 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
4838 *pfomask &= ~(1 << PFO_Z);
4840 if (*pfomask & (1 << PFO_S)) {
4841 fprintf(fout, "\n cond_s = (%s%s < 0);",
4842 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
4843 *pfomask &= ~(1 << PFO_S);
4848 OPP_FORCE_NORETURN = (1 << 0),
4849 OPP_SIMPLE_ARGS = (1 << 1),
4850 OPP_ALIGN = (1 << 2),
4853 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
4856 const char *cconv = "";
4858 if (pp->is_fastcall)
4859 cconv = "__fastcall ";
4860 else if (pp->is_stdcall && pp->argc_reg == 0)
4861 cconv = "__stdcall ";
4863 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
4865 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
4866 fprintf(fout, "noreturn ");
4869 static void output_pp(FILE *fout, const struct parsed_proto *pp,
4874 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
4878 output_pp_attrs(fout, pp, flags);
4881 fprintf(fout, "%s", pp->name);
4886 for (i = 0; i < pp->argc; i++) {
4888 fprintf(fout, ", ");
4889 if (pp->arg[i].fptr != NULL && !(flags & OPP_SIMPLE_ARGS)) {
4891 output_pp(fout, pp->arg[i].fptr, 0);
4893 else if (pp->arg[i].type.is_retreg) {
4894 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
4897 fprintf(fout, "%s", pp->arg[i].type.name);
4899 fprintf(fout, " a%d", i + 1);
4902 if (pp->is_vararg) {
4904 fprintf(fout, ", ");
4905 fprintf(fout, "...");
4910 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
4916 snprintf(buf1, sizeof(buf1), "%d", grp);
4917 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
4922 static void gen_x_cleanup(int opcnt);
4924 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
4926 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
4927 struct parsed_opr *last_arith_dst = NULL;
4928 char buf1[256], buf2[256], buf3[256], cast[64];
4929 struct parsed_proto *pp, *pp_tmp;
4930 struct parsed_data *pd;
4932 int save_arg_vars[MAX_ARG_GRP] = { 0, };
4933 unsigned char cbits[MAX_OPS / 8];
4935 int need_tmp_var = 0;
4938 int label_pending = 0;
4939 int regmask_save = 0; // regs saved/restored in this func
4940 int regmask_arg; // regs from this function args (fastcall, etc)
4941 int regmask_ret; // regs needed on ret
4942 int regmask_now; // temp
4943 int regmask_init = 0; // regs that need zero initialization
4944 int regmask_pp = 0; // regs used in complex push-pop graph
4945 int regmask = 0; // used regs
4954 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
4955 g_stack_frame_used = 0;
4956 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
4957 regmask_init = g_regmask_init;
4959 g_func_pp = proto_parse(fhdr, funcn, 0);
4960 if (g_func_pp == NULL)
4961 ferr(ops, "proto_parse failed for '%s'\n", funcn);
4963 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
4964 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
4967 // - resolve all branches
4968 // - parse calls with labels
4969 resolve_branches_parse_calls(opcnt);
4972 // - handle ebp/esp frame, remove ops related to it
4973 scan_prologue_epilogue(opcnt);
4976 // - remove dead labels
4977 // - set regs needed at ret
4978 for (i = 0; i < opcnt; i++)
4980 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
4985 if (ops[i].op == OP_RET)
4986 ops[i].regmask_src |= regmask_ret;
4990 // - process trivial calls
4991 for (i = 0; i < opcnt; i++)
4994 if (po->flags & (OPF_RMD|OPF_DONE))
4997 if (po->op == OP_CALL)
4999 pp = process_call_early(i, opcnt, &j);
5001 if (!(po->flags & OPF_ATAIL))
5002 // since we know the args, try to collect them
5003 if (collect_call_args_early(po, i, pp, ®mask) != 0)
5009 // commit esp adjust
5010 if (ops[j].op != OP_POP)
5011 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5013 for (l = 0; l < pp->argc_stack; l++)
5014 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
5018 if (strstr(pp->ret_type.name, "int64"))
5021 po->flags |= OPF_DONE;
5027 // - process calls, stage 2
5028 // - handle some push/pop pairs
5029 // - scan for STD/CLD, propagate DF
5030 for (i = 0; i < opcnt; i++)
5033 if (po->flags & OPF_RMD)
5036 if (po->op == OP_CALL)
5038 if (!(po->flags & OPF_DONE)) {
5039 pp = process_call(i, opcnt);
5041 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
5042 // since we know the args, collect them
5043 collect_call_args(po, i, pp, ®mask, save_arg_vars,
5046 // for unresolved, collect after other passes
5050 ferr_assert(po, pp != NULL);
5052 po->regmask_src |= get_pp_arg_regmask_src(pp);
5053 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
5055 if (po->regmask_dst & mxST0)
5056 po->flags |= OPF_FPUSH;
5058 if (strstr(pp->ret_type.name, "int64"))
5064 if (po->flags & OPF_DONE)
5067 if (po->op == OP_PUSH && !(po->flags & OPF_FARG)
5068 && !(po->flags & OPF_RSAVE) && po->operand[0].type == OPT_CONST)
5070 scan_for_pop_const(i, opcnt, i + opcnt * 12);
5072 else if (po->op == OP_POP)
5073 scan_pushes_for_pop(i, opcnt, ®mask_pp);
5074 else if (po->op == OP_STD) {
5075 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
5076 scan_propagate_df(i + 1, opcnt);
5081 // - find POPs for PUSHes, rm both
5082 // - scan for all used registers
5083 memset(cbits, 0, sizeof(cbits));
5084 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
5085 0, ®mask_save, ®mask_init, regmask_arg);
5088 // - find flag set ops for their users
5089 // - do unresolved calls
5090 // - declare indirect functions
5091 for (i = 0; i < opcnt; i++)
5094 if (po->flags & (OPF_RMD|OPF_DONE))
5097 if (po->flags & OPF_CC)
5099 int setters[16], cnt = 0, branched = 0;
5101 ret = scan_for_flag_set(i, i + opcnt * 6,
5102 &branched, setters, &cnt);
5103 if (ret < 0 || cnt <= 0)
5104 ferr(po, "unable to trace flag setter(s)\n");
5105 if (cnt > ARRAY_SIZE(setters))
5106 ferr(po, "too many flag setters\n");
5108 for (j = 0; j < cnt; j++)
5110 tmp_op = &ops[setters[j]]; // flag setter
5113 // to get nicer code, we try to delay test and cmp;
5114 // if we can't because of operand modification, or if we
5115 // have arith op, or branch, make it calculate flags explicitly
5116 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
5118 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
5119 pfomask = 1 << po->pfo;
5121 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
5122 pfomask = 1 << po->pfo;
5125 // see if we'll be able to handle based on op result
5126 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
5127 && po->pfo != PFO_Z && po->pfo != PFO_S
5128 && po->pfo != PFO_P)
5130 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
5132 pfomask = 1 << po->pfo;
5135 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
5136 propagate_lmod(tmp_op, &tmp_op->operand[0],
5137 &tmp_op->operand[1]);
5138 if (tmp_op->operand[0].lmod == OPLM_DWORD)
5143 tmp_op->pfomask |= pfomask;
5144 cond_vars |= pfomask;
5146 // note: may overwrite, currently not a problem
5150 if (po->op == OP_RCL || po->op == OP_RCR
5151 || po->op == OP_ADC || po->op == OP_SBB)
5152 cond_vars |= 1 << PFO_C;
5155 if (po->op == OP_CMPS || po->op == OP_SCAS) {
5156 cond_vars |= 1 << PFO_Z;
5158 else if (po->op == OP_MUL
5159 || (po->op == OP_IMUL && po->operand_cnt == 1))
5161 if (po->operand[0].lmod == OPLM_DWORD)
5164 else if (po->op == OP_CALL) {
5165 // note: resolved non-reg calls are OPF_DONE already
5167 ferr_assert(po, pp != NULL);
5169 if (pp->is_unresolved) {
5170 int regmask_stack = 0;
5171 collect_call_args(po, i, pp, ®mask, save_arg_vars,
5174 // this is pretty rough guess:
5175 // see ecx and edx were pushed (and not their saved versions)
5176 for (arg = 0; arg < pp->argc; arg++) {
5177 if (pp->arg[arg].reg != NULL)
5180 tmp_op = pp->arg[arg].datap;
5182 ferr(po, "parsed_op missing for arg%d\n", arg);
5183 if (tmp_op->p_argnum == 0 && tmp_op->operand[0].type == OPT_REG)
5184 regmask_stack |= 1 << tmp_op->operand[0].reg;
5187 if (!((regmask_stack & (1 << xCX))
5188 && (regmask_stack & (1 << xDX))))
5190 if (pp->argc_stack != 0
5191 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
5193 pp_insert_reg_arg(pp, "ecx");
5194 pp->is_fastcall = 1;
5195 regmask_init |= 1 << xCX;
5196 regmask |= 1 << xCX;
5198 if (pp->argc_stack != 0
5199 || ((regmask | regmask_arg) & (1 << xDX)))
5201 pp_insert_reg_arg(pp, "edx");
5202 regmask_init |= 1 << xDX;
5203 regmask |= 1 << xDX;
5207 // note: __cdecl doesn't fall into is_unresolved category
5208 if (pp->argc_stack > 0)
5212 else if (po->op == OP_MOV && po->operand[0].pp != NULL
5213 && po->operand[1].pp != NULL)
5215 // <var> = offset <something>
5216 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
5217 && !IS_START(po->operand[1].name, "off_"))
5219 if (!po->operand[0].pp->is_fptr)
5220 ferr(po, "%s not declared as fptr when it should be\n",
5221 po->operand[0].name);
5222 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
5223 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
5224 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
5225 fnote(po, "var: %s\n", buf1);
5226 fnote(po, "func: %s\n", buf2);
5227 ferr(po, "^ mismatch\n");
5231 else if (po->op == OP_DIV || po->op == OP_IDIV) {
5232 if (po->operand[0].lmod == OPLM_DWORD) {
5233 // 32bit division is common, look for it
5234 if (po->op == OP_DIV)
5235 ret = scan_for_reg_clear(i, xDX);
5237 ret = scan_for_cdq_edx(i);
5239 po->flags |= OPF_32BIT;
5246 else if (po->op == OP_CLD)
5247 po->flags |= OPF_RMD | OPF_DONE;
5248 else if (po->op == OPP_FTOL) {
5249 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
5251 find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
5253 po->flags |= OPF_32BIT;
5256 if (po->op == OP_RCL || po->op == OP_RCR || po->op == OP_XCHG)
5260 // output starts here
5262 // define userstack size
5263 if (g_func_pp->is_userstack) {
5264 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
5265 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
5266 fprintf(fout, "#endif\n");
5269 // the function itself
5270 ferr_assert(ops, !g_func_pp->is_fptr);
5271 output_pp(fout, g_func_pp,
5272 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
5273 fprintf(fout, "\n{\n");
5275 // declare indirect functions
5276 for (i = 0; i < opcnt; i++) {
5278 if (po->flags & OPF_RMD)
5281 if (po->op == OP_CALL) {
5284 ferr(po, "NULL pp\n");
5286 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
5287 if (pp->name[0] != 0) {
5288 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
5289 memcpy(pp->name, "i_", 2);
5291 // might be declared already
5293 for (j = 0; j < i; j++) {
5294 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
5295 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
5305 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
5308 output_pp(fout, pp, OPP_SIMPLE_ARGS);
5309 fprintf(fout, ";\n");
5314 // output LUTs/jumptables
5315 for (i = 0; i < g_func_pd_cnt; i++) {
5317 fprintf(fout, " static const ");
5318 if (pd->type == OPT_OFFSET) {
5319 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
5321 for (j = 0; j < pd->count; j++) {
5323 fprintf(fout, ", ");
5324 fprintf(fout, "&&%s", pd->d[j].u.label);
5328 fprintf(fout, "%s %s[] =\n { ",
5329 lmod_type_u(ops, pd->lmod), pd->label);
5331 for (j = 0; j < pd->count; j++) {
5333 fprintf(fout, ", ");
5334 fprintf(fout, "%u", pd->d[j].u.val);
5337 fprintf(fout, " };\n");
5341 // declare stack frame, va_arg
5343 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
5344 if (g_func_lmods & (1 << OPLM_WORD))
5345 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
5346 if (g_func_lmods & (1 << OPLM_BYTE))
5347 fprintf(fout, " u8 b[%d];", g_stack_fsz);
5348 if (g_func_lmods & (1 << OPLM_QWORD))
5349 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
5350 fprintf(fout, " } sf;\n");
5354 if (g_func_pp->is_userstack) {
5355 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
5356 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
5360 if (g_func_pp->is_vararg) {
5361 fprintf(fout, " va_list ap;\n");
5365 // declare arg-registers
5366 for (i = 0; i < g_func_pp->argc; i++) {
5367 if (g_func_pp->arg[i].reg != NULL) {
5368 reg = char_array_i(regs_r32,
5369 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
5370 if (regmask & (1 << reg)) {
5371 if (g_func_pp->arg[i].type.is_retreg)
5372 fprintf(fout, " u32 %s = *r_%s;\n",
5373 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
5375 fprintf(fout, " u32 %s = (u32)a%d;\n",
5376 g_func_pp->arg[i].reg, i + 1);
5379 if (g_func_pp->arg[i].type.is_retreg)
5380 ferr(ops, "retreg '%s' is unused?\n",
5381 g_func_pp->arg[i].reg);
5382 fprintf(fout, " // %s = a%d; // unused\n",
5383 g_func_pp->arg[i].reg, i + 1);
5389 // declare normal registers
5390 regmask_now = regmask & ~regmask_arg;
5391 regmask_now &= ~(1 << xSP);
5392 if (regmask_now & 0x00ff) {
5393 for (reg = 0; reg < 8; reg++) {
5394 if (regmask_now & (1 << reg)) {
5395 fprintf(fout, " u32 %s", regs_r32[reg]);
5396 if (regmask_init & (1 << reg))
5397 fprintf(fout, " = 0");
5398 fprintf(fout, ";\n");
5404 if (regmask_now & 0xff00) {
5405 for (reg = 8; reg < 16; reg++) {
5406 if (regmask_now & (1 << reg)) {
5407 fprintf(fout, " mmxr %s", regs_r32[reg]);
5408 if (regmask_init & (1 << reg))
5409 fprintf(fout, " = { 0, }");
5410 fprintf(fout, ";\n");
5416 if (regmask_now & 0xff0000) {
5417 for (reg = 16; reg < 24; reg++) {
5418 if (regmask_now & (1 << reg)) {
5419 fprintf(fout, " double f_st%d", reg - 16);
5420 if (regmask_init & (1 << reg))
5421 fprintf(fout, " = 0");
5422 fprintf(fout, ";\n");
5429 for (reg = 0; reg < 8; reg++) {
5430 if (regmask_save & (1 << reg)) {
5431 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
5437 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
5438 if (save_arg_vars[i] == 0)
5440 for (reg = 0; reg < 32; reg++) {
5441 if (save_arg_vars[i] & (1 << reg)) {
5442 fprintf(fout, " u32 %s;\n",
5443 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
5449 // declare push-pop temporaries
5451 for (reg = 0; reg < 8; reg++) {
5452 if (regmask_pp & (1 << reg)) {
5453 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
5460 for (i = 0; i < 8; i++) {
5461 if (cond_vars & (1 << i)) {
5462 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
5469 fprintf(fout, " u32 tmp;\n");
5474 fprintf(fout, " u64 tmp64;\n");
5479 fprintf(fout, "\n");
5481 // do stack clear, if needed
5482 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
5484 if (g_stack_clear_len != 0) {
5485 if (g_stack_clear_len <= 4) {
5486 for (i = 0; i < g_stack_clear_len; i++)
5487 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
5488 fprintf(fout, "0;\n");
5491 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
5492 g_stack_clear_start, g_stack_clear_len * 4);
5496 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
5499 if (g_func_pp->is_vararg) {
5500 if (g_func_pp->argc_stack == 0)
5501 ferr(ops, "vararg func without stack args?\n");
5502 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
5506 for (i = 0; i < opcnt; i++)
5508 if (g_labels[i] != NULL) {
5509 fprintf(fout, "\n%s:\n", g_labels[i]);
5512 delayed_flag_op = NULL;
5513 last_arith_dst = NULL;
5517 if (po->flags & OPF_RMD)
5522 #define assert_operand_cnt(n_) \
5523 if (po->operand_cnt != n_) \
5524 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
5526 // conditional/flag using op?
5527 if (po->flags & OPF_CC)
5533 // we go through all this trouble to avoid using parsed_flag_op,
5534 // which makes generated code much nicer
5535 if (delayed_flag_op != NULL)
5537 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
5538 po->pfo, po->pfo_inv);
5541 else if (last_arith_dst != NULL
5542 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
5543 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
5546 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
5547 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
5548 last_arith_dst->lmod, buf3);
5551 else if (tmp_op != NULL) {
5552 // use preprocessed flag calc results
5553 if (!(tmp_op->pfomask & (1 << po->pfo)))
5554 ferr(po, "not prepared for pfo %d\n", po->pfo);
5556 // note: pfo_inv was not yet applied
5557 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
5558 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
5561 ferr(po, "all methods of finding comparison failed\n");
5564 if (po->flags & OPF_JMP) {
5565 fprintf(fout, " if %s", buf1);
5567 else if (po->op == OP_RCL || po->op == OP_RCR
5568 || po->op == OP_ADC || po->op == OP_SBB)
5571 fprintf(fout, " cond_%s = %s;\n",
5572 parsed_flag_op_names[po->pfo], buf1);
5574 else if (po->flags & OPF_DATA) { // SETcc
5575 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
5576 fprintf(fout, " %s = %s;", buf2, buf1);
5579 ferr(po, "unhandled conditional op\n");
5583 pfomask = po->pfomask;
5585 if (po->flags & (OPF_REPZ|OPF_REPNZ)) {
5586 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
5587 ret = try_resolve_const(i, &opr, opcnt * 7 + i, &uval);
5589 if (ret != 1 || uval == 0) {
5590 // we need initial flags for ecx=0 case..
5591 if (i > 0 && ops[i - 1].op == OP_XOR
5592 && IS(ops[i - 1].operand[0].name,
5593 ops[i - 1].operand[1].name))
5595 fprintf(fout, " cond_z = ");
5596 if (pfomask & (1 << PFO_C))
5597 fprintf(fout, "cond_c = ");
5598 fprintf(fout, "0;\n");
5600 else if (last_arith_dst != NULL) {
5601 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
5602 out_test_for_cc(buf1, sizeof(buf1), po, PFO_Z, 0,
5603 last_arith_dst->lmod, buf3);
5604 fprintf(fout, " cond_z = %s;\n", buf1);
5607 ferr(po, "missing initial ZF\n");
5614 assert_operand_cnt(2);
5615 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5616 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5617 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
5618 fprintf(fout, " %s = %s;", buf1,
5619 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5624 assert_operand_cnt(2);
5625 po->operand[1].lmod = OPLM_DWORD; // always
5626 fprintf(fout, " %s = %s;",
5627 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5628 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5633 assert_operand_cnt(2);
5634 fprintf(fout, " %s = %s;",
5635 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5636 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5640 assert_operand_cnt(2);
5641 switch (po->operand[1].lmod) {
5643 strcpy(buf3, "(s8)");
5646 strcpy(buf3, "(s16)");
5649 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
5651 fprintf(fout, " %s = %s;",
5652 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5653 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5658 assert_operand_cnt(2);
5659 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5660 fprintf(fout, " tmp = %s;",
5661 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
5662 fprintf(fout, " %s = %s;",
5663 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5664 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5665 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
5666 fprintf(fout, " %s = %stmp;",
5667 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
5668 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
5669 snprintf(g_comment, sizeof(g_comment), "xchg");
5673 assert_operand_cnt(1);
5674 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5675 fprintf(fout, " %s = ~%s;", buf1, buf1);
5679 assert_operand_cnt(2);
5680 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5681 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
5682 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
5683 strcpy(g_comment, "xlat");
5687 assert_operand_cnt(2);
5688 fprintf(fout, " %s = (s32)%s >> 31;",
5689 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5690 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5691 strcpy(g_comment, "cdq");
5695 if (po->flags & OPF_REP) {
5696 assert_operand_cnt(3);
5701 assert_operand_cnt(2);
5702 fprintf(fout, " %s = %sesi; esi %c= %d;",
5703 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
5704 lmod_cast_u_ptr(po, po->operand[1].lmod),
5705 (po->flags & OPF_DF) ? '-' : '+',
5706 lmod_bytes(po, po->operand[1].lmod));
5707 strcpy(g_comment, "lods");
5712 if (po->flags & OPF_REP) {
5713 assert_operand_cnt(3);
5714 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
5715 (po->flags & OPF_DF) ? '-' : '+',
5716 lmod_bytes(po, po->operand[1].lmod));
5717 fprintf(fout, " %sedi = eax;",
5718 lmod_cast_u_ptr(po, po->operand[1].lmod));
5719 strcpy(g_comment, "rep stos");
5722 assert_operand_cnt(2);
5723 fprintf(fout, " %sedi = eax; edi %c= %d;",
5724 lmod_cast_u_ptr(po, po->operand[1].lmod),
5725 (po->flags & OPF_DF) ? '-' : '+',
5726 lmod_bytes(po, po->operand[1].lmod));
5727 strcpy(g_comment, "stos");
5732 j = lmod_bytes(po, po->operand[0].lmod);
5733 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
5734 l = (po->flags & OPF_DF) ? '-' : '+';
5735 if (po->flags & OPF_REP) {
5736 assert_operand_cnt(3);
5738 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
5741 " %sedi = %sesi;", buf1, buf1);
5742 strcpy(g_comment, "rep movs");
5745 assert_operand_cnt(2);
5746 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
5747 buf1, buf1, l, j, l, j);
5748 strcpy(g_comment, "movs");
5753 // repe ~ repeat while ZF=1
5754 j = lmod_bytes(po, po->operand[0].lmod);
5755 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
5756 l = (po->flags & OPF_DF) ? '-' : '+';
5757 if (po->flags & OPF_REP) {
5758 assert_operand_cnt(3);
5760 " for (; ecx != 0; ecx--) {\n");
5761 if (pfomask & (1 << PFO_C)) {
5764 " cond_c = %sesi < %sedi;\n", buf1, buf1);
5765 pfomask &= ~(1 << PFO_C);
5768 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
5769 buf1, buf1, l, j, l, j);
5771 " if (cond_z %s 0) break;\n",
5772 (po->flags & OPF_REPZ) ? "==" : "!=");
5775 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
5776 (po->flags & OPF_REPZ) ? "e" : "ne");
5779 assert_operand_cnt(2);
5781 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
5782 buf1, buf1, l, j, l, j);
5783 strcpy(g_comment, "cmps");
5785 pfomask &= ~(1 << PFO_Z);
5786 last_arith_dst = NULL;
5787 delayed_flag_op = NULL;
5791 // only does ZF (for now)
5792 // repe ~ repeat while ZF=1
5793 j = lmod_bytes(po, po->operand[1].lmod);
5794 l = (po->flags & OPF_DF) ? '-' : '+';
5795 if (po->flags & OPF_REP) {
5796 assert_operand_cnt(3);
5798 " for (; ecx != 0; ecx--) {\n");
5800 " cond_z = (%seax == %sedi); edi %c= %d;\n",
5801 lmod_cast_u(po, po->operand[1].lmod),
5802 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
5804 " if (cond_z %s 0) break;\n",
5805 (po->flags & OPF_REPZ) ? "==" : "!=");
5808 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
5809 (po->flags & OPF_REPZ) ? "e" : "ne");
5812 assert_operand_cnt(2);
5813 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
5814 lmod_cast_u(po, po->operand[1].lmod),
5815 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
5816 strcpy(g_comment, "scas");
5818 pfomask &= ~(1 << PFO_Z);
5819 last_arith_dst = NULL;
5820 delayed_flag_op = NULL;
5823 // arithmetic w/flags
5825 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
5826 goto dualop_arith_const;
5827 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5831 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5832 if (po->operand[1].type == OPT_CONST) {
5833 j = lmod_bytes(po, po->operand[0].lmod);
5834 if (((1ull << j * 8) - 1) == po->operand[1].val)
5835 goto dualop_arith_const;
5840 assert_operand_cnt(2);
5841 fprintf(fout, " %s %s= %s;",
5842 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5844 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5845 output_std_flags(fout, po, &pfomask, buf1);
5846 last_arith_dst = &po->operand[0];
5847 delayed_flag_op = NULL;
5851 // and 0, or ~0 used instead mov
5852 assert_operand_cnt(2);
5853 fprintf(fout, " %s = %s;",
5854 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5855 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5856 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
5857 output_std_flags(fout, po, &pfomask, buf1);
5858 last_arith_dst = &po->operand[0];
5859 delayed_flag_op = NULL;
5864 assert_operand_cnt(2);
5865 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5866 if (pfomask & (1 << PFO_C)) {
5867 if (po->operand[1].type == OPT_CONST) {
5868 l = lmod_bytes(po, po->operand[0].lmod) * 8;
5869 j = po->operand[1].val;
5872 if (po->op == OP_SHL)
5876 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
5880 ferr(po, "zero shift?\n");
5884 pfomask &= ~(1 << PFO_C);
5886 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
5887 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5888 if (po->operand[1].type != OPT_CONST)
5889 fprintf(fout, " & 0x1f");
5891 output_std_flags(fout, po, &pfomask, buf1);
5892 last_arith_dst = &po->operand[0];
5893 delayed_flag_op = NULL;
5897 assert_operand_cnt(2);
5898 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5899 fprintf(fout, " %s = %s%s >> %s;", buf1,
5900 lmod_cast_s(po, po->operand[0].lmod), buf1,
5901 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5902 output_std_flags(fout, po, &pfomask, buf1);
5903 last_arith_dst = &po->operand[0];
5904 delayed_flag_op = NULL;
5909 assert_operand_cnt(3);
5910 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5911 l = lmod_bytes(po, po->operand[0].lmod) * 8;
5912 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
5913 if (po->operand[2].type != OPT_CONST) {
5914 // no handling for "undefined" case, hopefully not needed
5915 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
5918 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
5919 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5920 if (po->op == OP_SHLD) {
5921 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
5922 buf1, buf3, buf1, buf2, l, buf3);
5923 strcpy(g_comment, "shld");
5926 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
5927 buf1, buf3, buf1, buf2, l, buf3);
5928 strcpy(g_comment, "shrd");
5930 output_std_flags(fout, po, &pfomask, buf1);
5931 last_arith_dst = &po->operand[0];
5932 delayed_flag_op = NULL;
5937 assert_operand_cnt(2);
5938 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5939 if (po->operand[1].type == OPT_CONST) {
5940 j = po->operand[1].val;
5941 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
5942 fprintf(fout, po->op == OP_ROL ?
5943 " %s = (%s << %d) | (%s >> %d);" :
5944 " %s = (%s >> %d) | (%s << %d);",
5945 buf1, buf1, j, buf1,
5946 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
5950 output_std_flags(fout, po, &pfomask, buf1);
5951 last_arith_dst = &po->operand[0];
5952 delayed_flag_op = NULL;
5957 assert_operand_cnt(2);
5958 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5959 l = lmod_bytes(po, po->operand[0].lmod) * 8;
5960 if (po->operand[1].type == OPT_CONST) {
5961 j = po->operand[1].val % l;
5963 ferr(po, "zero rotate\n");
5964 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
5965 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
5966 if (po->op == OP_RCL) {
5968 " %s = (%s << %d) | (cond_c << %d)",
5969 buf1, buf1, j, j - 1);
5971 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
5975 " %s = (%s >> %d) | (cond_c << %d)",
5976 buf1, buf1, j, l - j);
5978 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
5980 fprintf(fout, ";\n");
5981 fprintf(fout, " cond_c = tmp;");
5985 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
5986 output_std_flags(fout, po, &pfomask, buf1);
5987 last_arith_dst = &po->operand[0];
5988 delayed_flag_op = NULL;
5992 assert_operand_cnt(2);
5993 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5994 if (IS(opr_name(po, 0), opr_name(po, 1))) {
5995 // special case for XOR
5996 if (pfomask & (1 << PFO_BE)) { // weird, but it happens..
5997 fprintf(fout, " cond_be = 1;\n");
5998 pfomask &= ~(1 << PFO_BE);
6000 fprintf(fout, " %s = 0;",
6001 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6002 last_arith_dst = &po->operand[0];
6003 delayed_flag_op = NULL;
6009 assert_operand_cnt(2);
6010 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6011 if (pfomask & (1 << PFO_C)) {
6012 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6013 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6014 if (po->operand[0].lmod == OPLM_DWORD) {
6015 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
6016 fprintf(fout, " cond_c = tmp64 >> 32;\n");
6017 fprintf(fout, " %s = (u32)tmp64;",
6018 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6019 strcat(g_comment, " add64");
6022 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
6023 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
6024 fprintf(fout, " %s += %s;",
6025 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6028 pfomask &= ~(1 << PFO_C);
6029 output_std_flags(fout, po, &pfomask, buf1);
6030 last_arith_dst = &po->operand[0];
6031 delayed_flag_op = NULL;
6037 assert_operand_cnt(2);
6038 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6039 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
6040 for (j = 0; j <= PFO_LE; j++) {
6041 if (!(pfomask & (1 << j)))
6043 if (j == PFO_Z || j == PFO_S)
6046 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0);
6047 fprintf(fout, " cond_%s = %s;\n",
6048 parsed_flag_op_names[j], buf1);
6049 pfomask &= ~(1 << j);
6056 assert_operand_cnt(2);
6057 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6058 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6059 if (po->op == OP_SBB
6060 && IS(po->operand[0].name, po->operand[1].name))
6062 // avoid use of unitialized var
6063 fprintf(fout, " %s = -cond_c;", buf1);
6064 // carry remains what it was
6065 pfomask &= ~(1 << PFO_C);
6068 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
6069 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6071 output_std_flags(fout, po, &pfomask, buf1);
6072 last_arith_dst = &po->operand[0];
6073 delayed_flag_op = NULL;
6077 assert_operand_cnt(2);
6078 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6079 fprintf(fout, " %s = %s ? __builtin_ffs(%s) - 1 : 0;",
6080 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6082 output_std_flags(fout, po, &pfomask, buf1);
6083 last_arith_dst = &po->operand[0];
6084 delayed_flag_op = NULL;
6085 strcat(g_comment, " bsf");
6089 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
6090 for (j = 0; j <= PFO_LE; j++) {
6091 if (!(pfomask & (1 << j)))
6093 if (j == PFO_Z || j == PFO_S || j == PFO_C)
6096 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0);
6097 fprintf(fout, " cond_%s = %s;\n",
6098 parsed_flag_op_names[j], buf1);
6099 pfomask &= ~(1 << j);
6105 if (pfomask & (1 << PFO_C))
6106 // carry is unaffected by inc/dec.. wtf?
6107 ferr(po, "carry propagation needed\n");
6109 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6110 if (po->operand[0].type == OPT_REG) {
6111 strcpy(buf2, po->op == OP_INC ? "++" : "--");
6112 fprintf(fout, " %s%s;", buf1, buf2);
6115 strcpy(buf2, po->op == OP_INC ? "+" : "-");
6116 fprintf(fout, " %s %s= 1;", buf1, buf2);
6118 output_std_flags(fout, po, &pfomask, buf1);
6119 last_arith_dst = &po->operand[0];
6120 delayed_flag_op = NULL;
6124 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6125 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
6126 fprintf(fout, " %s = -%s%s;", buf1,
6127 lmod_cast_s(po, po->operand[0].lmod), buf2);
6128 last_arith_dst = &po->operand[0];
6129 delayed_flag_op = NULL;
6130 if (pfomask & (1 << PFO_C)) {
6131 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
6132 pfomask &= ~(1 << PFO_C);
6137 if (po->operand_cnt == 2) {
6138 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6141 if (po->operand_cnt == 3)
6142 ferr(po, "TODO imul3\n");
6145 assert_operand_cnt(1);
6146 switch (po->operand[0].lmod) {
6148 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
6149 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
6150 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
6151 fprintf(fout, " edx = tmp64 >> 32;\n");
6152 fprintf(fout, " eax = tmp64;");
6155 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
6156 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
6157 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
6161 ferr(po, "TODO: unhandled mul type\n");
6164 last_arith_dst = NULL;
6165 delayed_flag_op = NULL;
6170 assert_operand_cnt(1);
6171 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6172 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
6173 po->op == OP_IDIV));
6174 switch (po->operand[0].lmod) {
6176 if (po->flags & OPF_32BIT)
6177 snprintf(buf2, sizeof(buf2), "%seax", cast);
6179 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
6180 snprintf(buf2, sizeof(buf2), "%stmp64",
6181 (po->op == OP_IDIV) ? "(s64)" : "");
6183 if (po->operand[0].type == OPT_REG
6184 && po->operand[0].reg == xDX)
6186 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
6187 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
6190 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
6191 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
6195 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
6196 snprintf(buf2, sizeof(buf2), "%stmp",
6197 (po->op == OP_IDIV) ? "(s32)" : "");
6198 if (po->operand[0].type == OPT_REG
6199 && po->operand[0].reg == xDX)
6201 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
6203 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
6207 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
6209 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
6212 strcat(g_comment, " div16");
6215 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
6217 last_arith_dst = NULL;
6218 delayed_flag_op = NULL;
6223 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6225 for (j = 0; j < 8; j++) {
6226 if (pfomask & (1 << j)) {
6227 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
6228 fprintf(fout, " cond_%s = %s;",
6229 parsed_flag_op_names[j], buf1);
6236 last_arith_dst = NULL;
6237 delayed_flag_op = po;
6241 // SETcc - should already be handled
6244 // note: we reuse OP_Jcc for SETcc, only flags differ
6246 fprintf(fout, "\n goto %s;", po->operand[0].name);
6250 fprintf(fout, " if (ecx == 0)\n");
6251 fprintf(fout, " goto %s;", po->operand[0].name);
6252 strcat(g_comment, " jecxz");
6256 fprintf(fout, " if (--ecx != 0)\n");
6257 fprintf(fout, " goto %s;", po->operand[0].name);
6258 strcat(g_comment, " loop");
6262 assert_operand_cnt(1);
6263 last_arith_dst = NULL;
6264 delayed_flag_op = NULL;
6266 if (po->operand[0].type == OPT_REGMEM) {
6267 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
6270 ferr(po, "parse failure for jmp '%s'\n",
6271 po->operand[0].name);
6272 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
6275 else if (po->operand[0].type != OPT_LABEL)
6276 ferr(po, "unhandled jmp type\n");
6278 fprintf(fout, " goto %s;", po->operand[0].name);
6282 assert_operand_cnt(1);
6284 my_assert_not(pp, NULL);
6287 if (po->flags & OPF_CC) {
6288 // we treat conditional branch to another func
6289 // (yes such code exists..) as conditional tailcall
6291 fprintf(fout, " {\n");
6294 if (pp->is_fptr && !pp->is_arg) {
6295 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
6296 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6298 if (pp->is_unresolved)
6299 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
6300 buf3, asmfn, po->asmln, pp->name);
6303 fprintf(fout, "%s", buf3);
6304 if (strstr(pp->ret_type.name, "int64")) {
6305 if (po->flags & OPF_TAIL)
6306 ferr(po, "int64 and tail?\n");
6307 fprintf(fout, "tmp64 = ");
6309 else if (!IS(pp->ret_type.name, "void")) {
6310 if (po->flags & OPF_TAIL) {
6311 if (regmask_ret & mxAX) {
6312 fprintf(fout, "return ");
6313 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
6314 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
6316 else if (regmask_ret & mxST0)
6317 ferr(po, "float tailcall\n");
6319 else if (po->regmask_dst & mxAX) {
6320 fprintf(fout, "eax = ");
6321 if (pp->ret_type.is_ptr)
6322 fprintf(fout, "(u32)");
6324 else if (po->regmask_dst & mxST0) {
6325 fprintf(fout, "f_st0 = ");
6329 if (pp->name[0] == 0)
6330 ferr(po, "missing pp->name\n");
6331 fprintf(fout, "%s%s(", pp->name,
6332 pp->has_structarg ? "_sa" : "");
6334 if (po->flags & OPF_ATAIL) {
6335 if (pp->argc_stack != g_func_pp->argc_stack
6336 || (pp->argc_stack > 0
6337 && pp->is_stdcall != g_func_pp->is_stdcall))
6338 ferr(po, "incompatible tailcall\n");
6339 if (g_func_pp->has_retreg)
6340 ferr(po, "TODO: retreg+tailcall\n");
6342 for (arg = j = 0; arg < pp->argc; arg++) {
6344 fprintf(fout, ", ");
6347 if (pp->arg[arg].type.is_ptr)
6348 snprintf(cast, sizeof(cast), "(%s)",
6349 pp->arg[arg].type.name);
6351 if (pp->arg[arg].reg != NULL) {
6352 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6356 for (; j < g_func_pp->argc; j++)
6357 if (g_func_pp->arg[j].reg == NULL)
6359 fprintf(fout, "%sa%d", cast, j + 1);
6364 for (arg = 0; arg < pp->argc; arg++) {
6366 fprintf(fout, ", ");
6369 if (pp->arg[arg].type.is_ptr)
6370 snprintf(cast, sizeof(cast), "(%s)",
6371 pp->arg[arg].type.name);
6373 if (pp->arg[arg].reg != NULL) {
6374 if (pp->arg[arg].type.is_retreg)
6375 fprintf(fout, "&%s", pp->arg[arg].reg);
6377 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6382 tmp_op = pp->arg[arg].datap;
6384 ferr(po, "parsed_op missing for arg%d\n", arg);
6386 if (tmp_op->flags & OPF_VAPUSH) {
6387 fprintf(fout, "ap");
6389 else if (tmp_op->p_argpass != 0) {
6390 fprintf(fout, "a%d", tmp_op->p_argpass);
6392 else if (tmp_op->p_argnum != 0) {
6393 fprintf(fout, "%s%s", cast,
6394 saved_arg_name(buf1, sizeof(buf1),
6395 tmp_op->p_arggrp, tmp_op->p_argnum));
6399 out_src_opr(buf1, sizeof(buf1),
6400 tmp_op, &tmp_op->operand[0], cast, 0));
6404 fprintf(fout, ");");
6406 if (strstr(pp->ret_type.name, "int64")) {
6407 fprintf(fout, "\n");
6408 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
6409 fprintf(fout, "%seax = tmp64;", buf3);
6412 if (pp->is_unresolved) {
6413 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
6415 strcat(g_comment, buf2);
6418 if (po->flags & OPF_TAIL) {
6420 if (i == opcnt - 1 || pp->is_noreturn)
6422 else if (IS(pp->ret_type.name, "void"))
6424 else if (!(regmask_ret & (1 << xAX)))
6426 // else already handled as 'return f()'
6429 fprintf(fout, "\n%sreturn;", buf3);
6430 strcat(g_comment, " ^ tailcall");
6433 strcat(g_comment, " tailcall");
6435 if ((regmask_ret & (1 << xAX))
6436 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
6438 ferr(po, "int func -> void func tailcall?\n");
6441 if (pp->is_noreturn)
6442 strcat(g_comment, " noreturn");
6443 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
6444 strcat(g_comment, " argframe");
6445 if (po->flags & OPF_CC)
6446 strcat(g_comment, " cond");
6448 if (po->flags & OPF_CC)
6449 fprintf(fout, "\n }");
6451 delayed_flag_op = NULL;
6452 last_arith_dst = NULL;
6456 if (g_func_pp->is_vararg)
6457 fprintf(fout, " va_end(ap);\n");
6458 if (g_func_pp->has_retreg) {
6459 for (arg = 0; arg < g_func_pp->argc; arg++)
6460 if (g_func_pp->arg[arg].type.is_retreg)
6461 fprintf(fout, " *r_%s = %s;\n",
6462 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
6465 if (!(regmask_ret & (1 << xAX))) {
6466 if (i != opcnt - 1 || label_pending)
6467 fprintf(fout, " return;");
6469 else if (g_func_pp->ret_type.is_ptr) {
6470 fprintf(fout, " return (%s)eax;",
6471 g_func_pp->ret_type.name);
6473 else if (IS(g_func_pp->ret_type.name, "__int64"))
6474 fprintf(fout, " return ((u64)edx << 32) | eax;");
6476 fprintf(fout, " return eax;");
6478 last_arith_dst = NULL;
6479 delayed_flag_op = NULL;
6483 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6484 if (po->p_argnum != 0) {
6485 // special case - saved func arg
6486 fprintf(fout, " %s = %s;",
6487 saved_arg_name(buf2, sizeof(buf2),
6488 po->p_arggrp, po->p_argnum), buf1);
6491 else if (po->flags & OPF_RSAVE) {
6492 fprintf(fout, " s_%s = %s;", buf1, buf1);
6495 else if (po->flags & OPF_PPUSH) {
6497 ferr_assert(po, tmp_op != NULL);
6498 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
6499 fprintf(fout, " pp_%s = %s;", buf2, buf1);
6502 else if (g_func_pp->is_userstack) {
6503 fprintf(fout, " *(--esp) = %s;", buf1);
6506 if (!(g_ida_func_attr & IDAFA_NORETURN))
6507 ferr(po, "stray push encountered\n");
6512 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6513 if (po->flags & OPF_RSAVE) {
6514 fprintf(fout, " %s = s_%s;", buf1, buf1);
6517 else if (po->flags & OPF_PPUSH) {
6518 // push/pop graph / non-const
6519 ferr_assert(po, po->datap == NULL);
6520 fprintf(fout, " %s = pp_%s;", buf1, buf1);
6523 else if (po->datap != NULL) {
6526 fprintf(fout, " %s = %s;", buf1,
6527 out_src_opr(buf2, sizeof(buf2),
6528 tmp_op, &tmp_op->operand[0],
6529 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6532 else if (g_func_pp->is_userstack) {
6533 fprintf(fout, " %s = *esp++;", buf1);
6537 ferr(po, "stray pop encountered\n");
6546 if (po->flags & OPF_FSHIFT)
6547 fprintf(fout, " f_st1 = f_st0;\n");
6548 if (po->operand[0].type == OPT_REG
6549 && po->operand[0].reg == xST0)
6551 strcat(g_comment, " fld st");
6554 fprintf(fout, " f_st0 = %s;",
6555 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0]));
6556 strcat(g_comment, " fld");
6560 if (po->flags & OPF_FSHIFT)
6561 fprintf(fout, " f_st1 = f_st0;\n");
6562 fprintf(fout, " f_st0 = (double)%s;",
6563 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6564 lmod_cast(po, po->operand[0].lmod, 1), 0));
6565 strcat(g_comment, " fild");
6569 if (po->flags & OPF_FSHIFT)
6570 fprintf(fout, " f_st1 = f_st0;\n");
6571 fprintf(fout, " f_st0 = ");
6572 switch (po->operand[0].val) {
6573 case X87_CONST_1: fprintf(fout, "1.0;"); break;
6574 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
6575 default: ferr(po, "TODO\n"); break;
6580 if ((po->flags & OPF_FPOP) && po->operand[0].type == OPT_REG
6581 && po->operand[0].reg == xST0)
6586 fprintf(fout, " %s = f_st0;",
6587 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0]));
6588 if (po->flags & OPF_FSHIFT)
6589 fprintf(fout, "\n f_st0 = f_st1;");
6590 strcat(g_comment, " fst");
6598 case OP_FADD: j = '+'; break;
6599 case OP_FDIV: j = '/'; break;
6600 case OP_FMUL: j = '*'; break;
6601 case OP_FSUB: j = '-'; break;
6602 default: j = 'x'; break;
6604 if (po->flags & OPF_FSHIFT) {
6605 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
6608 fprintf(fout, " %s %c= %s;",
6609 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0]),
6611 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1]));
6617 if (po->flags & OPF_FSHIFT)
6618 snprintf(buf1, sizeof(buf1), "f_st0");
6620 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0]);
6621 fprintf(fout, " %s = %s %c %s;", buf1,
6622 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1]),
6623 po->op == OP_FDIVR ? '/' : '-',
6624 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0]));
6632 case OP_FIADD: j = '+'; break;
6633 case OP_FIDIV: j = '/'; break;
6634 case OP_FIMUL: j = '*'; break;
6635 case OP_FISUB: j = '-'; break;
6636 default: j = 'x'; break;
6638 fprintf(fout, " f_st0 %c= (double)%s;", j,
6639 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6640 lmod_cast(po, po->operand[0].lmod, 1), 0));
6645 fprintf(fout, " f_st0 = %s %c f_st0;",
6646 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1]),
6647 po->op == OP_FIDIVR ? '/' : '-');
6651 ferr_assert(po, po->flags & OPF_32BIT);
6652 fprintf(fout, " eax = (s32)f_st0;");
6653 if (po->flags & OPF_FSHIFT)
6654 fprintf(fout, "\n f_st0 = f_st1;");
6655 strcat(g_comment, " ftol");
6660 strcpy(g_comment, " (emms)");
6665 ferr(po, "unhandled op type %d, flags %x\n",
6670 if (g_comment[0] != 0) {
6671 char *p = g_comment;
6672 while (my_isblank(*p))
6674 fprintf(fout, " // %s", p);
6679 fprintf(fout, "\n");
6681 // some sanity checking
6682 if (po->flags & OPF_REP) {
6683 if (po->op != OP_STOS && po->op != OP_MOVS
6684 && po->op != OP_CMPS && po->op != OP_SCAS)
6685 ferr(po, "unexpected rep\n");
6686 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
6687 && (po->op == OP_CMPS || po->op == OP_SCAS))
6688 ferr(po, "cmps/scas with plain rep\n");
6690 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
6691 && po->op != OP_CMPS && po->op != OP_SCAS)
6692 ferr(po, "unexpected repz/repnz\n");
6695 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
6697 // see is delayed flag stuff is still valid
6698 if (delayed_flag_op != NULL && delayed_flag_op != po) {
6699 if (is_any_opr_modified(delayed_flag_op, po, 0))
6700 delayed_flag_op = NULL;
6703 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
6704 if (is_opr_modified(last_arith_dst, po))
6705 last_arith_dst = NULL;
6711 if (g_stack_fsz && !g_stack_frame_used)
6712 fprintf(fout, " (void)sf;\n");
6714 fprintf(fout, "}\n\n");
6716 gen_x_cleanup(opcnt);
6719 static void gen_x_cleanup(int opcnt)
6723 for (i = 0; i < opcnt; i++) {
6724 struct label_ref *lr, *lr_del;
6726 lr = g_label_refs[i].next;
6727 while (lr != NULL) {
6732 g_label_refs[i].i = -1;
6733 g_label_refs[i].next = NULL;
6735 if (ops[i].op == OP_CALL) {
6737 proto_release(ops[i].pp);
6743 struct func_proto_dep;
6745 struct func_prototype {
6750 int has_ret:3; // -1, 0, 1: unresolved, no, yes
6751 unsigned int dep_resolved:1;
6752 unsigned int is_stdcall:1;
6753 struct func_proto_dep *dep_func;
6755 const struct parsed_proto *pp; // seed pp, if any
6758 struct func_proto_dep {
6760 struct func_prototype *proto;
6761 int regmask_live; // .. at the time of call
6762 unsigned int ret_dep:1; // return from this is caller's return
6765 static struct func_prototype *hg_fp;
6766 static int hg_fp_cnt;
6768 static struct scanned_var {
6770 enum opr_lenmod lmod;
6771 unsigned int is_seeded:1;
6772 unsigned int is_c_str:1;
6773 const struct parsed_proto *pp; // seed pp, if any
6775 static int hg_var_cnt;
6777 static char **hg_refs;
6778 static int hg_ref_cnt;
6780 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
6783 static struct func_prototype *hg_fp_add(const char *funcn)
6785 struct func_prototype *fp;
6787 if ((hg_fp_cnt & 0xff) == 0) {
6788 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
6789 my_assert_not(hg_fp, NULL);
6790 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
6793 fp = &hg_fp[hg_fp_cnt];
6794 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
6796 fp->argc_stack = -1;
6802 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
6807 for (i = 0; i < fp->dep_func_cnt; i++)
6808 if (IS(fp->dep_func[i].name, name))
6809 return &fp->dep_func[i];
6814 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
6817 if (hg_fp_find_dep(fp, name))
6820 if ((fp->dep_func_cnt & 0xff) == 0) {
6821 fp->dep_func = realloc(fp->dep_func,
6822 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
6823 my_assert_not(fp->dep_func, NULL);
6824 memset(&fp->dep_func[fp->dep_func_cnt], 0,
6825 sizeof(fp->dep_func[0]) * 0x100);
6827 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
6831 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
6833 const struct func_prototype *p1 = p1_, *p2 = p2_;
6834 return strcmp(p1->name, p2->name);
6838 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
6840 const struct func_prototype *p1 = p1_, *p2 = p2_;
6841 return p1->id - p2->id;
6845 static void hg_ref_add(const char *name)
6847 if ((hg_ref_cnt & 0xff) == 0) {
6848 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
6849 my_assert_not(hg_refs, NULL);
6850 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
6853 hg_refs[hg_ref_cnt] = strdup(name);
6854 my_assert_not(hg_refs[hg_ref_cnt], NULL);
6858 // recursive register dep pass
6859 // - track saved regs (part 2)
6860 // - try to figure out arg-regs
6861 // - calculate reg deps
6862 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
6863 struct func_prototype *fp, int regmask_save, int regmask_dst,
6864 int *regmask_dep, int *has_ret)
6866 struct func_proto_dep *dep;
6867 struct parsed_op *po;
6868 int from_caller = 0;
6873 for (; i < opcnt; i++)
6875 if (cbits[i >> 3] & (1 << (i & 7)))
6877 cbits[i >> 3] |= (1 << (i & 7));
6881 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
6882 if (po->flags & OPF_RMD)
6885 if (po->btj != NULL) {
6887 for (j = 0; j < po->btj->count; j++) {
6888 check_i(po, po->btj->d[j].bt_i);
6889 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
6890 regmask_save, regmask_dst, regmask_dep, has_ret);
6895 check_i(po, po->bt_i);
6896 if (po->flags & OPF_CJMP) {
6897 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
6898 regmask_save, regmask_dst, regmask_dep, has_ret);
6906 if (po->flags & OPF_FARG)
6907 /* (just calculate register deps) */;
6908 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
6910 reg = po->operand[0].reg;
6911 ferr_assert(po, reg >= 0);
6913 if (po->flags & OPF_RSAVE) {
6914 regmask_save |= 1 << reg;
6917 if (po->flags & OPF_DONE)
6920 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0);
6922 regmask_save |= 1 << reg;
6923 po->flags |= OPF_RMD;
6924 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, OPF_RMD);
6928 else if (po->flags & OPF_RMD)
6930 else if (po->op == OP_CALL) {
6931 po->regmask_dst |= 1 << xAX;
6933 dep = hg_fp_find_dep(fp, po->operand[0].name);
6935 dep->regmask_live = regmask_save | regmask_dst;
6937 else if (po->op == OP_RET) {
6938 if (po->operand_cnt > 0) {
6940 if (fp->argc_stack >= 0
6941 && fp->argc_stack != po->operand[0].val / 4)
6942 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
6943 fp->argc_stack = po->operand[0].val / 4;
6947 // if has_ret is 0, there is uninitialized eax path,
6948 // which means it's most likely void func
6949 if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
6950 if (po->op == OP_CALL) {
6955 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
6958 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
6961 if (ret != 1 && from_caller) {
6962 // unresolved eax - probably void func
6966 if (j >= 0 && ops[j].op == OP_CALL) {
6967 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
6978 l = regmask_save | regmask_dst;
6979 if (g_bp_frame && !(po->flags & OPF_EBP_S))
6982 l = po->regmask_src & ~l;
6985 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
6986 l, regmask_dst, regmask_save, po->flags);
6989 regmask_dst |= po->regmask_dst;
6991 if (po->flags & OPF_TAIL)
6996 static void gen_hdr(const char *funcn, int opcnt)
6998 int save_arg_vars[MAX_ARG_GRP] = { 0, };
6999 unsigned char cbits[MAX_OPS / 8];
7000 const struct parsed_proto *pp_c;
7001 struct parsed_proto *pp;
7002 struct func_prototype *fp;
7003 struct parsed_op *po;
7004 int regmask_dummy = 0;
7006 int max_bp_offset = 0;
7011 pp_c = proto_parse(g_fhdr, funcn, 1);
7013 // already in seed, will add to hg_fp later
7016 fp = hg_fp_add(funcn);
7018 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
7019 g_stack_frame_used = 0;
7022 // - resolve all branches
7023 // - parse calls with labels
7024 resolve_branches_parse_calls(opcnt);
7027 // - handle ebp/esp frame, remove ops related to it
7028 scan_prologue_epilogue(opcnt);
7031 // - remove dead labels
7033 for (i = 0; i < opcnt; i++)
7035 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7041 if (po->flags & (OPF_RMD|OPF_DONE))
7044 if (po->op == OP_CALL) {
7045 if (po->operand[0].type == OPT_LABEL)
7046 hg_fp_add_dep(fp, opr_name(po, 0));
7047 else if (po->pp != NULL)
7048 hg_fp_add_dep(fp, po->pp->name);
7053 // - remove dead labels
7054 // - handle push <const>/pop pairs
7055 for (i = 0; i < opcnt; i++)
7057 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7063 if (po->flags & (OPF_RMD|OPF_DONE))
7066 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
7067 scan_for_pop_const(i, opcnt, i + opcnt * 13);
7071 // - process trivial calls
7072 for (i = 0; i < opcnt; i++)
7075 if (po->flags & (OPF_RMD|OPF_DONE))
7078 if (po->op == OP_CALL)
7080 pp = process_call_early(i, opcnt, &j);
7082 if (!(po->flags & OPF_ATAIL))
7083 // since we know the args, try to collect them
7084 if (collect_call_args_early(po, i, pp, ®mask_dummy) != 0)
7090 // commit esp adjust
7091 if (ops[j].op != OP_POP)
7092 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
7094 for (l = 0; l < pp->argc_stack; l++)
7095 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
7099 po->flags |= OPF_DONE;
7105 // - track saved regs (simple)
7107 for (i = 0; i < opcnt; i++)
7110 if (po->flags & (OPF_RMD|OPF_DONE))
7113 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
7114 && po->operand[0].reg != xCX)
7116 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
7118 // regmask_save |= 1 << po->operand[0].reg; // do it later
7119 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
7120 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
7123 else if (po->op == OP_CALL)
7125 pp = process_call(i, opcnt);
7127 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
7128 // since we know the args, collect them
7129 ret = collect_call_args(po, i, pp, ®mask_dummy, save_arg_vars,
7136 memset(cbits, 0, sizeof(cbits));
7140 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, ®mask_dep, &has_ret);
7142 // find unreachable code - must be fixed in IDA
7143 for (i = 0; i < opcnt; i++)
7145 if (cbits[i >> 3] & (1 << (i & 7)))
7148 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
7149 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
7151 // the compiler sometimes still generates code after
7152 // noreturn OS functions
7155 if (ops[i].op != OP_NOP)
7156 ferr(&ops[i], "unreachable code\n");
7159 for (i = 0; i < g_eqcnt; i++) {
7160 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
7161 max_bp_offset = g_eqs[i].offset;
7164 if (fp->argc_stack < 0) {
7165 max_bp_offset = (max_bp_offset + 3) & ~3;
7166 fp->argc_stack = max_bp_offset / 4;
7167 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
7171 fp->regmask_dep = regmask_dep & ~(1 << xSP);
7172 fp->has_ret = has_ret;
7174 printf("// has_ret %d, regmask_dep %x\n",
7175 fp->has_ret, fp->regmask_dep);
7176 output_hdr_fp(stdout, fp, 1);
7177 if (IS(funcn, "sub_10007F72")) exit(1);
7180 gen_x_cleanup(opcnt);
7183 static void hg_fp_resolve_deps(struct func_prototype *fp)
7185 struct func_prototype fp_s;
7189 // this thing is recursive, so mark first..
7190 fp->dep_resolved = 1;
7192 for (i = 0; i < fp->dep_func_cnt; i++) {
7193 strcpy(fp_s.name, fp->dep_func[i].name);
7194 fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
7195 sizeof(hg_fp[0]), hg_fp_cmp_name);
7196 if (fp->dep_func[i].proto != NULL) {
7197 if (!fp->dep_func[i].proto->dep_resolved)
7198 hg_fp_resolve_deps(fp->dep_func[i].proto);
7200 dep = ~fp->dep_func[i].regmask_live
7201 & fp->dep_func[i].proto->regmask_dep;
7202 fp->regmask_dep |= dep;
7203 // printf("dep %s %s |= %x\n", fp->name,
7204 // fp->dep_func[i].name, dep);
7206 if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
7207 fp->has_ret = fp->dep_func[i].proto->has_ret;
7212 // make all thiscall/edx arg functions referenced from .data fastcall
7213 static void do_func_refs_from_data(void)
7215 struct func_prototype *fp, fp_s;
7218 for (i = 0; i < hg_ref_cnt; i++) {
7219 strcpy(fp_s.name, hg_refs[i]);
7220 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
7221 sizeof(hg_fp[0]), hg_fp_cmp_name);
7225 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
7226 fp->regmask_dep |= mxCX | mxDX;
7230 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7233 const struct parsed_proto *pp;
7234 char *p, namebuf[NAMELEN];
7240 for (; count > 0; count--, fp++) {
7241 if (fp->has_ret == -1)
7242 fprintf(fout, "// ret unresolved\n");
7244 fprintf(fout, "// dep:");
7245 for (j = 0; j < fp->dep_func_cnt; j++) {
7246 fprintf(fout, " %s/", fp->dep_func[j].name);
7247 if (fp->dep_func[j].proto != NULL)
7248 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
7249 fp->dep_func[j].proto->has_ret);
7251 fprintf(fout, "\n");
7254 p = strchr(fp->name, '@');
7256 memcpy(namebuf, fp->name, p - fp->name);
7257 namebuf[p - fp->name] = 0;
7265 pp = proto_parse(g_fhdr, name, 1);
7266 if (pp != NULL && pp->is_include)
7269 if (fp->pp != NULL) {
7270 // part of seed, output later
7274 regmask_dep = fp->regmask_dep;
7275 argc_normal = fp->argc_stack;
7277 fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
7278 (fp->has_ret ? "int" : "void"));
7279 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
7280 && (regmask_dep & ~mxCX) == 0)
7282 fprintf(fout, "/*__thiscall*/ ");
7286 else if (regmask_dep && (fp->is_stdcall || fp->argc_stack == 0)
7287 && (regmask_dep & ~(mxCX | mxDX)) == 0)
7289 fprintf(fout, " __fastcall ");
7290 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
7296 else if (regmask_dep && !fp->is_stdcall) {
7297 fprintf(fout, "/*__usercall*/ ");
7299 else if (regmask_dep) {
7300 fprintf(fout, "/*__userpurge*/ ");
7302 else if (fp->is_stdcall)
7303 fprintf(fout, " __stdcall ");
7305 fprintf(fout, " __cdecl ");
7307 fprintf(fout, "%s(", name);
7310 for (j = 0; j < xSP; j++) {
7311 if (regmask_dep & (1 << j)) {
7314 fprintf(fout, ", ");
7316 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
7318 fprintf(fout, "int");
7319 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
7323 for (j = 0; j < argc_normal; j++) {
7326 fprintf(fout, ", ");
7327 if (fp->pp != NULL) {
7328 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
7329 if (!fp->pp->arg[arg - 1].type.is_ptr)
7333 fprintf(fout, "int ");
7334 fprintf(fout, "a%d", arg);
7337 fprintf(fout, ");\n");
7341 static void output_hdr(FILE *fout)
7343 static const char *lmod_c_names[] = {
7344 [OPLM_UNSPEC] = "???",
7345 [OPLM_BYTE] = "uint8_t",
7346 [OPLM_WORD] = "uint16_t",
7347 [OPLM_DWORD] = "uint32_t",
7348 [OPLM_QWORD] = "uint64_t",
7350 const struct scanned_var *var;
7351 struct func_prototype *fp;
7352 char line[256] = { 0, };
7356 // add stuff from headers
7357 for (i = 0; i < pp_cache_size; i++) {
7358 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
7359 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
7361 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
7362 fp = hg_fp_add(name);
7363 fp->pp = &pp_cache[i];
7364 fp->argc_stack = fp->pp->argc_stack;
7365 fp->is_stdcall = fp->pp->is_stdcall;
7366 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
7367 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
7371 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
7372 for (i = 0; i < hg_fp_cnt; i++)
7373 hg_fp_resolve_deps(&hg_fp[i]);
7375 // adjust functions referenced from data segment
7376 do_func_refs_from_data();
7378 // note: messes up .proto ptr, don't use
7379 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
7382 for (i = 0; i < hg_var_cnt; i++) {
7385 if (var->pp != NULL)
7388 else if (var->is_c_str)
7389 fprintf(fout, "extern %-8s %s[];", "char", var->name);
7391 fprintf(fout, "extern %-8s %s;",
7392 lmod_c_names[var->lmod], var->name);
7395 fprintf(fout, " // seeded");
7396 fprintf(fout, "\n");
7399 fprintf(fout, "\n");
7401 // output function prototypes
7402 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
7405 fprintf(fout, "\n// - seed -\n");
7408 while (fgets(line, sizeof(line), g_fhdr))
7409 fwrite(line, 1, strlen(line), fout);
7412 // '=' needs special treatment
7414 static char *next_word_s(char *w, size_t wsize, char *s)
7421 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
7423 for (i = 1; i < wsize - 1; i++) {
7425 printf("warning: missing closing quote: \"%s\"\n", s);
7434 for (; i < wsize - 1; i++) {
7435 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
7441 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
7442 printf("warning: '%s' truncated\n", w);
7447 static int cmpstringp(const void *p1, const void *p2)
7449 return strcmp(*(char * const *)p1, *(char * const *)p2);
7452 static int is_xref_needed(char *p, char **rlist, int rlist_len)
7457 if (strstr(p, "..."))
7458 // unable to determine, assume needed
7461 if (*p == '.') // .text, .data, ...
7462 // ref from other data or non-function -> no
7465 p2 = strpbrk(p, "+:\r\n\x18");
7468 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
7469 // referenced from removed code
7475 static int ida_xrefs_show_need(FILE *fasm, char *p,
7476 char **rlist, int rlist_len)
7482 p = strrchr(p, ';');
7483 if (p != NULL && *p == ';' && IS_START(p + 2, "DATA XREF: ")) {
7485 if (is_xref_needed(p, rlist, rlist_len))
7492 if (!my_fgets(line, sizeof(line), fasm))
7494 // non-first line is always indented
7495 if (!my_isblank(line[0]))
7498 // should be no content, just comment
7503 p = strrchr(p, ';');
7505 // it's printed once, but no harm to check again
7506 if (IS_START(p, "DATA XREF: "))
7509 if (is_xref_needed(p, rlist, rlist_len)) {
7514 fseek(fasm, pos, SEEK_SET);
7518 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
7520 struct scanned_var *var;
7521 char line[256] = { 0, };
7530 // skip to next data section
7531 while (my_fgets(line, sizeof(line), fasm))
7536 if (*p == 0 || *p == ';')
7539 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
7540 if (*p == 0 || *p == ';')
7543 if (*p != 's' || !IS_START(p, "segment para public"))
7549 if (p == NULL || !IS_START(p, "segment para public"))
7553 if (!IS_START(p, "'DATA'"))
7557 while (my_fgets(line, sizeof(line), fasm))
7562 no_identifier = my_isblank(*p);
7565 if (*p == 0 || *p == ';')
7568 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
7569 words[wordc][0] = 0;
7570 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
7571 if (*p == 0 || *p == ';') {
7577 if (wordc == 2 && IS(words[1], "ends"))
7582 if (no_identifier) {
7583 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
7584 hg_ref_add(words[2]);
7588 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
7589 // when this starts, we don't need anything from this section
7593 // check refs comment(s)
7594 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
7597 if ((hg_var_cnt & 0xff) == 0) {
7598 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
7599 * (hg_var_cnt + 0x100));
7600 my_assert_not(hg_vars, NULL);
7601 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
7604 var = &hg_vars[hg_var_cnt++];
7605 snprintf(var->name, sizeof(var->name), "%s", words[0]);
7607 // maybe already in seed header?
7608 var->pp = proto_parse(g_fhdr, var->name, 1);
7609 if (var->pp != NULL) {
7610 if (var->pp->is_fptr) {
7611 var->lmod = OPLM_DWORD;
7614 else if (var->pp->is_func)
7616 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
7617 aerr("unhandled C type '%s' for '%s'\n",
7618 var->pp->type.name, var->name);
7624 if (IS(words[1], "dd")) {
7625 var->lmod = OPLM_DWORD;
7626 if (wordc >= 4 && IS(words[2], "offset"))
7627 hg_ref_add(words[3]);
7629 else if (IS(words[1], "dw"))
7630 var->lmod = OPLM_WORD;
7631 else if (IS(words[1], "db")) {
7632 var->lmod = OPLM_BYTE;
7633 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
7634 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
7638 else if (IS(words[1], "dq"))
7639 var->lmod = OPLM_QWORD;
7640 //else if (IS(words[1], "dt"))
7642 aerr("type '%s' not known\n", words[1]);
7650 static void set_label(int i, const char *name)
7656 p = strchr(name, ':');
7660 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
7661 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
7662 g_labels[i] = realloc(g_labels[i], len + 1);
7663 my_assert_not(g_labels[i], NULL);
7664 memcpy(g_labels[i], name, len);
7665 g_labels[i][len] = 0;
7674 static struct chunk_item *func_chunks;
7675 static int func_chunk_cnt;
7676 static int func_chunk_alloc;
7678 static void add_func_chunk(FILE *fasm, const char *name, int line)
7680 if (func_chunk_cnt >= func_chunk_alloc) {
7681 func_chunk_alloc *= 2;
7682 func_chunks = realloc(func_chunks,
7683 func_chunk_alloc * sizeof(func_chunks[0]));
7684 my_assert_not(func_chunks, NULL);
7686 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
7687 func_chunks[func_chunk_cnt].name = strdup(name);
7688 func_chunks[func_chunk_cnt].asmln = line;
7692 static int cmp_chunks(const void *p1, const void *p2)
7694 const struct chunk_item *c1 = p1, *c2 = p2;
7695 return strcmp(c1->name, c2->name);
7698 static void scan_ahead(FILE *fasm)
7708 oldpos = ftell(fasm);
7711 while (my_fgets(line, sizeof(line), fasm))
7722 // get rid of random tabs
7723 for (i = 0; line[i] != 0; i++)
7724 if (line[i] == '\t')
7727 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
7730 next_word(words[0], sizeof(words[0]), p);
7731 if (words[0][0] == 0)
7732 aerr("missing name for func chunk?\n");
7734 add_func_chunk(fasm, words[0], asmln);
7736 else if (IS_START(p, "; sctend"))
7742 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
7743 words[wordc][0] = 0;
7744 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
7745 if (*p == 0 || *p == ';') {
7751 if (wordc == 2 && IS(words[1], "ends"))
7755 fseek(fasm, oldpos, SEEK_SET);
7759 int main(int argc, char *argv[])
7761 FILE *fout, *fasm, *frlist;
7762 struct parsed_data *pd = NULL;
7764 char **rlist = NULL;
7766 int rlist_alloc = 0;
7767 int func_chunks_used = 0;
7768 int func_chunks_sorted = 0;
7769 int func_chunk_i = -1;
7770 long func_chunk_ret = 0;
7771 int func_chunk_ret_ln = 0;
7772 int scanned_ahead = 0;
7774 char words[20][256];
7775 enum opr_lenmod lmod;
7776 char *sctproto = NULL;
7778 int pending_endp = 0;
7780 int skip_warned = 0;
7793 for (arg = 1; arg < argc; arg++) {
7794 if (IS(argv[arg], "-v"))
7796 else if (IS(argv[arg], "-rf"))
7797 g_allow_regfunc = 1;
7798 else if (IS(argv[arg], "-m"))
7800 else if (IS(argv[arg], "-hdr"))
7801 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
7806 if (argc < arg + 3) {
7807 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
7808 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
7810 " -hdr - header generation mode\n"
7811 " -rf - allow unannotated indirect calls\n"
7812 " -m - allow multiple .text sections\n"
7813 "[rlist] is a file with function names to skip,"
7821 asmfn = argv[arg++];
7822 fasm = fopen(asmfn, "r");
7823 my_assert_not(fasm, NULL);
7825 hdrfn = argv[arg++];
7826 g_fhdr = fopen(hdrfn, "r");
7827 my_assert_not(g_fhdr, NULL);
7830 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
7831 my_assert_not(rlist, NULL);
7832 // needs special handling..
7833 rlist[rlist_len++] = "__alloca_probe";
7835 func_chunk_alloc = 32;
7836 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
7837 my_assert_not(func_chunks, NULL);
7839 memset(words, 0, sizeof(words));
7841 for (; arg < argc; arg++) {
7842 frlist = fopen(argv[arg], "r");
7843 my_assert_not(frlist, NULL);
7845 while (my_fgets(line, sizeof(line), frlist)) {
7847 if (*p == 0 || *p == ';')
7850 if (IS_START(p, "#if 0")
7851 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
7855 else if (IS_START(p, "#endif"))
7862 p = next_word(words[0], sizeof(words[0]), p);
7863 if (words[0][0] == 0)
7866 if (rlist_len >= rlist_alloc) {
7867 rlist_alloc = rlist_alloc * 2 + 64;
7868 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
7869 my_assert_not(rlist, NULL);
7871 rlist[rlist_len++] = strdup(words[0]);
7880 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
7882 fout = fopen(argv[arg_out], "w");
7883 my_assert_not(fout, NULL);
7886 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
7887 my_assert_not(g_eqs, NULL);
7889 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
7890 g_label_refs[i].i = -1;
7891 g_label_refs[i].next = NULL;
7895 scan_variables(fasm, rlist, rlist_len);
7897 while (my_fgets(line, sizeof(line), fasm))
7906 // get rid of random tabs
7907 for (i = 0; line[i] != 0; i++)
7908 if (line[i] == '\t')
7913 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
7914 goto do_pending_endp; // eww..
7916 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
7918 static const char *attrs[] = {
7927 // parse IDA's attribute-list comment
7928 g_ida_func_attr = 0;
7931 for (; *p != 0; p = sskip(p)) {
7932 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
7933 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
7934 g_ida_func_attr |= 1 << i;
7935 p += strlen(attrs[i]);
7939 if (i == ARRAY_SIZE(attrs)) {
7940 anote("unparsed IDA attr: %s\n", p);
7943 if (IS(attrs[i], "fpd=")) {
7944 p = next_word(words[0], sizeof(words[0]), p);
7949 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
7951 static const char *attrs[] = {
7956 // parse manual attribute-list comment
7957 g_sct_func_attr = 0;
7960 for (; *p != 0; p = sskip(p)) {
7961 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
7962 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
7963 g_sct_func_attr |= 1 << i;
7964 p += strlen(attrs[i]);
7971 // clear_sf=start,len (in dwords)
7972 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
7973 &g_stack_clear_len, &j);
7975 // clear_regmask=<mask>
7976 ret = sscanf(p, "=%d%n", &g_regmask_init, &j) + 1;
7978 anote("unparsed attr value: %s\n", p);
7983 else if (i == ARRAY_SIZE(attrs)) {
7984 anote("unparsed sct attr: %s\n", p);
7989 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
7992 next_word(words[0], sizeof(words[0]), p);
7993 if (words[0][0] == 0)
7994 aerr("missing name for func chunk?\n");
7996 if (!scanned_ahead) {
7997 add_func_chunk(fasm, words[0], asmln);
7998 func_chunks_sorted = 0;
8001 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
8003 if (func_chunk_i >= 0) {
8004 if (func_chunk_i < func_chunk_cnt
8005 && IS(func_chunks[func_chunk_i].name, g_func))
8007 // move on to next chunk
8008 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
8010 aerr("seek failed for '%s' chunk #%d\n",
8011 g_func, func_chunk_i);
8012 asmln = func_chunks[func_chunk_i].asmln;
8016 if (func_chunk_ret == 0)
8017 aerr("no return from chunk?\n");
8018 fseek(fasm, func_chunk_ret, SEEK_SET);
8019 asmln = func_chunk_ret_ln;
8025 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
8026 func_chunks_used = 1;
8028 if (IS_START(g_func, "sub_")) {
8029 unsigned long addr = strtoul(p, NULL, 16);
8030 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
8031 if (addr > f_addr && !scanned_ahead) {
8032 //anote("scan_ahead caused by '%s', addr %lx\n",
8036 func_chunks_sorted = 0;
8044 for (i = wordc; i < ARRAY_SIZE(words); i++)
8046 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8047 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8048 if (*p == 0 || *p == ';') {
8053 if (*p != 0 && *p != ';')
8054 aerr("too many words\n");
8056 // alow asm patches in comments
8058 if (IS_START(p, "; sctpatch:")) {
8060 if (*p == 0 || *p == ';')
8062 goto parse_words; // lame
8064 if (IS_START(p, "; sctproto:")) {
8065 sctproto = strdup(p + 11);
8067 else if (IS_START(p, "; sctend")) {
8076 awarn("wordc == 0?\n");
8080 // don't care about this:
8081 if (words[0][0] == '.'
8082 || IS(words[0], "include")
8083 || IS(words[0], "assume") || IS(words[1], "segment")
8084 || IS(words[0], "align"))
8090 // do delayed endp processing to collect switch jumptables
8092 if (in_func && !g_skip_func && !end && wordc >= 2
8093 && ((words[0][0] == 'd' && words[0][2] == 0)
8094 || (words[1][0] == 'd' && words[1][2] == 0)))
8097 if (words[1][0] == 'd' && words[1][2] == 0) {
8099 if (g_func_pd_cnt >= pd_alloc) {
8100 pd_alloc = pd_alloc * 2 + 16;
8101 g_func_pd = realloc(g_func_pd,
8102 sizeof(g_func_pd[0]) * pd_alloc);
8103 my_assert_not(g_func_pd, NULL);
8105 pd = &g_func_pd[g_func_pd_cnt];
8107 memset(pd, 0, sizeof(*pd));
8108 strcpy(pd->label, words[0]);
8109 pd->type = OPT_CONST;
8110 pd->lmod = lmod_from_directive(words[1]);
8116 anote("skipping alignment byte?\n");
8119 lmod = lmod_from_directive(words[0]);
8120 if (lmod != pd->lmod)
8121 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
8124 if (pd->count_alloc < pd->count + wordc) {
8125 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
8126 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
8127 my_assert_not(pd->d, NULL);
8129 for (; i < wordc; i++) {
8130 if (IS(words[i], "offset")) {
8131 pd->type = OPT_OFFSET;
8134 p = strchr(words[i], ',');
8137 if (pd->type == OPT_OFFSET)
8138 pd->d[pd->count].u.label = strdup(words[i]);
8140 pd->d[pd->count].u.val = parse_number(words[i]);
8141 pd->d[pd->count].bt_i = -1;
8147 if (in_func && !g_skip_func) {
8149 gen_hdr(g_func, pi);
8151 gen_func(fout, g_fhdr, g_func, pi);
8156 g_ida_func_attr = 0;
8157 g_sct_func_attr = 0;
8158 g_stack_clear_start = 0;
8159 g_stack_clear_len = 0;
8164 func_chunks_used = 0;
8167 memset(&ops, 0, pi * sizeof(ops[0]));
8172 for (i = 0; i < g_func_pd_cnt; i++) {
8174 if (pd->type == OPT_OFFSET) {
8175 for (j = 0; j < pd->count; j++)
8176 free(pd->d[j].u.label);
8191 if (IS(words[1], "proc")) {
8193 aerr("proc '%s' while in_func '%s'?\n",
8196 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8198 strcpy(g_func, words[0]);
8199 set_label(0, words[0]);
8204 if (IS(words[1], "endp"))
8207 aerr("endp '%s' while not in_func?\n", words[0]);
8208 if (!IS(g_func, words[0]))
8209 aerr("endp '%s' while in_func '%s'?\n",
8212 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
8213 && ops[0].op == OP_JMP && ops[0].operand[0].had_ds)
8219 if (!g_skip_func && func_chunks_used) {
8220 // start processing chunks
8221 struct chunk_item *ci, key = { g_func, 0 };
8223 func_chunk_ret = ftell(fasm);
8224 func_chunk_ret_ln = asmln;
8225 if (!func_chunks_sorted) {
8226 qsort(func_chunks, func_chunk_cnt,
8227 sizeof(func_chunks[0]), cmp_chunks);
8228 func_chunks_sorted = 1;
8230 ci = bsearch(&key, func_chunks, func_chunk_cnt,
8231 sizeof(func_chunks[0]), cmp_chunks);
8233 aerr("'%s' needs chunks, but none found\n", g_func);
8234 func_chunk_i = ci - func_chunks;
8235 for (; func_chunk_i > 0; func_chunk_i--)
8236 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
8239 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
8241 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
8242 asmln = func_chunks[func_chunk_i].asmln;
8250 if (wordc == 2 && IS(words[1], "ends")) {
8254 goto do_pending_endp;
8258 // scan for next text segment
8259 while (my_fgets(line, sizeof(line), fasm)) {
8262 if (*p == 0 || *p == ';')
8265 if (strstr(p, "segment para public 'CODE' use32"))
8272 p = strchr(words[0], ':');
8274 set_label(pi, words[0]);
8278 if (!in_func || g_skip_func) {
8279 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
8281 anote("skipping from '%s'\n", g_labels[pi]);
8285 g_labels[pi] = NULL;
8289 if (wordc > 1 && IS(words[1], "="))
8292 aerr("unhandled equ, wc=%d\n", wordc);
8293 if (g_eqcnt >= eq_alloc) {
8295 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
8296 my_assert_not(g_eqs, NULL);
8299 len = strlen(words[0]);
8300 if (len > sizeof(g_eqs[0].name) - 1)
8301 aerr("equ name too long: %d\n", len);
8302 strcpy(g_eqs[g_eqcnt].name, words[0]);
8304 if (!IS(words[3], "ptr"))
8305 aerr("unhandled equ\n");
8306 if (IS(words[2], "dword"))
8307 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
8308 else if (IS(words[2], "word"))
8309 g_eqs[g_eqcnt].lmod = OPLM_WORD;
8310 else if (IS(words[2], "byte"))
8311 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
8312 else if (IS(words[2], "qword"))
8313 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
8315 aerr("bad lmod: '%s'\n", words[2]);
8317 g_eqs[g_eqcnt].offset = parse_number(words[4]);
8322 if (pi >= ARRAY_SIZE(ops))
8323 aerr("too many ops\n");
8325 parse_op(&ops[pi], words, wordc);
8327 ops[pi].datap = sctproto;
8342 // vim:ts=2:shiftwidth=2:expandtab