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
266 // note: limited to 32k due to p_argnext
268 #define MAX_ARG_GRP 2
270 static struct parsed_op ops[MAX_OPS];
271 static struct parsed_equ *g_eqs;
273 static char *g_labels[MAX_OPS];
274 static struct label_ref g_label_refs[MAX_OPS];
275 static const struct parsed_proto *g_func_pp;
276 static struct parsed_data *g_func_pd;
277 static int g_func_pd_cnt;
278 static int g_func_lmods;
279 static char g_func[256];
280 static char g_comment[256];
281 static int g_bp_frame;
282 static int g_sp_frame;
283 static int g_stack_frame_used;
284 static int g_stack_fsz;
285 static int g_ida_func_attr;
286 static int g_sct_func_attr;
287 static int g_stack_clear_start; // in dwords
288 static int g_stack_clear_len;
289 static int g_skip_func;
290 static int g_allow_regfunc;
291 static int g_quiet_pp;
292 static int g_header_mode;
294 #define ferr(op_, fmt, ...) do { \
295 printf("%s:%d: error %u: [%s] '%s': " fmt, asmfn, (op_)->asmln, \
296 __LINE__, g_func, dump_op(op_), ##__VA_ARGS__); \
300 #define fnote(op_, fmt, ...) \
301 printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
302 dump_op(op_), ##__VA_ARGS__)
304 #define ferr_assert(op_, cond) do { \
305 if (!(cond)) ferr(op_, "assertion '%s' failed\n", #cond); \
308 const char *regs_r32[] = {
309 "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
310 // not r32, but list here for easy parsing and printing
311 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
312 "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"
314 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
315 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
316 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
322 xMM0, xMM1, xMM2, xMM3, // mmx
323 xMM4, xMM5, xMM6, xMM7,
324 xST0, xST1, xST2, xST3, // x87
325 xST4, xST5, xST6, xST7,
328 #define mxAX (1 << xAX)
329 #define mxDX (1 << xDX)
330 #define mxST0 (1 << xST0)
331 #define mxST1 (1 << xST1)
333 // possible basic comparison types (without inversion)
334 enum parsed_flag_op {
338 PFO_BE, // 6 CF=1||ZF=1
342 PFO_LE, // e ZF=1||SF!=OF
345 #define PFOB_O (1 << PFO_O)
346 #define PFOB_C (1 << PFO_C)
347 #define PFOB_Z (1 << PFO_Z)
348 #define PFOB_S (1 << PFO_S)
350 static const char *parsed_flag_op_names[] = {
351 "o", "c", "z", "be", "s", "p", "l", "le"
354 static int char_array_i(const char *array[], size_t len, const char *s)
358 for (i = 0; i < len; i++)
365 static void printf_number(char *buf, size_t buf_size,
366 unsigned long number)
368 // output in C-friendly form
369 snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
372 static int check_segment_prefix(const char *s)
374 if (s[0] == 0 || s[1] != 's' || s[2] != ':')
388 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
392 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
394 *reg_lmod = OPLM_QWORD;
398 *reg_lmod = OPLM_DWORD;
401 reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
403 *reg_lmod = OPLM_WORD;
406 reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
408 *reg_lmod = OPLM_BYTE;
411 reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
413 *reg_lmod = OPLM_BYTE;
420 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
422 enum opr_lenmod lmod;
435 while (my_isblank(*s))
437 for (; my_issep(*s); d++, s++)
439 while (my_isblank(*s))
443 // skip '?s:' prefixes
444 if (check_segment_prefix(s))
447 s = next_idt(w, sizeof(w), s);
452 reg = parse_reg(&lmod, w);
454 *regmask |= 1 << reg;
458 if ('0' <= w[0] && w[0] <= '9') {
459 number = parse_number(w);
460 printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
464 // probably some label/identifier - pass
467 snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
471 strcpy(name, cvtbuf);
476 static int is_reg_in_str(const char *s)
480 if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
483 for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
484 if (!strncmp(s, regs_r32[i], 3))
490 static const char *parse_stack_el(const char *name, char *extra_reg,
493 const char *p, *p2, *s;
499 if (g_bp_frame || early_try)
502 if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
504 if (extra_reg != NULL) {
505 strncpy(extra_reg, name, 3);
510 if (IS_START(p, "ebp+")) {
514 if (p2 != NULL && is_reg_in_str(p)) {
515 if (extra_reg != NULL) {
516 strncpy(extra_reg, p, p2 - p);
517 extra_reg[p2 - p] = 0;
522 if (!('0' <= *p && *p <= '9'))
529 if (!IS_START(name, "esp+"))
535 if (is_reg_in_str(s)) {
536 if (extra_reg != NULL) {
537 strncpy(extra_reg, s, p - s);
538 extra_reg[p - s] = 0;
543 aerr("%s IDA stackvar not set?\n", __func__);
545 if (!('0' <= *s && *s <= '9')) {
546 aerr("%s IDA stackvar offset not set?\n", __func__);
549 if (s[0] == '0' && s[1] == 'x')
552 if (len < sizeof(buf) - 1) {
553 strncpy(buf, s, len);
555 val = strtol(buf, &endp, 16);
556 if (val == 0 || *endp != 0) {
557 aerr("%s num parse fail for '%s'\n", __func__, buf);
566 if ('0' <= *p && *p <= '9')
572 static int guess_lmod_from_name(struct parsed_opr *opr)
574 if (IS_START(opr->name, "dword_") || IS_START(opr->name, "off_")) {
575 opr->lmod = OPLM_DWORD;
578 if (IS_START(opr->name, "word_")) {
579 opr->lmod = OPLM_WORD;
582 if (IS_START(opr->name, "byte_")) {
583 opr->lmod = OPLM_BYTE;
586 if (IS_START(opr->name, "qword_")) {
587 opr->lmod = OPLM_QWORD;
593 static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
594 const struct parsed_type *c_type)
596 static const char *dword_types[] = {
597 "uint32_t", "int", "_DWORD", "UINT_PTR", "DWORD",
598 "WPARAM", "LPARAM", "UINT", "__int32",
599 "LONG", "HIMC", "BOOL", "size_t",
602 static const char *word_types[] = {
603 "uint16_t", "int16_t", "_WORD", "WORD",
604 "unsigned __int16", "__int16",
606 static const char *byte_types[] = {
607 "uint8_t", "int8_t", "char",
608 "unsigned __int8", "__int8", "BYTE", "_BYTE",
610 // structures.. deal the same as with _UNKNOWN for now
616 if (c_type->is_ptr) {
621 n = skip_type_mod(c_type->name);
623 for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
624 if (IS(n, dword_types[i])) {
630 for (i = 0; i < ARRAY_SIZE(word_types); i++) {
631 if (IS(n, word_types[i])) {
637 for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
638 if (IS(n, byte_types[i])) {
647 static char *default_cast_to(char *buf, size_t buf_size,
648 struct parsed_opr *opr)
652 if (!opr->is_ptr || strchr(opr->name, '['))
654 if (opr->pp == NULL || opr->pp->type.name == NULL
657 snprintf(buf, buf_size, "%s", "(void *)");
661 snprintf(buf, buf_size, "(%s)", opr->pp->type.name);
665 static enum opr_type lmod_from_directive(const char *d)
669 else if (IS(d, "dw"))
671 else if (IS(d, "db"))
674 aerr("unhandled directive: '%s'\n", d);
678 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
684 *regmask |= 1 << reg;
687 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
690 static int parse_operand(struct parsed_opr *opr,
691 int *regmask, int *regmask_indirect,
692 char words[16][256], int wordc, int w, unsigned int op_flags)
694 const struct parsed_proto *pp = NULL;
695 enum opr_lenmod tmplmod;
696 unsigned long number;
704 aerr("parse_operand w %d, wordc %d\n", w, wordc);
708 for (i = w; i < wordc; i++) {
709 len = strlen(words[i]);
710 if (words[i][len - 1] == ',') {
711 words[i][len - 1] = 0;
717 wordc_in = wordc - w;
719 if ((op_flags & OPF_JMP) && wordc_in > 0
720 && !('0' <= words[w][0] && words[w][0] <= '9'))
722 const char *label = NULL;
724 if (wordc_in == 3 && !strncmp(words[w], "near", 4)
725 && IS(words[w + 1], "ptr"))
726 label = words[w + 2];
727 else if (wordc_in == 2 && IS(words[w], "short"))
728 label = words[w + 1];
729 else if (wordc_in == 1
730 && strchr(words[w], '[') == NULL
731 && parse_reg(&tmplmod, words[w]) < 0)
735 opr->type = OPT_LABEL;
736 ret = check_segment_prefix(label);
739 aerr("fs/gs used\n");
743 strcpy(opr->name, label);
749 if (IS(words[w + 1], "ptr")) {
750 if (IS(words[w], "dword"))
751 opr->lmod = OPLM_DWORD;
752 else if (IS(words[w], "word"))
753 opr->lmod = OPLM_WORD;
754 else if (IS(words[w], "byte"))
755 opr->lmod = OPLM_BYTE;
756 else if (IS(words[w], "qword"))
757 opr->lmod = OPLM_QWORD;
759 aerr("type parsing failed\n");
761 wordc_in = wordc - w;
766 if (IS(words[w], "offset")) {
767 opr->type = OPT_OFFSET;
768 opr->lmod = OPLM_DWORD;
769 strcpy(opr->name, words[w + 1]);
770 pp = proto_parse(g_fhdr, opr->name, 1);
773 if (IS(words[w], "(offset")) {
774 p = strchr(words[w + 1], ')');
776 aerr("parse of bracketed offset failed\n");
778 opr->type = OPT_OFFSET;
779 strcpy(opr->name, words[w + 1]);
785 aerr("parse_operand 1 word expected\n");
787 ret = check_segment_prefix(words[w]);
790 aerr("fs/gs used\n");
792 memmove(words[w], words[w] + 3, strlen(words[w]) - 2);
794 strcpy(opr->name, words[w]);
796 if (words[w][0] == '[') {
797 opr->type = OPT_REGMEM;
798 ret = sscanf(words[w], "[%[^]]]", opr->name);
800 aerr("[] parse failure\n");
802 parse_indmode(opr->name, regmask_indirect, 1);
803 if (opr->lmod == OPLM_UNSPEC && parse_stack_el(opr->name, NULL, 1))
806 struct parsed_equ *eq =
807 equ_find(NULL, parse_stack_el(opr->name, NULL, 1), &i);
809 opr->lmod = eq->lmod;
811 // might be unaligned access
812 g_func_lmods |= 1 << OPLM_BYTE;
816 else if (strchr(words[w], '[')) {
818 p = strchr(words[w], '[');
819 opr->type = OPT_REGMEM;
820 parse_indmode(p, regmask_indirect, 0);
821 strncpy(buf, words[w], p - words[w]);
822 buf[p - words[w]] = 0;
823 pp = proto_parse(g_fhdr, buf, 1);
826 else if (('0' <= words[w][0] && words[w][0] <= '9')
827 || words[w][0] == '-')
829 number = parse_number(words[w]);
830 opr->type = OPT_CONST;
832 printf_number(opr->name, sizeof(opr->name), number);
836 ret = parse_reg(&tmplmod, opr->name);
838 setup_reg_opr(opr, ret, tmplmod, regmask);
842 // most likely var in data segment
843 opr->type = OPT_LABEL;
844 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
848 if (pp->is_fptr || pp->is_func) {
849 opr->lmod = OPLM_DWORD;
853 tmplmod = OPLM_UNSPEC;
854 if (!guess_lmod_from_c_type(&tmplmod, &pp->type))
855 anote("unhandled C type '%s' for '%s'\n",
856 pp->type.name, opr->name);
858 if (opr->lmod == OPLM_UNSPEC) {
860 opr->type_from_var = 1;
862 else if (opr->lmod != tmplmod) {
863 opr->size_mismatch = 1;
864 if (tmplmod < opr->lmod)
867 opr->is_ptr = pp->type.is_ptr;
869 opr->is_array = pp->type.is_array;
873 if (opr->lmod == OPLM_UNSPEC)
874 guess_lmod_from_name(opr);
878 static const struct {
883 { "repe", OPF_REP|OPF_REPZ },
884 { "repz", OPF_REP|OPF_REPZ },
885 { "repne", OPF_REP|OPF_REPNZ },
886 { "repnz", OPF_REP|OPF_REPNZ },
887 { "lock", OPF_LOCK }, // ignored for now..
890 #define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
892 static const struct {
895 unsigned short minopr;
896 unsigned short maxopr;
899 unsigned char pfo_inv;
901 { "nop", OP_NOP, 0, 0, 0 },
902 { "push", OP_PUSH, 1, 1, 0 },
903 { "pop", OP_POP, 1, 1, OPF_DATA },
904 { "leave",OP_LEAVE, 0, 0, OPF_DATA },
905 { "mov" , OP_MOV, 2, 2, OPF_DATA },
906 { "lea", OP_LEA, 2, 2, OPF_DATA },
907 { "movzx",OP_MOVZX, 2, 2, OPF_DATA },
908 { "movsx",OP_MOVSX, 2, 2, OPF_DATA },
909 { "xchg", OP_XCHG, 2, 2, OPF_DATA },
910 { "not", OP_NOT, 1, 1, OPF_DATA },
911 { "xlat", OP_XLAT, 0, 0, OPF_DATA },
912 { "cdq", OP_CDQ, 0, 0, OPF_DATA },
913 { "lodsb",OP_LODS, 0, 0, OPF_DATA },
914 { "lodsw",OP_LODS, 0, 0, OPF_DATA },
915 { "lodsd",OP_LODS, 0, 0, OPF_DATA },
916 { "stosb",OP_STOS, 0, 0, OPF_DATA },
917 { "stosw",OP_STOS, 0, 0, OPF_DATA },
918 { "stosd",OP_STOS, 0, 0, OPF_DATA },
919 { "movsb",OP_MOVS, 0, 0, OPF_DATA },
920 { "movsw",OP_MOVS, 0, 0, OPF_DATA },
921 { "movsd",OP_MOVS, 0, 0, OPF_DATA },
922 { "cmpsb",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
923 { "cmpsw",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
924 { "cmpsd",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
925 { "scasb",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
926 { "scasw",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
927 { "scasd",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
928 { "std", OP_STD, 0, 0, OPF_DATA }, // special flag
929 { "cld", OP_CLD, 0, 0, OPF_DATA },
930 { "add", OP_ADD, 2, 2, OPF_DATA|OPF_FLAGS },
931 { "sub", OP_SUB, 2, 2, OPF_DATA|OPF_FLAGS },
932 { "and", OP_AND, 2, 2, OPF_DATA|OPF_FLAGS },
933 { "or", OP_OR, 2, 2, OPF_DATA|OPF_FLAGS },
934 { "xor", OP_XOR, 2, 2, OPF_DATA|OPF_FLAGS },
935 { "shl", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
936 { "shr", OP_SHR, 2, 2, OPF_DATA|OPF_FLAGS },
937 { "sal", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
938 { "sar", OP_SAR, 2, 2, OPF_DATA|OPF_FLAGS },
939 { "shld", OP_SHLD, 3, 3, OPF_DATA|OPF_FLAGS },
940 { "shrd", OP_SHRD, 3, 3, OPF_DATA|OPF_FLAGS },
941 { "rol", OP_ROL, 2, 2, OPF_DATA|OPF_FLAGS },
942 { "ror", OP_ROR, 2, 2, OPF_DATA|OPF_FLAGS },
943 { "rcl", OP_RCL, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
944 { "rcr", OP_RCR, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
945 { "adc", OP_ADC, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
946 { "sbb", OP_SBB, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
947 { "bsf", OP_BSF, 2, 2, OPF_DATA|OPF_FLAGS },
948 { "inc", OP_INC, 1, 1, OPF_DATA|OPF_FLAGS },
949 { "dec", OP_DEC, 1, 1, OPF_DATA|OPF_FLAGS },
950 { "neg", OP_NEG, 1, 1, OPF_DATA|OPF_FLAGS },
951 { "mul", OP_MUL, 1, 1, OPF_DATA|OPF_FLAGS },
952 { "imul", OP_IMUL, 1, 3, OPF_DATA|OPF_FLAGS },
953 { "div", OP_DIV, 1, 1, OPF_DATA|OPF_FLAGS },
954 { "idiv", OP_IDIV, 1, 1, OPF_DATA|OPF_FLAGS },
955 { "test", OP_TEST, 2, 2, OPF_FLAGS },
956 { "cmp", OP_CMP, 2, 2, OPF_FLAGS },
957 { "retn", OP_RET, 0, 1, OPF_TAIL },
958 { "call", OP_CALL, 1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
959 { "jmp", OP_JMP, 1, 1, OPF_JMP },
960 { "jecxz",OP_JECXZ, 1, 1, OPF_JMP|OPF_CJMP },
961 { "loop", OP_LOOP, 1, 1, OPF_JMP|OPF_CJMP|OPF_DATA },
962 { "jo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 0 }, // 70 OF=1
963 { "jno", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 1 }, // 71 OF=0
964 { "jc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72 CF=1
965 { "jb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72
966 { "jnc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73 CF=0
967 { "jnb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
968 { "jae", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
969 { "jz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74 ZF=1
970 { "je", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74
971 { "jnz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75 ZF=0
972 { "jne", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75
973 { "jbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76 CF=1||ZF=1
974 { "jna", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76
975 { "ja", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77 CF=0&&ZF=0
976 { "jnbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77
977 { "js", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 0 }, // 78 SF=1
978 { "jns", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 1 }, // 79 SF=0
979 { "jp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a PF=1
980 { "jpe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a
981 { "jnp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b PF=0
982 { "jpo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b
983 { "jl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c SF!=OF
984 { "jnge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c
985 { "jge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d SF=OF
986 { "jnl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d
987 { "jle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e ZF=1||SF!=OF
988 { "jng", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e
989 { "jg", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f ZF=0&&SF=OF
990 { "jnle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f
991 { "seto", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 0 },
992 { "setno", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 1 },
993 { "setc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
994 { "setb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
995 { "setnc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
996 { "setae", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
997 { "setnb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
998 { "setz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
999 { "sete", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1000 { "setnz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1001 { "setne", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1002 { "setbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1003 { "setna", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1004 { "seta", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1005 { "setnbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1006 { "sets", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 0 },
1007 { "setns", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 1 },
1008 { "setp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1009 { "setpe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1010 { "setnp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1011 { "setpo", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1012 { "setl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1013 { "setnge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1014 { "setge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1015 { "setnl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1016 { "setle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1017 { "setng", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1018 { "setg", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1019 { "setnle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1021 { "fld", OP_FLD, 1, 1, OPF_FPUSH },
1022 { "fild", OP_FILD, 1, 1, OPF_FPUSH },
1023 { "fld1", OP_FLDc, 0, 0, OPF_FPUSH },
1024 { "fldz", OP_FLDc, 0, 0, OPF_FPUSH },
1025 { "fstp", OP_FST, 1, 1, OPF_FPOP },
1026 { "fst", OP_FST, 1, 1, 0 },
1027 { "fadd", OP_FADD, 0, 2, 0 },
1028 { "faddp", OP_FADD, 0, 2, OPF_FPOP },
1029 { "fdiv", OP_FDIV, 0, 2, 0 },
1030 { "fdivp", OP_FDIV, 0, 2, OPF_FPOP },
1031 { "fmul", OP_FMUL, 0, 2, 0 },
1032 { "fmulp", OP_FMUL, 0, 2, OPF_FPOP },
1033 { "fsub", OP_FSUB, 0, 2, 0 },
1034 { "fsubp", OP_FSUB, 0, 2, OPF_FPOP },
1035 { "fdivr", OP_FDIVR, 0, 2, 0 },
1036 { "fdivrp", OP_FDIVR, 0, 2, OPF_FPOP },
1037 { "fsubr", OP_FSUBR, 0, 2, 0 },
1038 { "fsubrp", OP_FSUBR, 0, 2, OPF_FPOP },
1039 { "fiadd", OP_FIADD, 1, 1, 0 },
1040 { "fidiv", OP_FIDIV, 1, 1, 0 },
1041 { "fimul", OP_FIMUL, 1, 1, 0 },
1042 { "fisub", OP_FISUB, 1, 1, 0 },
1043 { "fidivr", OP_FIDIVR, 1, 1, 0 },
1044 { "fisubr", OP_FISUBR, 1, 1, 0 },
1046 { "emms", OP_EMMS, 0, 0, OPF_DATA },
1047 { "movq", OP_MOV, 2, 2, OPF_DATA },
1048 // pseudo-ops for lib calls
1049 { "_ftol", OPP_FTOL },
1054 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
1056 enum opr_lenmod lmod = OPLM_UNSPEC;
1057 int prefix_flags = 0;
1065 for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
1066 if (IS(words[w], pref_table[i].name)) {
1067 prefix_flags = pref_table[i].flags;
1074 aerr("lone prefix: '%s'\n", words[0]);
1079 for (i = 0; i < ARRAY_SIZE(op_table); i++) {
1080 if (IS(words[w], op_table[i].name))
1084 if (i == ARRAY_SIZE(op_table)) {
1086 aerr("unhandled op: '%s'\n", words[0]);
1091 op->op = op_table[i].op;
1092 op->flags = op_table[i].flags | prefix_flags;
1093 op->pfo = op_table[i].pfo;
1094 op->pfo_inv = op_table[i].pfo_inv;
1095 op->regmask_src = op->regmask_dst = 0;
1098 if (op->op == OP_UD2)
1101 for (opr = 0; opr < op_table[i].maxopr; opr++) {
1102 if (opr >= op_table[i].minopr && w >= wordc)
1105 regmask = regmask_ind = 0;
1106 w = parse_operand(&op->operand[opr], ®mask, ®mask_ind,
1107 words, wordc, w, op->flags);
1109 if (opr == 0 && (op->flags & OPF_DATA))
1110 op->regmask_dst = regmask;
1112 op->regmask_src |= regmask;
1113 op->regmask_src |= regmask_ind;
1115 if (op->operand[opr].lmod != OPLM_UNSPEC)
1116 g_func_lmods |= 1 << op->operand[opr].lmod;
1120 aerr("parse_op %s incomplete: %d/%d\n",
1121 words[0], w, wordc);
1124 op->operand_cnt = opr;
1125 if (!strncmp(op_table[i].name, "set", 3))
1126 op->operand[0].lmod = OPLM_BYTE;
1129 // first operand is not dst
1132 op->regmask_src |= op->regmask_dst;
1133 op->regmask_dst = 0;
1136 // first operand is src too
1148 op->regmask_src |= op->regmask_dst;
1153 op->regmask_src |= op->regmask_dst;
1154 op->regmask_dst |= op->regmask_src;
1160 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1161 && op->operand[0].lmod == op->operand[1].lmod
1162 && op->operand[0].reg == op->operand[1].reg
1163 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1165 op->regmask_src = 0;
1168 op->regmask_src |= op->regmask_dst;
1171 // ops with implicit argumets
1173 op->operand_cnt = 2;
1174 setup_reg_opr(&op->operand[0], xAX, OPLM_BYTE, &op->regmask_src);
1175 op->regmask_dst = op->regmask_src;
1176 setup_reg_opr(&op->operand[1], xBX, OPLM_DWORD, &op->regmask_src);
1180 op->operand_cnt = 2;
1181 setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
1182 setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
1188 if (words[op_w][4] == 'b')
1190 else if (words[op_w][4] == 'w')
1192 else if (words[op_w][4] == 'd')
1195 op->regmask_src = 0;
1196 setup_reg_opr(&op->operand[j++], op->op == OP_LODS ? xSI : xDI,
1197 OPLM_DWORD, &op->regmask_src);
1198 op->regmask_dst = op->regmask_src;
1199 setup_reg_opr(&op->operand[j++], xAX, lmod,
1200 op->op == OP_LODS ? &op->regmask_dst : &op->regmask_src);
1201 if (op->flags & OPF_REP) {
1202 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1203 op->regmask_dst |= 1 << xCX;
1205 op->operand_cnt = j;
1210 if (words[op_w][4] == 'b')
1212 else if (words[op_w][4] == 'w')
1214 else if (words[op_w][4] == 'd')
1217 op->regmask_src = 0;
1218 // note: lmod is not correct, don't have where to place it
1219 setup_reg_opr(&op->operand[j++], xDI, lmod, &op->regmask_src);
1220 setup_reg_opr(&op->operand[j++], xSI, OPLM_DWORD, &op->regmask_src);
1221 if (op->flags & OPF_REP)
1222 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1223 op->operand_cnt = j;
1224 op->regmask_dst = op->regmask_src;
1228 op->regmask_dst = 1 << xCX;
1231 op->operand_cnt = 2;
1232 op->regmask_src = 1 << xCX;
1233 op->operand[1].type = OPT_REG;
1234 op->operand[1].reg = xCX;
1235 op->operand[1].lmod = OPLM_DWORD;
1239 if (op->operand_cnt == 2) {
1240 if (op->operand[0].type != OPT_REG)
1241 aerr("reg expected\n");
1242 op->regmask_src |= 1 << op->operand[0].reg;
1244 if (op->operand_cnt != 1)
1249 op->regmask_src |= op->regmask_dst;
1250 op->regmask_dst = (1 << xDX) | (1 << xAX);
1251 if (op->operand[0].lmod == OPLM_UNSPEC)
1252 op->operand[0].lmod = OPLM_DWORD;
1257 // we could set up operands for edx:eax, but there is no real need to
1258 // (see is_opr_modified())
1259 op->regmask_src |= op->regmask_dst;
1260 op->regmask_dst = (1 << xDX) | (1 << xAX);
1261 if (op->operand[0].lmod == OPLM_UNSPEC)
1262 op->operand[0].lmod = OPLM_DWORD;
1270 op->regmask_src |= op->regmask_dst;
1271 if (op->operand[1].lmod == OPLM_UNSPEC)
1272 op->operand[1].lmod = OPLM_BYTE;
1277 op->regmask_src |= op->regmask_dst;
1278 if (op->operand[2].lmod == OPLM_UNSPEC)
1279 op->operand[2].lmod = OPLM_BYTE;
1283 op->regmask_src |= op->regmask_dst;
1284 op->regmask_dst = 0;
1285 if (op->operand[0].lmod == OPLM_UNSPEC
1286 && (op->operand[0].type == OPT_CONST
1287 || op->operand[0].type == OPT_OFFSET
1288 || op->operand[0].type == OPT_LABEL))
1289 op->operand[0].lmod = OPLM_DWORD;
1295 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1296 && op->operand[0].lmod == op->operand[1].lmod
1297 && op->operand[0].reg == op->operand[1].reg
1298 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1300 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1301 op->regmask_src = op->regmask_dst = 0;
1306 if (op->operand[0].type == OPT_REG
1307 && op->operand[1].type == OPT_REGMEM)
1310 snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1311 if (IS(buf, op->operand[1].name))
1312 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1317 // trashed regs must be explicitly detected later
1318 op->regmask_dst = 0;
1322 op->regmask_dst = (1 << xBP) | (1 << xSP);
1323 op->regmask_src = 1 << xBP;
1328 op->regmask_dst |= mxST0;
1332 op->regmask_dst |= mxST0;
1333 if (IS(words[op_w] + 3, "1"))
1334 op->operand[0].val = X87_CONST_1;
1335 else if (IS(words[op_w] + 3, "z"))
1336 op->operand[0].val = X87_CONST_Z;
1342 op->regmask_src |= mxST0;
1351 op->regmask_src |= mxST0;
1352 if (op->operand_cnt == 2)
1353 op->regmask_src |= op->regmask_dst;
1354 else if (op->operand_cnt == 1) {
1355 memcpy(&op->operand[1], &op->operand[0], sizeof(op->operand[1]));
1356 op->operand[0].type = OPT_REG;
1357 op->operand[0].lmod = OPLM_QWORD;
1358 op->operand[0].reg = xST0;
1359 op->regmask_dst |= mxST0;
1362 // IDA doesn't use this
1363 aerr("no operands?\n");
1372 op->regmask_src |= mxST0;
1373 op->regmask_dst |= mxST0;
1380 if (op->operand[0].type == OPT_REG
1381 && op->operand[1].type == OPT_CONST)
1383 struct parsed_opr *op1 = &op->operand[1];
1384 if ((op->op == OP_AND && op1->val == 0)
1387 || (op->operand[0].lmod == OPLM_WORD && op1->val == 0xffff)
1388 || (op->operand[0].lmod == OPLM_BYTE && op1->val == 0xff))))
1390 op->regmask_src = 0;
1395 static const char *op_name(struct parsed_op *po)
1397 static char buf[16];
1401 if (po->op == OP_JCC || po->op == OP_SCC) {
1403 *p++ = (po->op == OP_JCC) ? 'j' : 's';
1406 strcpy(p, parsed_flag_op_names[po->pfo]);
1410 for (i = 0; i < ARRAY_SIZE(op_table); i++)
1411 if (op_table[i].op == po->op)
1412 return op_table[i].name;
1418 static const char *dump_op(struct parsed_op *po)
1420 static char out[128];
1427 snprintf(out, sizeof(out), "%s", op_name(po));
1428 for (i = 0; i < po->operand_cnt; i++) {
1432 snprintf(p, sizeof(out) - (p - out),
1433 po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1434 po->operand[i].name);
1440 static const char *lmod_type_u(struct parsed_op *po,
1441 enum opr_lenmod lmod)
1453 ferr(po, "invalid lmod: %d\n", lmod);
1454 return "(_invalid_)";
1458 static const char *lmod_cast_u(struct parsed_op *po,
1459 enum opr_lenmod lmod)
1471 ferr(po, "invalid lmod: %d\n", lmod);
1472 return "(_invalid_)";
1476 static const char *lmod_cast_u_ptr(struct parsed_op *po,
1477 enum opr_lenmod lmod)
1489 ferr(po, "invalid lmod: %d\n", lmod);
1490 return "(_invalid_)";
1494 static const char *lmod_cast_s(struct parsed_op *po,
1495 enum opr_lenmod lmod)
1507 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1508 return "(_invalid_)";
1512 static const char *lmod_cast(struct parsed_op *po,
1513 enum opr_lenmod lmod, int is_signed)
1516 lmod_cast_s(po, lmod) :
1517 lmod_cast_u(po, lmod);
1520 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1532 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1537 static const char *opr_name(struct parsed_op *po, int opr_num)
1539 if (opr_num >= po->operand_cnt)
1540 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1541 return po->operand[opr_num].name;
1544 static unsigned int opr_const(struct parsed_op *po, int opr_num)
1546 if (opr_num >= po->operand_cnt)
1547 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1548 if (po->operand[opr_num].type != OPT_CONST)
1549 ferr(po, "opr %d: const expected\n", opr_num);
1550 return po->operand[opr_num].val;
1553 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1555 if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
1556 ferr(po, "invalid reg: %d\n", popr->reg);
1557 return regs_r32[popr->reg];
1560 static int check_simple_cast(const char *cast, int *bits, int *is_signed)
1562 if (IS_START(cast, "(s8)") || IS_START(cast, "(u8)"))
1564 else if (IS_START(cast, "(s16)") || IS_START(cast, "(u16)"))
1566 else if (IS_START(cast, "(s32)") || IS_START(cast, "(u32)"))
1568 else if (IS_START(cast, "(s64)") || IS_START(cast, "(u64)"))
1573 *is_signed = cast[1] == 's' ? 1 : 0;
1577 static int check_deref_cast(const char *cast, int *bits)
1579 if (IS_START(cast, "*(u8 *)"))
1581 else if (IS_START(cast, "*(u16 *)"))
1583 else if (IS_START(cast, "*(u32 *)"))
1585 else if (IS_START(cast, "*(u64 *)"))
1593 // cast1 is the "final" cast
1594 static const char *simplify_cast(const char *cast1, const char *cast2)
1596 static char buf[256];
1604 if (IS(cast1, cast2))
1607 if (check_simple_cast(cast1, &bits1, &s1) == 0
1608 && check_simple_cast(cast2, &bits2, &s2) == 0)
1613 if (check_simple_cast(cast1, &bits1, &s1) == 0
1614 && check_deref_cast(cast2, &bits2) == 0)
1616 if (bits1 == bits2) {
1617 snprintf(buf, sizeof(buf), "*(%c%d *)", s1 ? 's' : 'u', bits1);
1622 if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1625 snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1629 static const char *simplify_cast_num(const char *cast, unsigned int val)
1631 if (IS(cast, "(u8)") && val < 0x100)
1633 if (IS(cast, "(s8)") && val < 0x80)
1635 if (IS(cast, "(u16)") && val < 0x10000)
1637 if (IS(cast, "(s16)") && val < 0x8000)
1639 if (IS(cast, "(s32)") && val < 0x80000000)
1645 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1654 namelen = strlen(name);
1656 p = strchr(name, '+');
1660 ferr(po, "equ parse failed for '%s'\n", name);
1662 if (IS_START(p, "0x"))
1664 *extra_offs = strtol(p, &endp, 16);
1666 ferr(po, "equ parse failed for '%s'\n", name);
1669 for (i = 0; i < g_eqcnt; i++)
1670 if (strncmp(g_eqs[i].name, name, namelen) == 0
1671 && g_eqs[i].name[namelen] == 0)
1675 ferr(po, "unresolved equ name: '%s'\n", name);
1682 static int is_stack_access(struct parsed_op *po,
1683 const struct parsed_opr *popr)
1685 return (parse_stack_el(popr->name, NULL, 0)
1686 || (g_bp_frame && !(po->flags & OPF_EBP_S)
1687 && IS_START(popr->name, "ebp")));
1690 static void parse_stack_access(struct parsed_op *po,
1691 const char *name, char *ofs_reg, int *offset_out,
1692 int *stack_ra_out, const char **bp_arg_out, int is_lea)
1694 const char *bp_arg = "";
1695 const char *p = NULL;
1696 struct parsed_equ *eq;
1703 if (IS_START(name, "ebp-")
1704 || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1707 if (IS_START(p, "0x"))
1709 offset = strtoul(p, &endp, 16);
1713 ferr(po, "ebp- parse of '%s' failed\n", name);
1716 bp_arg = parse_stack_el(name, ofs_reg, 0);
1717 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1718 eq = equ_find(po, bp_arg, &offset);
1720 ferr(po, "detected but missing eq\n");
1721 offset += eq->offset;
1724 if (!strncmp(name, "ebp", 3))
1727 // yes it sometimes LEAs ra for compares..
1728 if (!is_lea && ofs_reg[0] == 0
1729 && stack_ra <= offset && offset < stack_ra + 4)
1731 ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1734 *offset_out = offset;
1735 *stack_ra_out = stack_ra;
1737 *bp_arg_out = bp_arg;
1740 static int stack_frame_access(struct parsed_op *po,
1741 struct parsed_opr *popr, char *buf, size_t buf_size,
1742 const char *name, const char *cast, int is_src, int is_lea)
1744 enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1745 const char *prefix = "";
1746 const char *bp_arg = NULL;
1747 char ofs_reg[16] = { 0, };
1748 int i, arg_i, arg_s;
1756 if (po->flags & OPF_EBP_S)
1757 ferr(po, "stack_frame_access while ebp is scratch\n");
1759 parse_stack_access(po, name, ofs_reg, &offset,
1760 &stack_ra, &bp_arg, is_lea);
1762 if (offset > stack_ra)
1764 arg_i = (offset - stack_ra - 4) / 4;
1765 if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1767 if (g_func_pp->is_vararg
1768 && arg_i == g_func_pp->argc_stack && is_lea)
1770 // should be va_list
1773 snprintf(buf, buf_size, "%sap", cast);
1776 ferr(po, "offset %d (%s,%d) doesn't map to any arg\n",
1777 offset, bp_arg, arg_i);
1779 if (ofs_reg[0] != 0)
1780 ferr(po, "offset reg on arg access?\n");
1782 for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1783 if (g_func_pp->arg[i].reg != NULL)
1789 if (i == g_func_pp->argc)
1790 ferr(po, "arg %d not in prototype?\n", arg_i);
1792 popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
1799 ferr(po, "lea/byte to arg?\n");
1800 if (is_src && (offset & 3) == 0)
1801 snprintf(buf, buf_size, "%sa%d",
1802 simplify_cast(cast, "(u8)"), i + 1);
1804 snprintf(buf, buf_size, "%sBYTE%d(a%d)",
1805 cast, offset & 3, i + 1);
1810 ferr(po, "lea/word to arg?\n");
1815 ferr(po, "problematic arg store\n");
1816 snprintf(buf, buf_size, "%s((char *)&a%d + 1)",
1817 simplify_cast(cast, "*(u16 *)"), i + 1);
1820 ferr(po, "unaligned arg word load\n");
1822 else if (is_src && (offset & 2) == 0)
1823 snprintf(buf, buf_size, "%sa%d",
1824 simplify_cast(cast, "(u16)"), i + 1);
1826 snprintf(buf, buf_size, "%s%sWORD(a%d)",
1827 cast, (offset & 2) ? "HI" : "LO", i + 1);
1839 snprintf(buf, buf_size, "(u32)&a%d + %d",
1842 ferr(po, "unaligned arg store\n");
1844 // mov edx, [ebp+arg_4+2]; movsx ecx, dx
1845 snprintf(buf, buf_size, "%s(a%d >> %d)",
1846 prefix, i + 1, (offset & 3) * 8);
1850 snprintf(buf, buf_size, "%s%sa%d",
1851 prefix, is_lea ? "&" : "", i + 1);
1856 ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
1860 snprintf(g_comment, sizeof(g_comment), "%s unaligned", bp_arg);
1863 guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
1864 if (tmp_lmod != OPLM_DWORD
1865 && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
1866 < lmod_bytes(po, popr->lmod) + (offset & 3))))
1868 ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
1869 i + 1, offset, g_func_pp->arg[i].type.name);
1871 // can't check this because msvc likes to reuse
1872 // arg space for scratch..
1873 //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
1874 // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
1878 if (g_stack_fsz == 0)
1879 ferr(po, "stack var access without stackframe\n");
1880 g_stack_frame_used = 1;
1882 sf_ofs = g_stack_fsz + offset;
1883 lim = (ofs_reg[0] != 0) ? -4 : 0;
1884 if (offset > 0 || sf_ofs < lim)
1885 ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
1895 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1896 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1900 if ((sf_ofs & 1) || ofs_reg[0] != 0) {
1901 // known unaligned or possibly unaligned
1902 strcat(g_comment, " unaligned");
1904 prefix = "*(u16 *)&";
1905 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1906 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1909 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
1913 if ((sf_ofs & 3) || ofs_reg[0] != 0) {
1914 // known unaligned or possibly unaligned
1915 strcat(g_comment, " unaligned");
1917 prefix = "*(u32 *)&";
1918 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1919 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1922 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
1926 ferr_assert(po, !(sf_ofs & 7));
1927 ferr_assert(po, ofs_reg[0] == 0);
1928 // float callers set is_lea
1929 ferr_assert(po, is_lea);
1930 snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
1934 ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
1941 static void check_func_pp(struct parsed_op *po,
1942 const struct parsed_proto *pp, const char *pfx)
1944 enum opr_lenmod tmp_lmod;
1948 if (pp->argc_reg != 0) {
1949 if (/*!g_allow_regfunc &&*/ !pp->is_fastcall) {
1950 pp_print(buf, sizeof(buf), pp);
1951 ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
1953 if (pp->argc_stack > 0 && pp->argc_reg != 2)
1954 ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
1955 pfx, pp->argc_reg, pp->argc_stack);
1958 // fptrs must use 32bit args, callsite might have no information and
1959 // lack a cast to smaller types, which results in incorrectly masked
1960 // args passed (callee may assume masked args, it does on ARM)
1961 if (!pp->is_osinc) {
1962 for (i = 0; i < pp->argc; i++) {
1963 ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
1964 if (ret && tmp_lmod != OPLM_DWORD)
1965 ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
1966 i + 1, pp->arg[i].type.name);
1971 static const char *check_label_read_ref(struct parsed_op *po,
1974 const struct parsed_proto *pp;
1976 pp = proto_parse(g_fhdr, name, 0);
1978 ferr(po, "proto_parse failed for ref '%s'\n", name);
1981 check_func_pp(po, pp, "ref");
1986 static char *out_src_opr(char *buf, size_t buf_size,
1987 struct parsed_op *po, struct parsed_opr *popr, const char *cast,
1990 char tmp1[256], tmp2[256];
1999 switch (popr->type) {
2002 ferr(po, "lea from reg?\n");
2004 switch (popr->lmod) {
2006 snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2009 snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2012 snprintf(buf, buf_size, "%s%s",
2013 simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2016 if (popr->name[1] == 'h') // XXX..
2017 snprintf(buf, buf_size, "%s(%s >> 8)",
2018 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2020 snprintf(buf, buf_size, "%s%s",
2021 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2024 ferr(po, "invalid src lmod: %d\n", popr->lmod);
2029 if (is_stack_access(po, popr)) {
2030 stack_frame_access(po, popr, buf, buf_size,
2031 popr->name, cast, 1, is_lea);
2035 strcpy(expr, popr->name);
2036 if (strchr(expr, '[')) {
2037 // special case: '[' can only be left for label[reg] form
2038 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2040 ferr(po, "parse failure for '%s'\n", expr);
2041 if (tmp1[0] == '(') {
2042 // (off_4FFF50+3)[eax]
2043 p = strchr(tmp1 + 1, ')');
2044 if (p == NULL || p[1] != 0)
2045 ferr(po, "parse failure (2) for '%s'\n", expr);
2047 memmove(tmp1, tmp1 + 1, strlen(tmp1));
2049 snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2052 // XXX: do we need more parsing?
2054 snprintf(buf, buf_size, "%s", expr);
2058 snprintf(buf, buf_size, "%s(%s)",
2059 simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2063 name = check_label_read_ref(po, popr->name);
2064 if (cast[0] == 0 && popr->is_ptr)
2068 snprintf(buf, buf_size, "(u32)&%s", name);
2069 else if (popr->size_lt)
2070 snprintf(buf, buf_size, "%s%s%s%s", cast,
2071 lmod_cast_u_ptr(po, popr->lmod),
2072 popr->is_array ? "" : "&", name);
2074 snprintf(buf, buf_size, "%s%s%s", cast, name,
2075 popr->is_array ? "[0]" : "");
2079 name = check_label_read_ref(po, popr->name);
2083 ferr(po, "lea an offset?\n");
2084 snprintf(buf, buf_size, "%s&%s", cast, name);
2089 ferr(po, "lea from const?\n");
2091 printf_number(tmp1, sizeof(tmp1), popr->val);
2092 if (popr->val == 0 && strchr(cast, '*'))
2093 snprintf(buf, buf_size, "NULL");
2095 snprintf(buf, buf_size, "%s%s",
2096 simplify_cast_num(cast, popr->val), tmp1);
2100 ferr(po, "invalid src type: %d\n", popr->type);
2106 // note: may set is_ptr (we find that out late for ebp frame..)
2107 static char *out_dst_opr(char *buf, size_t buf_size,
2108 struct parsed_op *po, struct parsed_opr *popr)
2110 switch (popr->type) {
2112 switch (popr->lmod) {
2114 snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2117 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2121 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2125 if (popr->name[1] == 'h') // XXX..
2126 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2128 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2131 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2136 if (is_stack_access(po, popr)) {
2137 stack_frame_access(po, popr, buf, buf_size,
2138 popr->name, "", 0, 0);
2142 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2145 if (popr->size_mismatch)
2146 snprintf(buf, buf_size, "%s%s%s",
2147 lmod_cast_u_ptr(po, popr->lmod),
2148 popr->is_array ? "" : "&", popr->name);
2150 snprintf(buf, buf_size, "%s%s", popr->name,
2151 popr->is_array ? "[0]" : "");
2155 ferr(po, "invalid dst type: %d\n", popr->type);
2161 static char *out_src_opr_u32(char *buf, size_t buf_size,
2162 struct parsed_op *po, struct parsed_opr *popr)
2164 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2167 static char *out_src_opr_float(char *buf, size_t buf_size,
2168 struct parsed_op *po, struct parsed_opr *popr)
2170 const char *cast = NULL;
2173 switch (popr->type) {
2175 if (popr->reg < xST0 || popr->reg > xST7)
2176 ferr(po, "bad reg: %d\n", popr->reg);
2178 snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2184 switch (popr->lmod) {
2192 ferr(po, "unhandled lmod: %d\n", popr->lmod);
2195 out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2196 snprintf(buf, buf_size, "*((%s *)%s)", cast, tmp);
2200 ferr(po, "invalid float type: %d\n", popr->type);
2206 static char *out_dst_opr_float(char *buf, size_t buf_size,
2207 struct parsed_op *po, struct parsed_opr *popr)
2210 return out_src_opr_float(buf, buf_size, po, popr);
2213 static void out_test_for_cc(char *buf, size_t buf_size,
2214 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2215 enum opr_lenmod lmod, const char *expr)
2217 const char *cast, *scast;
2219 cast = lmod_cast_u(po, lmod);
2220 scast = lmod_cast_s(po, lmod);
2224 case PFO_BE: // CF=1||ZF=1; CF=0
2225 snprintf(buf, buf_size, "(%s%s %s 0)",
2226 cast, expr, is_inv ? "!=" : "==");
2230 case PFO_L: // SF!=OF; OF=0
2231 snprintf(buf, buf_size, "(%s%s %s 0)",
2232 scast, expr, is_inv ? ">=" : "<");
2235 case PFO_LE: // ZF=1||SF!=OF; OF=0
2236 snprintf(buf, buf_size, "(%s%s %s 0)",
2237 scast, expr, is_inv ? ">" : "<=");
2241 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2245 static void out_cmp_for_cc(char *buf, size_t buf_size,
2246 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2248 const char *cast, *scast, *cast_use;
2249 char buf1[256], buf2[256];
2250 enum opr_lenmod lmod;
2252 if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2253 ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2254 po->operand[0].lmod, po->operand[1].lmod);
2255 lmod = po->operand[0].lmod;
2257 cast = lmod_cast_u(po, lmod);
2258 scast = lmod_cast_s(po, lmod);
2274 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2277 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2278 if (po->op == OP_DEC)
2279 snprintf(buf2, sizeof(buf2), "1");
2281 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_use, 0);
2285 // note: must be unsigned compare
2286 snprintf(buf, buf_size, "(%s %s %s)",
2287 buf1, is_inv ? ">=" : "<", buf2);
2291 snprintf(buf, buf_size, "(%s %s %s)",
2292 buf1, is_inv ? "!=" : "==", buf2);
2296 // note: must be unsigned compare
2297 snprintf(buf, buf_size, "(%s %s %s)",
2298 buf1, is_inv ? ">" : "<=", buf2);
2301 if (is_inv && lmod == OPLM_BYTE
2302 && po->operand[1].type == OPT_CONST
2303 && po->operand[1].val == 0xff)
2305 snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2306 snprintf(buf, buf_size, "(0)");
2310 // note: must be signed compare
2312 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2313 scast, buf1, buf2, is_inv ? ">=" : "<");
2317 snprintf(buf, buf_size, "(%s %s %s)",
2318 buf1, is_inv ? ">=" : "<", buf2);
2322 snprintf(buf, buf_size, "(%s %s %s)",
2323 buf1, is_inv ? ">" : "<=", buf2);
2331 static void out_cmp_test(char *buf, size_t buf_size,
2332 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2334 char buf1[256], buf2[256], buf3[256];
2336 if (po->op == OP_TEST) {
2337 if (IS(opr_name(po, 0), opr_name(po, 1))) {
2338 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2341 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2342 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2343 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2345 out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2346 po->operand[0].lmod, buf3);
2348 else if (po->op == OP_CMP) {
2349 out_cmp_for_cc(buf, buf_size, po, pfo, is_inv);
2352 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2355 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2356 struct parsed_opr *popr2)
2358 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2359 ferr(po, "missing lmod for both operands\n");
2361 if (popr1->lmod == OPLM_UNSPEC)
2362 popr1->lmod = popr2->lmod;
2363 else if (popr2->lmod == OPLM_UNSPEC)
2364 popr2->lmod = popr1->lmod;
2365 else if (popr1->lmod != popr2->lmod) {
2366 if (popr1->type_from_var) {
2367 popr1->size_mismatch = 1;
2368 if (popr1->lmod < popr2->lmod)
2370 popr1->lmod = popr2->lmod;
2372 else if (popr2->type_from_var) {
2373 popr2->size_mismatch = 1;
2374 if (popr2->lmod < popr1->lmod)
2376 popr2->lmod = popr1->lmod;
2379 ferr(po, "conflicting lmods: %d vs %d\n",
2380 popr1->lmod, popr2->lmod);
2384 static const char *op_to_c(struct parsed_op *po)
2408 ferr(po, "op_to_c was supplied with %d\n", po->op);
2412 // last op in stream - unconditional branch or ret
2413 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2414 || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2415 && ops[_i].op != OP_CALL))
2417 #define check_i(po, i) \
2419 ferr(po, "bad " #i ": %d\n", i)
2421 // note: this skips over calls and rm'd stuff assuming they're handled
2422 // so it's intended to use at one of final passes
2423 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2424 int depth, int flags_set)
2426 struct parsed_op *po;
2431 for (; i < opcnt; i++) {
2433 if (po->cc_scratch == magic)
2434 return ret; // already checked
2435 po->cc_scratch = magic;
2437 if (po->flags & OPF_TAIL) {
2438 if (po->op == OP_CALL) {
2439 if (po->pp != NULL && po->pp->is_noreturn)
2440 // assume no stack cleanup for noreturn
2443 return -1; // deadend
2446 if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
2449 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2450 if (po->btj != NULL) {
2452 for (j = 0; j < po->btj->count; j++) {
2453 check_i(po, po->btj->d[j].bt_i);
2454 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2457 return ret; // dead end
2462 check_i(po, po->bt_i);
2463 if (po->flags & OPF_CJMP) {
2464 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2467 return ret; // dead end
2476 if ((po->op == OP_POP || po->op == OP_PUSH)
2477 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2482 if (po->op == OP_PUSH) {
2485 else if (po->op == OP_POP) {
2486 if (relevant && depth == 0) {
2487 po->flags |= flags_set;
2497 // scan for 'reg' pop backwards starting from i
2498 // intended to use for register restore search, so other reg
2499 // references are considered an error
2500 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2502 struct parsed_op *po;
2503 struct label_ref *lr;
2506 ops[i].cc_scratch = magic;
2510 if (g_labels[i] != NULL) {
2511 lr = &g_label_refs[i];
2512 for (; lr != NULL; lr = lr->next) {
2513 check_i(&ops[i], lr->i);
2514 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2518 if (i > 0 && LAST_OP(i - 1))
2526 if (ops[i].cc_scratch == magic)
2528 ops[i].cc_scratch = magic;
2531 if (po->op == OP_POP && po->operand[0].reg == reg) {
2532 if (po->flags & (OPF_RMD|OPF_DONE))
2535 po->flags |= set_flags;
2539 // this also covers the case where we reach corresponding push
2540 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2544 // nothing interesting on this path
2548 static void find_reachable_exits(int i, int opcnt, int magic,
2549 int *exits, int *exit_count)
2551 struct parsed_op *po;
2554 for (; i < opcnt; i++)
2557 if (po->cc_scratch == magic)
2559 po->cc_scratch = magic;
2561 if (po->flags & OPF_TAIL) {
2562 ferr_assert(po, *exit_count < MAX_EXITS);
2563 exits[*exit_count] = i;
2568 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2569 if (po->flags & OPF_RMD)
2572 if (po->btj != NULL) {
2573 for (j = 0; j < po->btj->count; j++) {
2574 check_i(po, po->btj->d[j].bt_i);
2575 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2581 check_i(po, po->bt_i);
2582 if (po->flags & OPF_CJMP)
2583 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2591 // scan for 'reg' pop backwards starting from exits (all paths)
2592 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2594 static int exits[MAX_EXITS];
2595 static int exit_count;
2600 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2602 ferr_assert(&ops[i], exit_count > 0);
2605 for (j = 0; j < exit_count; j++) {
2606 ret = scan_for_rsave_pop_reg(exits[j], i + opcnt * 16 + set_flags,
2615 // scan for one or more pop of push <const>
2616 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2617 int push_i, int is_probe)
2619 struct parsed_op *po;
2620 struct label_ref *lr;
2624 for (; i < opcnt; i++)
2627 if (po->cc_scratch == magic)
2628 return ret; // already checked
2629 po->cc_scratch = magic;
2631 if (po->flags & OPF_JMP) {
2632 if (po->flags & OPF_RMD)
2634 if (po->op == OP_CALL)
2637 if (po->btj != NULL) {
2638 for (j = 0; j < po->btj->count; j++) {
2639 check_i(po, po->btj->d[j].bt_i);
2640 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2648 check_i(po, po->bt_i);
2649 if (po->flags & OPF_CJMP) {
2650 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2661 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2664 if (g_labels[i] != NULL) {
2665 // all refs must be visited
2666 lr = &g_label_refs[i];
2667 for (; lr != NULL; lr = lr->next) {
2669 if (ops[lr->i].cc_scratch != magic)
2672 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2676 if (po->op == OP_POP)
2678 if (po->flags & (OPF_RMD|OPF_DONE))
2682 po->flags |= OPF_DONE;
2683 po->datap = &ops[push_i];
2692 static void scan_for_pop_const(int i, int opcnt, int magic)
2696 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
2698 ops[i].flags |= OPF_RMD | OPF_DONE;
2699 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
2703 // check if all branch targets within a marked path are also marked
2704 // note: the path checked must not be empty or end with a branch
2705 static int check_path_branches(int opcnt, int magic)
2707 struct parsed_op *po;
2710 for (i = 0; i < opcnt; i++) {
2712 if (po->cc_scratch != magic)
2715 if (po->flags & OPF_JMP) {
2716 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
2719 if (po->btj != NULL) {
2720 for (j = 0; j < po->btj->count; j++) {
2721 check_i(po, po->btj->d[j].bt_i);
2722 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
2727 check_i(po, po->bt_i);
2728 if (ops[po->bt_i].cc_scratch != magic)
2730 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
2738 // scan for multiple pushes for given pop
2739 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
2742 int reg = ops[pop_i].operand[0].reg;
2743 struct parsed_op *po;
2744 struct label_ref *lr;
2747 ops[i].cc_scratch = magic;
2751 if (g_labels[i] != NULL) {
2752 lr = &g_label_refs[i];
2753 for (; lr != NULL; lr = lr->next) {
2754 check_i(&ops[i], lr->i);
2755 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
2759 if (i > 0 && LAST_OP(i - 1))
2767 if (ops[i].cc_scratch == magic)
2769 ops[i].cc_scratch = magic;
2772 if (po->op == OP_CALL)
2774 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
2777 if (po->op == OP_PUSH)
2779 if (po->datap != NULL)
2781 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2782 // leave this case for reg save/restore handlers
2786 po->flags |= OPF_PPUSH | OPF_DONE;
2787 po->datap = &ops[pop_i];
2796 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
2798 int magic = i + opcnt * 14;
2801 ret = scan_pushes_for_pop_r(i, magic, i, 1);
2803 ret = check_path_branches(opcnt, magic);
2805 ops[i].flags |= OPF_PPUSH | OPF_DONE;
2806 *regmask_pp |= 1 << ops[i].operand[0].reg;
2807 scan_pushes_for_pop_r(i, magic + 1, i, 0);
2812 static void scan_propagate_df(int i, int opcnt)
2814 struct parsed_op *po = &ops[i];
2817 for (; i < opcnt; i++) {
2819 if (po->flags & OPF_DF)
2820 return; // already resolved
2821 po->flags |= OPF_DF;
2823 if (po->op == OP_CALL)
2824 ferr(po, "call with DF set?\n");
2826 if (po->flags & OPF_JMP) {
2827 if (po->btj != NULL) {
2829 for (j = 0; j < po->btj->count; j++) {
2830 check_i(po, po->btj->d[j].bt_i);
2831 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
2836 if (po->flags & OPF_RMD)
2838 check_i(po, po->bt_i);
2839 if (po->flags & OPF_CJMP)
2840 scan_propagate_df(po->bt_i, opcnt);
2846 if (po->flags & OPF_TAIL)
2849 if (po->op == OP_CLD) {
2850 po->flags |= OPF_RMD | OPF_DONE;
2855 ferr(po, "missing DF clear?\n");
2858 // is operand 'opr' referenced by parsed_op 'po'?
2859 static int is_opr_referenced(const struct parsed_opr *opr,
2860 const struct parsed_op *po)
2864 if (opr->type == OPT_REG) {
2865 mask = po->regmask_dst | po->regmask_src;
2866 if (po->op == OP_CALL)
2867 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
2868 if ((1 << opr->reg) & mask)
2874 for (i = 0; i < po->operand_cnt; i++)
2875 if (IS(po->operand[0].name, opr->name))
2881 // is operand 'opr' read by parsed_op 'po'?
2882 static int is_opr_read(const struct parsed_opr *opr,
2883 const struct parsed_op *po)
2885 if (opr->type == OPT_REG) {
2886 if (po->regmask_src & (1 << opr->reg))
2896 // is operand 'opr' modified by parsed_op 'po'?
2897 static int is_opr_modified(const struct parsed_opr *opr,
2898 const struct parsed_op *po)
2902 if (opr->type == OPT_REG) {
2903 if (po->op == OP_CALL) {
2904 mask = po->regmask_dst;
2905 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
2906 if (mask & (1 << opr->reg))
2912 if (po->regmask_dst & (1 << opr->reg))
2918 return IS(po->operand[0].name, opr->name);
2921 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
2922 static int is_any_opr_modified(const struct parsed_op *po_test,
2923 const struct parsed_op *po, int c_mode)
2928 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
2931 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
2934 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
2937 // in reality, it can wreck any register, but in decompiled C
2938 // version it can only overwrite eax or edx:eax
2939 mask = (1 << xAX) | (1 << xDX);
2943 if (po->op == OP_CALL
2944 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
2947 for (i = 0; i < po_test->operand_cnt; i++)
2948 if (IS(po_test->operand[i].name, po->operand[0].name))
2954 // scan for any po_test operand modification in range given
2955 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
2958 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
2961 for (; i < opcnt; i++) {
2962 if (is_any_opr_modified(po_test, &ops[i], c_mode))
2969 // scan for po_test operand[0] modification in range given
2970 static int scan_for_mod_opr0(struct parsed_op *po_test,
2973 for (; i < opcnt; i++) {
2974 if (is_opr_modified(&po_test->operand[0], &ops[i]))
2981 static int scan_for_flag_set(int i, int magic, int *branched,
2982 int *setters, int *setter_cnt)
2984 struct label_ref *lr;
2988 if (ops[i].cc_scratch == magic) {
2989 // is this a problem?
2990 //ferr(&ops[i], "%s looped\n", __func__);
2993 ops[i].cc_scratch = magic;
2995 if (g_labels[i] != NULL) {
2998 lr = &g_label_refs[i];
2999 for (; lr->next; lr = lr->next) {
3000 check_i(&ops[i], lr->i);
3001 ret = scan_for_flag_set(lr->i, magic,
3002 branched, setters, setter_cnt);
3007 check_i(&ops[i], lr->i);
3008 if (i > 0 && LAST_OP(i - 1)) {
3012 ret = scan_for_flag_set(lr->i, magic,
3013 branched, setters, setter_cnt);
3019 if (ops[i].flags & OPF_FLAGS) {
3020 setters[*setter_cnt] = i;
3025 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3032 // scan back for cdq, if anything modifies edx, fail
3033 static int scan_for_cdq_edx(int i)
3036 if (g_labels[i] != NULL) {
3037 if (g_label_refs[i].next != NULL)
3039 if (i > 0 && LAST_OP(i - 1)) {
3040 i = g_label_refs[i].i;
3047 if (ops[i].op == OP_CDQ)
3050 if (ops[i].regmask_dst & (1 << xDX))
3057 static int scan_for_reg_clear(int i, int reg)
3060 if (g_labels[i] != NULL) {
3061 if (g_label_refs[i].next != NULL)
3063 if (i > 0 && LAST_OP(i - 1)) {
3064 i = g_label_refs[i].i;
3071 if (ops[i].op == OP_XOR
3072 && ops[i].operand[0].lmod == OPLM_DWORD
3073 && ops[i].operand[0].reg == ops[i].operand[1].reg
3074 && ops[i].operand[0].reg == reg)
3077 if (ops[i].regmask_dst & (1 << reg))
3084 static void patch_esp_adjust(struct parsed_op *po, int adj)
3086 ferr_assert(po, po->op == OP_ADD);
3087 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3088 ferr_assert(po, po->operand[1].type == OPT_CONST);
3090 // this is a bit of a hack, but deals with use of
3091 // single adj for multiple calls
3092 po->operand[1].val -= adj;
3093 po->flags |= OPF_RMD;
3094 if (po->operand[1].val == 0)
3095 po->flags |= OPF_DONE;
3096 ferr_assert(po, (int)po->operand[1].val >= 0);
3099 // scan for positive, constant esp adjust
3100 // multipath case is preliminary
3101 static int scan_for_esp_adjust(int i, int opcnt,
3102 int adj_expect, int *adj, int *is_multipath, int do_update)
3104 int adj_expect_unknown = 0;
3105 struct parsed_op *po;
3109 *adj = *is_multipath = 0;
3110 if (adj_expect < 0) {
3111 adj_expect_unknown = 1;
3112 adj_expect = 32 * 4; // enough?
3115 for (; i < opcnt && *adj < adj_expect; i++) {
3116 if (g_labels[i] != NULL)
3120 if (po->flags & OPF_DONE)
3123 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3124 if (po->operand[1].type != OPT_CONST)
3125 ferr(&ops[i], "non-const esp adjust?\n");
3126 *adj += po->operand[1].val;
3128 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3131 patch_esp_adjust(po, adj_expect);
3133 po->flags |= OPF_RMD;
3137 else if (po->op == OP_PUSH) {
3138 //if (first_pop == -1)
3139 // first_pop = -2; // none
3140 *adj -= lmod_bytes(po, po->operand[0].lmod);
3142 else if (po->op == OP_POP) {
3143 if (!(po->flags & OPF_DONE)) {
3144 // seems like msvc only uses 'pop ecx' for stack realignment..
3145 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3147 if (first_pop == -1 && *adj >= 0)
3150 if (do_update && *adj >= 0) {
3151 po->flags |= OPF_RMD;
3153 po->flags |= OPF_DONE | OPF_NOREGS;
3156 *adj += lmod_bytes(po, po->operand[0].lmod);
3157 if (*adj > adj_best)
3160 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3161 if (po->op == OP_JMP && po->btj == NULL) {
3167 if (po->op != OP_CALL)
3169 if (po->operand[0].type != OPT_LABEL)
3171 if (po->pp != NULL && po->pp->is_stdcall)
3173 if (adj_expect_unknown && first_pop >= 0)
3175 // assume it's another cdecl call
3179 if (first_pop >= 0) {
3180 // probably only 'pop ecx' was used
3188 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3190 struct parsed_op *po;
3194 ferr(ops, "%s: followed bad branch?\n", __func__);
3196 for (; i < opcnt; i++) {
3198 if (po->cc_scratch == magic)
3200 po->cc_scratch = magic;
3203 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3204 if (po->btj != NULL) {
3206 for (j = 0; j < po->btj->count; j++)
3207 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3211 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3212 if (!(po->flags & OPF_CJMP))
3215 if (po->flags & OPF_TAIL)
3220 static const struct parsed_proto *try_recover_pp(
3221 struct parsed_op *po, const struct parsed_opr *opr, int *search_instead)
3223 const struct parsed_proto *pp = NULL;
3227 // maybe an arg of g_func?
3228 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3230 char ofs_reg[16] = { 0, };
3231 int arg, arg_s, arg_i;
3238 parse_stack_access(po, opr->name, ofs_reg,
3239 &offset, &stack_ra, NULL, 0);
3240 if (ofs_reg[0] != 0)
3241 ferr(po, "offset reg on arg access?\n");
3242 if (offset <= stack_ra) {
3243 // search who set the stack var instead
3244 if (search_instead != NULL)
3245 *search_instead = 1;
3249 arg_i = (offset - stack_ra - 4) / 4;
3250 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3251 if (g_func_pp->arg[arg].reg != NULL)
3257 if (arg == g_func_pp->argc)
3258 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3260 pp = g_func_pp->arg[arg].fptr;
3262 ferr(po, "icall sa: arg%d is not a fptr?\n", arg + 1);
3263 check_func_pp(po, pp, "icall arg");
3265 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3267 p = strchr(opr->name + 1, '[');
3268 memcpy(buf, opr->name, p - opr->name);
3269 buf[p - opr->name] = 0;
3270 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3272 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3273 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3276 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3279 check_func_pp(po, pp, "reg-fptr ref");
3285 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3286 int magic, const struct parsed_proto **pp_found, int *pp_i,
3289 const struct parsed_proto *pp = NULL;
3290 struct parsed_op *po;
3291 struct label_ref *lr;
3293 ops[i].cc_scratch = magic;
3296 if (g_labels[i] != NULL) {
3297 lr = &g_label_refs[i];
3298 for (; lr != NULL; lr = lr->next) {
3299 check_i(&ops[i], lr->i);
3300 scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3302 if (i > 0 && LAST_OP(i - 1))
3310 if (ops[i].cc_scratch == magic)
3312 ops[i].cc_scratch = magic;
3314 if (!(ops[i].flags & OPF_DATA))
3316 if (!is_opr_modified(opr, &ops[i]))
3318 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3319 // most probably trashed by some processing
3324 opr = &ops[i].operand[1];
3325 if (opr->type != OPT_REG)
3329 po = (i >= 0) ? &ops[i] : ops;
3332 // reached the top - can only be an arg-reg
3333 if (opr->type != OPT_REG || g_func_pp == NULL)
3336 for (i = 0; i < g_func_pp->argc; i++) {
3337 if (g_func_pp->arg[i].reg == NULL)
3339 if (IS(opr->name, g_func_pp->arg[i].reg))
3342 if (i == g_func_pp->argc)
3344 pp = g_func_pp->arg[i].fptr;
3346 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3347 i + 1, g_func_pp->arg[i].reg);
3348 check_func_pp(po, pp, "icall reg-arg");
3351 pp = try_recover_pp(po, opr, NULL);
3353 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3354 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3355 || (*pp_found)->is_stdcall != pp->is_stdcall
3356 || (*pp_found)->is_fptr != pp->is_fptr
3357 || (*pp_found)->argc != pp->argc
3358 || (*pp_found)->argc_reg != pp->argc_reg
3359 || (*pp_found)->argc_stack != pp->argc_stack)
3361 ferr(po, "icall: parsed_proto mismatch\n");
3371 static void add_label_ref(struct label_ref *lr, int op_i)
3373 struct label_ref *lr_new;
3380 lr_new = calloc(1, sizeof(*lr_new));
3382 lr_new->next = lr->next;
3386 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3388 struct parsed_op *po = &ops[i];
3389 struct parsed_data *pd;
3390 char label[NAMELEN], *p;
3393 p = strchr(po->operand[0].name, '[');
3397 len = p - po->operand[0].name;
3398 strncpy(label, po->operand[0].name, len);
3401 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3402 if (IS(g_func_pd[j].label, label)) {
3408 //ferr(po, "label '%s' not parsed?\n", label);
3411 if (pd->type != OPT_OFFSET)
3412 ferr(po, "label '%s' with non-offset data?\n", label);
3414 // find all labels, link
3415 for (j = 0; j < pd->count; j++) {
3416 for (l = 0; l < opcnt; l++) {
3417 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3418 add_label_ref(&g_label_refs[l], i);
3428 static void clear_labels(int count)
3432 for (i = 0; i < count; i++) {
3433 if (g_labels[i] != NULL) {
3440 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3445 for (i = 0; i < pp->argc; i++) {
3446 if (pp->arg[i].reg != NULL) {
3447 reg = char_array_i(regs_r32,
3448 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3450 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3451 pp->arg[i].reg, pp->name);
3452 regmask |= 1 << reg;
3459 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3464 if (pp->has_retreg) {
3465 for (i = 0; i < pp->argc; i++) {
3466 if (pp->arg[i].type.is_retreg) {
3467 reg = char_array_i(regs_r32,
3468 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3469 ferr_assert(ops, reg >= 0);
3470 regmask |= 1 << reg;
3475 if (strstr(pp->ret_type.name, "int64"))
3476 return regmask | (1 << xAX) | (1 << xDX);
3477 if (IS(pp->ret_type.name, "float")
3478 || IS(pp->ret_type.name, "double"))
3480 return regmask | mxST0;
3482 if (strcasecmp(pp->ret_type.name, "void") == 0)
3485 return regmask | mxAX;
3488 static void resolve_branches_parse_calls(int opcnt)
3490 static const struct {
3494 unsigned int regmask_src;
3495 unsigned int regmask_dst;
3497 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3499 const struct parsed_proto *pp_c;
3500 struct parsed_proto *pp;
3501 struct parsed_data *pd;
3502 struct parsed_op *po;
3503 const char *tmpname;
3507 for (i = 0; i < opcnt; i++)
3513 if (po->datap != NULL) {
3514 pp = calloc(1, sizeof(*pp));
3515 my_assert_not(pp, NULL);
3517 ret = parse_protostr(po->datap, pp);
3519 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3525 if (po->op == OP_CALL) {
3530 else if (po->operand[0].type == OPT_LABEL)
3532 tmpname = opr_name(po, 0);
3533 if (IS_START(tmpname, "loc_"))
3534 ferr(po, "call to loc_*\n");
3536 // convert some calls to pseudo-ops
3537 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3538 if (!IS(tmpname, pseudo_ops[l].name))
3541 po->op = pseudo_ops[l].op;
3542 po->operand_cnt = 0;
3543 po->regmask_src = pseudo_ops[l].regmask_src;
3544 po->regmask_dst = pseudo_ops[l].regmask_dst;
3545 po->flags = pseudo_ops[l].flags;
3546 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3549 if (l < ARRAY_SIZE(pseudo_ops))
3552 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3553 if (!g_header_mode && pp_c == NULL)
3554 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3557 pp = proto_clone(pp_c);
3558 my_assert_not(pp, NULL);
3564 check_func_pp(po, pp, "fptr var call");
3565 if (pp->is_noreturn)
3566 po->flags |= OPF_TAIL;
3572 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3575 if (po->operand[0].type == OPT_REGMEM) {
3576 pd = try_resolve_jumptab(i, opcnt);
3584 for (l = 0; l < opcnt; l++) {
3585 if (g_labels[l] != NULL
3586 && IS(po->operand[0].name, g_labels[l]))
3588 if (l == i + 1 && po->op == OP_JMP) {
3589 // yet another alignment type..
3590 po->flags |= OPF_RMD|OPF_DONE;
3593 add_label_ref(&g_label_refs[l], i);
3599 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3602 if (po->operand[0].type == OPT_LABEL)
3606 ferr(po, "unhandled branch\n");
3610 po->flags |= OPF_TAIL;
3611 if (i > 0 && ops[i - 1].op == OP_POP)
3612 po->flags |= OPF_ATAIL;
3617 static void scan_prologue_epilogue(int opcnt)
3619 int ecx_push = 0, esp_sub = 0;
3623 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
3624 && ops[1].op == OP_MOV
3625 && IS(opr_name(&ops[1], 0), "ebp")
3626 && IS(opr_name(&ops[1], 1), "esp"))
3629 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3630 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3633 if (ops[2].op == OP_SUB && IS(opr_name(&ops[2], 0), "esp")) {
3634 g_stack_fsz = opr_const(&ops[2], 1);
3635 ops[2].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3639 // another way msvc builds stack frame..
3641 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3643 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3647 // and another way..
3648 if (i == 2 && ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3649 && ops[i].operand[1].type == OPT_CONST
3650 && ops[i + 1].op == OP_CALL
3651 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3653 g_stack_fsz += ops[i].operand[1].val;
3654 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3656 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3663 for (; i < opcnt; i++)
3664 if (ops[i].flags & OPF_TAIL)
3667 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3668 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3674 if ((ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
3675 || ops[j].op == OP_LEAVE)
3677 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3679 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
3680 && ops[i].pp->is_noreturn)
3682 // on noreturn, msvc sometimes cleans stack, sometimes not
3687 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3688 ferr(&ops[j], "'pop ebp' expected\n");
3690 if (g_stack_fsz != 0) {
3691 if (ops[j].op == OP_LEAVE)
3693 else if (ops[j].op == OP_POP
3694 && ops[j - 1].op == OP_MOV
3695 && IS(opr_name(&ops[j - 1], 0), "esp")
3696 && IS(opr_name(&ops[j - 1], 1), "ebp"))
3698 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3701 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3703 ferr(&ops[j], "esp restore expected\n");
3706 if (ecx_push && j >= 0 && ops[j].op == OP_POP
3707 && IS(opr_name(&ops[j], 0), "ecx"))
3709 ferr(&ops[j], "unexpected ecx pop\n");
3715 } while (i < opcnt);
3718 ferr(ops, "missing ebp epilogue\n");
3724 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3725 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3731 for (; i < opcnt; i++) {
3732 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
3734 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
3735 && ops[i].operand[1].type == OPT_CONST)
3737 g_stack_fsz = ops[i].operand[1].val;
3738 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3744 if (ecx_push && !esp_sub) {
3745 // could actually be args for a call..
3746 for (; i < opcnt; i++)
3747 if (ops[i].op != OP_PUSH)
3750 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
3751 const struct parsed_proto *pp;
3752 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
3753 j = pp ? pp->argc_stack : 0;
3754 while (i > 0 && j > 0) {
3756 if (ops[i].op == OP_PUSH) {
3757 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
3762 ferr(&ops[i], "unhandled prologue\n");
3765 i = g_stack_fsz = ecx_push = 0;
3766 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3767 if (!(ops[i].flags & OPF_RMD))
3777 if (ecx_push || esp_sub)
3783 for (; i < opcnt; i++)
3784 if (ops[i].flags & OPF_TAIL)
3787 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3788 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3795 for (l = 0; l < ecx_push; l++) {
3796 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
3798 else if (ops[j].op == OP_ADD
3799 && IS(opr_name(&ops[j], 0), "esp")
3800 && ops[j].operand[1].type == OPT_CONST)
3803 l += ops[j].operand[1].val / 4 - 1;
3806 ferr(&ops[j], "'pop ecx' expected\n");
3808 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3812 ferr(&ops[j], "epilogue scan failed\n");
3818 if (ops[j].op != OP_ADD
3819 || !IS(opr_name(&ops[j], 0), "esp")
3820 || ops[j].operand[1].type != OPT_CONST
3821 || ops[j].operand[1].val != g_stack_fsz)
3822 ferr(&ops[j], "'add esp' expected\n");
3824 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3825 ops[j].operand[1].val = 0; // hack for stack arg scanner
3830 } while (i < opcnt);
3833 ferr(ops, "missing esp epilogue\n");
3837 // find an instruction that changed opr before i op
3838 // *op_i must be set to -1 by the caller
3839 // *is_caller is set to 1 if one source is determined to be g_func arg
3840 // returns 1 if found, *op_i is then set to origin
3841 // returns -1 if multiple origins are found
3842 static int resolve_origin(int i, const struct parsed_opr *opr,
3843 int magic, int *op_i, int *is_caller)
3845 struct label_ref *lr;
3848 if (ops[i].cc_scratch == magic)
3850 ops[i].cc_scratch = magic;
3853 if (g_labels[i] != NULL) {
3854 lr = &g_label_refs[i];
3855 for (; lr != NULL; lr = lr->next) {
3856 check_i(&ops[i], lr->i);
3857 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
3859 if (i > 0 && LAST_OP(i - 1))
3865 if (is_caller != NULL)
3870 if (ops[i].cc_scratch == magic)
3872 ops[i].cc_scratch = magic;
3874 if (!(ops[i].flags & OPF_DATA))
3876 if (!is_opr_modified(opr, &ops[i]))
3883 // XXX: could check if the other op does the same
3892 // find an instruction that previously referenced opr
3893 // if multiple results are found - fail
3894 // *op_i must be set to -1 by the caller
3895 // returns 1 if found, *op_i is then set to referencer insn
3896 static int resolve_last_ref(int i, const struct parsed_opr *opr,
3897 int magic, int *op_i)
3899 struct label_ref *lr;
3902 if (ops[i].cc_scratch == magic)
3904 ops[i].cc_scratch = magic;
3907 if (g_labels[i] != NULL) {
3908 lr = &g_label_refs[i];
3909 for (; lr != NULL; lr = lr->next) {
3910 check_i(&ops[i], lr->i);
3911 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
3913 if (i > 0 && LAST_OP(i - 1))
3921 if (ops[i].cc_scratch == magic)
3923 ops[i].cc_scratch = magic;
3925 if (!is_opr_referenced(opr, &ops[i]))
3936 // find next instruction that reads opr
3937 // *op_i must be set to -1 by the caller
3938 // on return, *op_i is set to first referencer insn
3939 // returns 1 if exactly 1 referencer is found
3940 static int find_next_read(int i, int opcnt,
3941 const struct parsed_opr *opr, int magic, int *op_i)
3943 struct parsed_op *po;
3946 for (; i < opcnt; i++)
3948 if (ops[i].cc_scratch == magic)
3950 ops[i].cc_scratch = magic;
3953 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3954 if (po->btj != NULL) {
3956 for (j = 0; j < po->btj->count; j++) {
3957 check_i(po, po->btj->d[j].bt_i);
3958 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
3964 if (po->flags & OPF_RMD)
3966 check_i(po, po->bt_i);
3967 if (po->flags & OPF_CJMP) {
3968 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
3977 if (!is_opr_read(opr, po)) {
3978 if (is_opr_modified(opr, po)
3979 && (po->op == OP_CALL
3980 || ((po->flags & OPF_DATA)
3981 && po->operand[0].lmod == OPLM_DWORD)))
3986 if (po->flags & OPF_TAIL)
4001 static int try_resolve_const(int i, const struct parsed_opr *opr,
4002 int magic, unsigned int *val)
4007 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4010 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4013 *val = ops[i].operand[1].val;
4020 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4021 int *pp_i, int *multi_src)
4023 const struct parsed_proto *pp = NULL;
4024 int search_advice = 0;
4034 switch (ops[i].operand[0].type) {
4036 // try to resolve struct member calls
4037 ret = sscanf(ops[i].operand[0].name, "%3s+%x%n",
4038 s_reg, &offset, &len);
4039 if (ret == 2 && len == strlen(ops[i].operand[0].name))
4041 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4043 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, reg);
4045 ret = resolve_origin(i, &opr, i + opcnt * 19, &j, NULL);
4048 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4049 && ops[j].operand[0].lmod == OPLM_DWORD
4050 && ops[j].pp == NULL) // no hint
4052 // allow one simple dereference (directx)
4053 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4054 ops[j].operand[1].name);
4057 struct parsed_opr opr2 = OPR_INIT(OPT_REG, OPLM_DWORD, reg);
4059 ret = resolve_origin(j, &opr2, j + opcnt * 19, &k, NULL);
4064 if (ops[j].op != OP_MOV)
4066 if (ops[j].operand[0].lmod != OPLM_DWORD)
4068 if (ops[j].pp != NULL) {
4072 else if (ops[j].operand[1].type == OPT_REGMEM) {
4073 // allow 'hello[ecx]' - assume array of same type items
4074 ret = sscanf(ops[j].operand[1].name, "%[^[][e%2s]",
4078 pp = proto_parse(g_fhdr, name, g_quiet_pp);
4080 else if (ops[j].operand[1].type == OPT_LABEL)
4081 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4086 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4090 pp = proto_lookup_struct(g_fhdr, pp->type.name, offset);
4097 pp = try_recover_pp(&ops[i], &ops[i].operand[0], &search_advice);
4102 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4110 static struct parsed_proto *process_call_early(int i, int opcnt,
4113 struct parsed_op *po = &ops[i];
4114 struct parsed_proto *pp;
4120 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4124 // look for and make use of esp adjust
4126 if (!pp->is_stdcall && pp->argc_stack > 0)
4127 ret = scan_for_esp_adjust(i + 1, opcnt,
4128 pp->argc_stack * 4, &adj, &multipath, 0);
4130 if (pp->argc_stack > adj / 4)
4134 if (ops[ret].op == OP_POP) {
4135 for (j = 1; j < adj / 4; j++) {
4136 if (ops[ret + j].op != OP_POP
4137 || ops[ret + j].operand[0].reg != xCX)
4149 static struct parsed_proto *process_call(int i, int opcnt)
4151 struct parsed_op *po = &ops[i];
4152 const struct parsed_proto *pp_c;
4153 struct parsed_proto *pp;
4154 const char *tmpname;
4155 int call_i = -1, ref_i = -1;
4156 int adj = 0, multipath = 0;
4159 tmpname = opr_name(po, 0);
4164 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4166 if (!pp_c->is_func && !pp_c->is_fptr)
4167 ferr(po, "call to non-func: %s\n", pp_c->name);
4168 pp = proto_clone(pp_c);
4169 my_assert_not(pp, NULL);
4171 // not resolved just to single func
4174 switch (po->operand[0].type) {
4176 // we resolved this call and no longer need the register
4177 po->regmask_src &= ~(1 << po->operand[0].reg);
4179 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4180 && ops[call_i].operand[1].type == OPT_LABEL)
4182 // no other source users?
4183 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4185 if (ret == 1 && call_i == ref_i) {
4186 // and nothing uses it after us?
4188 find_next_read(i + 1, opcnt, &po->operand[0],
4189 i + opcnt * 11, &ref_i);
4191 // then also don't need the source mov
4192 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4204 pp = calloc(1, sizeof(*pp));
4205 my_assert_not(pp, NULL);
4208 ret = scan_for_esp_adjust(i + 1, opcnt,
4209 -1, &adj, &multipath, 0);
4210 if (ret < 0 || adj < 0) {
4211 if (!g_allow_regfunc)
4212 ferr(po, "non-__cdecl indirect call unhandled yet\n");
4213 pp->is_unresolved = 1;
4217 if (adj > ARRAY_SIZE(pp->arg))
4218 ferr(po, "esp adjust too large: %d\n", adj);
4219 pp->ret_type.name = strdup("int");
4220 pp->argc = pp->argc_stack = adj;
4221 for (arg = 0; arg < pp->argc; arg++)
4222 pp->arg[arg].type.name = strdup("int");
4227 // look for and make use of esp adjust
4230 if (!pp->is_stdcall && pp->argc_stack > 0) {
4231 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
4232 ret = scan_for_esp_adjust(i + 1, opcnt,
4233 adj_expect, &adj, &multipath, 0);
4236 if (pp->is_vararg) {
4237 if (adj / 4 < pp->argc_stack) {
4238 fnote(po, "(this call)\n");
4239 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
4240 adj, pp->argc_stack * 4);
4242 // modify pp to make it have varargs as normal args
4244 pp->argc += adj / 4 - pp->argc_stack;
4245 for (; arg < pp->argc; arg++) {
4246 pp->arg[arg].type.name = strdup("int");
4249 if (pp->argc > ARRAY_SIZE(pp->arg))
4250 ferr(po, "too many args for '%s'\n", tmpname);
4252 if (pp->argc_stack > adj / 4) {
4253 fnote(po, "(this call)\n");
4254 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
4255 tmpname, pp->argc_stack * 4, adj);
4258 scan_for_esp_adjust(i + 1, opcnt,
4259 pp->argc_stack * 4, &adj, &multipath, 1);
4261 else if (pp->is_vararg)
4262 ferr(po, "missing esp_adjust for vararg func '%s'\n",
4268 static int collect_call_args_early(struct parsed_op *po, int i,
4269 struct parsed_proto *pp, int *regmask)
4274 for (arg = 0; arg < pp->argc; arg++)
4275 if (pp->arg[arg].reg == NULL)
4278 // first see if it can be easily done
4279 for (j = i; j > 0 && arg < pp->argc; )
4281 if (g_labels[j] != NULL)
4285 if (ops[j].op == OP_CALL)
4287 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP)
4289 else if (ops[j].op == OP_POP)
4291 else if (ops[j].flags & OPF_CJMP)
4293 else if (ops[j].op == OP_PUSH) {
4294 if (ops[j].flags & (OPF_FARG|OPF_FARGNR))
4296 ret = scan_for_mod(&ops[j], j + 1, i, 1);
4300 if (pp->arg[arg].type.is_va_list)
4304 for (arg++; arg < pp->argc; arg++)
4305 if (pp->arg[arg].reg == NULL)
4314 for (arg = 0; arg < pp->argc; arg++)
4315 if (pp->arg[arg].reg == NULL)
4318 for (j = i; j > 0 && arg < pp->argc; )
4322 if (ops[j].op == OP_PUSH)
4324 ops[j].p_argnext = -1;
4325 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
4326 pp->arg[arg].datap = &ops[j];
4328 if (ops[j].operand[0].type == OPT_REG)
4329 *regmask |= 1 << ops[j].operand[0].reg;
4331 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4332 ops[j].flags &= ~OPF_RSAVE;
4335 for (arg++; arg < pp->argc; arg++)
4336 if (pp->arg[arg].reg == NULL)
4344 static int collect_call_args_r(struct parsed_op *po, int i,
4345 struct parsed_proto *pp, int *regmask, int *save_arg_vars,
4346 int *arg_grp, int arg, int magic, int need_op_saving, int may_reuse)
4348 struct parsed_proto *pp_tmp;
4349 struct parsed_op *po_tmp;
4350 struct label_ref *lr;
4351 int need_to_save_current;
4352 int arg_grp_current = 0;
4353 int save_args_seen = 0;
4361 ferr(po, "dead label encountered\n");
4365 for (; arg < pp->argc; arg++)
4366 if (pp->arg[arg].reg == NULL)
4368 magic = (magic & 0xffffff) | (arg << 24);
4370 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
4372 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
4373 if (ops[j].cc_scratch != magic) {
4374 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
4378 // ok: have already been here
4381 ops[j].cc_scratch = magic;
4383 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
4384 lr = &g_label_refs[j];
4385 if (lr->next != NULL)
4387 for (; lr->next; lr = lr->next) {
4388 check_i(&ops[j], lr->i);
4389 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4391 ret = collect_call_args_r(po, lr->i, pp, regmask, save_arg_vars,
4392 arg_grp, arg, magic, need_op_saving, may_reuse);
4397 check_i(&ops[j], lr->i);
4398 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4400 if (j > 0 && LAST_OP(j - 1)) {
4401 // follow last branch in reverse
4406 ret = collect_call_args_r(po, lr->i, pp, regmask, save_arg_vars,
4407 arg_grp, arg, magic, need_op_saving, may_reuse);
4413 if (ops[j].op == OP_CALL)
4415 if (pp->is_unresolved)
4420 ferr(po, "arg collect hit unparsed call '%s'\n",
4421 ops[j].operand[0].name);
4422 if (may_reuse && pp_tmp->argc_stack > 0)
4423 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
4424 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
4426 // esp adjust of 0 means we collected it before
4427 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
4428 && (ops[j].operand[1].type != OPT_CONST
4429 || ops[j].operand[1].val != 0))
4431 if (pp->is_unresolved)
4434 fnote(po, "(this call)\n");
4435 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
4436 arg, pp->argc, ops[j].operand[1].val);
4438 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
4440 if (pp->is_unresolved)
4443 fnote(po, "(this call)\n");
4444 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
4446 else if (ops[j].flags & OPF_CJMP)
4448 if (pp->is_unresolved)
4453 else if (ops[j].op == OP_PUSH
4454 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
4456 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
4459 ops[j].p_argnext = -1;
4460 po_tmp = pp->arg[arg].datap;
4462 ops[j].p_argnext = po_tmp - ops;
4463 pp->arg[arg].datap = &ops[j];
4465 need_to_save_current = 0;
4468 if (ops[j].operand[0].type == OPT_REG)
4469 reg = ops[j].operand[0].reg;
4471 if (!need_op_saving) {
4472 ret = scan_for_mod(&ops[j], j + 1, i, 1);
4473 need_to_save_current = (ret >= 0);
4475 if (need_op_saving || need_to_save_current) {
4476 // mark this push as one that needs operand saving
4477 ops[j].flags &= ~OPF_RMD;
4478 if (ops[j].p_argnum == 0) {
4479 ops[j].p_argnum = arg + 1;
4480 save_args |= 1 << arg;
4482 else if (ops[j].p_argnum < arg + 1) {
4483 // XXX: might kill valid var..
4484 //*save_arg_vars &= ~(1 << (ops[j].p_argnum - 1));
4485 ops[j].p_argnum = arg + 1;
4486 save_args |= 1 << arg;
4489 if (save_args_seen & (1 << (ops[j].p_argnum - 1))) {
4492 if (arg_grp_current >= MAX_ARG_GRP)
4493 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
4494 ops[j].p_argnum, pp->name);
4497 else if (ops[j].p_argnum == 0)
4498 ops[j].flags |= OPF_RMD;
4500 // some PUSHes are reused by different calls on other branches,
4501 // but that can't happen if we didn't branch, so they
4502 // can be removed from future searches (handles nested calls)
4504 ops[j].flags |= OPF_FARGNR;
4506 ops[j].flags |= OPF_FARG;
4507 ops[j].flags &= ~OPF_RSAVE;
4509 // check for __VALIST
4510 if (!pp->is_unresolved && g_func_pp != NULL
4511 && pp->arg[arg].type.is_va_list)
4514 ret = resolve_origin(j, &ops[j].operand[0],
4515 magic + 1, &k, NULL);
4516 if (ret == 1 && k >= 0)
4518 if (ops[k].op == OP_LEA) {
4519 if (!g_func_pp->is_vararg)
4520 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
4523 snprintf(buf, sizeof(buf), "arg_%X",
4524 g_func_pp->argc_stack * 4);
4525 if (strstr(ops[k].operand[1].name, buf)
4526 || strstr(ops[k].operand[1].name, "arglist"))
4528 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
4529 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
4530 save_args &= ~(1 << arg);
4534 ferr(&ops[k], "va_list arg detection failed\n");
4536 // check for va_list from g_func_pp arg too
4537 else if (ops[k].op == OP_MOV
4538 && is_stack_access(&ops[k], &ops[k].operand[1]))
4540 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
4541 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
4543 ops[k].flags |= OPF_RMD | OPF_DONE;
4544 ops[j].flags |= OPF_RMD;
4545 ops[j].p_argpass = ret + 1;
4546 save_args &= ~(1 << arg);
4553 *save_arg_vars |= save_args;
4555 // tracking reg usage
4557 *regmask |= 1 << reg;
4560 if (!pp->is_unresolved) {
4562 for (; arg < pp->argc; arg++)
4563 if (pp->arg[arg].reg == NULL)
4566 magic = (magic & 0xffffff) | (arg << 24);
4569 if (ops[j].p_arggrp > arg_grp_current) {
4571 arg_grp_current = ops[j].p_arggrp;
4573 if (ops[j].p_argnum > 0)
4574 save_args_seen |= 1 << (ops[j].p_argnum - 1);
4577 if (arg < pp->argc) {
4578 ferr(po, "arg collect failed for '%s': %d/%d\n",
4579 pp->name, arg, pp->argc);
4583 if (arg_grp_current > *arg_grp)
4584 *arg_grp = arg_grp_current;
4589 static int collect_call_args(struct parsed_op *po, int i,
4590 struct parsed_proto *pp, int *regmask, int *save_arg_vars,
4593 // arg group is for cases when pushes for
4594 // multiple funcs are going on
4595 struct parsed_op *po_tmp;
4596 int save_arg_vars_current = 0;
4601 ret = collect_call_args_r(po, i, pp, regmask,
4602 &save_arg_vars_current, &arg_grp, 0, magic, 0, 0);
4607 // propagate arg_grp
4608 for (a = 0; a < pp->argc; a++) {
4609 if (pp->arg[a].reg != NULL)
4612 po_tmp = pp->arg[a].datap;
4613 while (po_tmp != NULL) {
4614 po_tmp->p_arggrp = arg_grp;
4615 if (po_tmp->p_argnext > 0)
4616 po_tmp = &ops[po_tmp->p_argnext];
4622 save_arg_vars[arg_grp] |= save_arg_vars_current;
4624 if (pp->is_unresolved) {
4626 pp->argc_stack += ret;
4627 for (a = 0; a < pp->argc; a++)
4628 if (pp->arg[a].type.name == NULL)
4629 pp->arg[a].type.name = strdup("int");
4635 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
4636 int regmask_now, int *regmask,
4637 int regmask_save_now, int *regmask_save,
4638 int *regmask_init, int regmask_arg)
4640 struct parsed_op *po;
4649 for (; i < opcnt; i++)
4652 if (cbits[i >> 3] & (1 << (i & 7)))
4654 cbits[i >> 3] |= (1 << (i & 7));
4656 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4657 if (po->flags & (OPF_RMD|OPF_DONE))
4659 if (po->btj != NULL) {
4660 for (j = 0; j < po->btj->count; j++) {
4661 check_i(po, po->btj->d[j].bt_i);
4662 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
4663 regmask_now, regmask, regmask_save_now, regmask_save,
4664 regmask_init, regmask_arg);
4669 check_i(po, po->bt_i);
4670 if (po->flags & OPF_CJMP)
4671 reg_use_pass(po->bt_i, opcnt, cbits,
4672 regmask_now, regmask, regmask_save_now, regmask_save,
4673 regmask_init, regmask_arg);
4679 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
4680 && !g_func_pp->is_userstack
4681 && po->operand[0].type == OPT_REG)
4683 reg = po->operand[0].reg;
4684 ferr_assert(po, reg >= 0);
4687 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
4688 if (regmask_now & (1 << reg)) {
4689 already_saved = regmask_save_now & (1 << reg);
4690 flags_set = OPF_RSAVE | OPF_DONE;
4693 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0);
4695 scan_for_pop(i + 1, opcnt, i + opcnt * 4, reg, 0, flags_set);
4698 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
4700 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
4705 ferr_assert(po, !already_saved);
4706 po->flags |= flags_set;
4708 if (regmask_now & (1 << reg)) {
4709 regmask_save_now |= (1 << reg);
4710 *regmask_save |= regmask_save_now;
4715 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
4716 reg = po->operand[0].reg;
4717 ferr_assert(po, reg >= 0);
4719 if (regmask_save_now & (1 << reg))
4720 regmask_save_now &= ~(1 << reg);
4722 regmask_now &= ~(1 << reg);
4725 else if (po->op == OP_CALL) {
4726 if ((po->regmask_dst & (1 << xAX))
4727 && !(po->regmask_dst & (1 << xDX)))
4729 if (po->flags & OPF_TAIL)
4730 // don't need eax, will do "return f();" or "f(); return;"
4731 po->regmask_dst &= ~(1 << xAX);
4733 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
4735 find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
4738 po->regmask_dst &= ~(1 << xAX);
4743 if (po->flags & OPF_NOREGS)
4746 if (po->flags & OPF_FPUSH) {
4747 if (regmask_now & mxST1)
4748 ferr(po, "TODO: FPUSH on active ST1\n");
4749 if (regmask_now & mxST0)
4750 po->flags |= OPF_FSHIFT;
4751 mask = mxST0 | mxST1;
4752 regmask_now = (regmask_now & ~mask) | ((regmask_now & mxST0) << 1);
4755 // if incomplete register is used, clear it on init to avoid
4756 // later use of uninitialized upper part in some situations
4757 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
4758 && po->operand[0].lmod != OPLM_DWORD)
4760 reg = po->operand[0].reg;
4761 ferr_assert(po, reg >= 0);
4763 if (!(regmask_now & (1 << reg)))
4764 *regmask_init |= 1 << reg;
4767 regmask_op = po->regmask_src | po->regmask_dst;
4769 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
4770 regmask_new &= ~(1 << xSP);
4771 if (g_bp_frame && !(po->flags & OPF_EBP_S))
4772 regmask_new &= ~(1 << xBP);
4774 if (po->op == OP_CALL) {
4775 // allow fastcall calls from anywhere, calee may be also sitting
4776 // in some fastcall table even when it's not using reg args
4777 if (regmask_new & po->regmask_src & (1 << xCX)) {
4778 *regmask_init |= (1 << xCX);
4779 regmask_now |= (1 << xCX);
4780 regmask_new &= ~(1 << xCX);
4782 if (regmask_new & po->regmask_src & (1 << xDX)) {
4783 *regmask_init |= (1 << xDX);
4784 regmask_now |= (1 << xDX);
4785 regmask_new &= ~(1 << xDX);
4789 if (regmask_new != 0)
4790 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
4792 if (regmask_op & (1 << xBP)) {
4793 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
4794 if (po->regmask_dst & (1 << xBP))
4795 // compiler decided to drop bp frame and use ebp as scratch
4796 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
4798 regmask_op &= ~(1 << xBP);
4802 regmask_now |= regmask_op;
4803 *regmask |= regmask_now;
4806 if (po->flags & OPF_FPOP) {
4807 mask = mxST0 | mxST1;
4808 if (!(regmask_now & mask))
4809 ferr(po, "float pop on empty stack?\n");
4810 if (regmask_now & mxST1)
4811 po->flags |= OPF_FSHIFT;
4812 regmask_now = (regmask_now & ~mask) | ((regmask_now & mxST1) >> 1);
4815 if (po->flags & OPF_TAIL) {
4816 if (regmask_now & (mxST0 | mxST1))
4817 ferr(po, "float regs on tail: %x\n", regmask_now);
4819 // there is support for "conditional tailcall", sort of
4820 if (!(po->flags & OPF_CC))
4826 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
4830 for (i = 0; i < pp->argc; i++)
4831 if (pp->arg[i].reg == NULL)
4835 memmove(&pp->arg[i + 1], &pp->arg[i],
4836 sizeof(pp->arg[0]) * pp->argc_stack);
4837 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
4838 pp->arg[i].reg = strdup(reg);
4839 pp->arg[i].type.name = strdup("int");
4844 static void output_std_flags(FILE *fout, struct parsed_op *po,
4845 int *pfomask, const char *dst_opr_text)
4847 if (*pfomask & (1 << PFO_Z)) {
4848 fprintf(fout, "\n cond_z = (%s%s == 0);",
4849 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
4850 *pfomask &= ~(1 << PFO_Z);
4852 if (*pfomask & (1 << PFO_S)) {
4853 fprintf(fout, "\n cond_s = (%s%s < 0);",
4854 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
4855 *pfomask &= ~(1 << PFO_S);
4860 OPP_FORCE_NORETURN = (1 << 0),
4861 OPP_SIMPLE_ARGS = (1 << 1),
4862 OPP_ALIGN = (1 << 2),
4865 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
4868 const char *cconv = "";
4870 if (pp->is_fastcall)
4871 cconv = "__fastcall ";
4872 else if (pp->is_stdcall && pp->argc_reg == 0)
4873 cconv = "__stdcall ";
4875 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
4877 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
4878 fprintf(fout, "noreturn ");
4881 static void output_pp(FILE *fout, const struct parsed_proto *pp,
4886 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
4890 output_pp_attrs(fout, pp, flags);
4893 fprintf(fout, "%s", pp->name);
4898 for (i = 0; i < pp->argc; i++) {
4900 fprintf(fout, ", ");
4901 if (pp->arg[i].fptr != NULL && !(flags & OPP_SIMPLE_ARGS)) {
4903 output_pp(fout, pp->arg[i].fptr, 0);
4905 else if (pp->arg[i].type.is_retreg) {
4906 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
4909 fprintf(fout, "%s", pp->arg[i].type.name);
4911 fprintf(fout, " a%d", i + 1);
4914 if (pp->is_vararg) {
4916 fprintf(fout, ", ");
4917 fprintf(fout, "...");
4922 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
4928 snprintf(buf1, sizeof(buf1), "%d", grp);
4929 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
4934 static void gen_x_cleanup(int opcnt);
4936 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
4938 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
4939 struct parsed_opr *last_arith_dst = NULL;
4940 char buf1[256], buf2[256], buf3[256], cast[64];
4941 struct parsed_proto *pp, *pp_tmp;
4942 struct parsed_data *pd;
4944 int save_arg_vars[MAX_ARG_GRP] = { 0, };
4945 unsigned char cbits[MAX_OPS / 8];
4947 int need_tmp_var = 0;
4950 int label_pending = 0;
4951 int regmask_save = 0; // regs saved/restored in this func
4952 int regmask_arg; // regs from this function args (fastcall, etc)
4953 int regmask_ret; // regs needed on ret
4954 int regmask_now; // temp
4955 int regmask_init = 0; // regs that need zero initialization
4956 int regmask_pp = 0; // regs used in complex push-pop graph
4957 int regmask = 0; // used regs
4966 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
4967 g_stack_frame_used = 0;
4969 g_func_pp = proto_parse(fhdr, funcn, 0);
4970 if (g_func_pp == NULL)
4971 ferr(ops, "proto_parse failed for '%s'\n", funcn);
4973 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
4974 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
4977 // - resolve all branches
4978 // - parse calls with labels
4979 resolve_branches_parse_calls(opcnt);
4982 // - handle ebp/esp frame, remove ops related to it
4983 scan_prologue_epilogue(opcnt);
4986 // - remove dead labels
4987 // - set regs needed at ret
4988 for (i = 0; i < opcnt; i++)
4990 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
4995 if (ops[i].op == OP_RET)
4996 ops[i].regmask_src |= regmask_ret;
5000 // - process trivial calls
5001 for (i = 0; i < opcnt; i++)
5004 if (po->flags & (OPF_RMD|OPF_DONE))
5007 if (po->op == OP_CALL)
5009 pp = process_call_early(i, opcnt, &j);
5011 if (!(po->flags & OPF_ATAIL))
5012 // since we know the args, try to collect them
5013 if (collect_call_args_early(po, i, pp, ®mask) != 0)
5019 // commit esp adjust
5020 if (ops[j].op != OP_POP)
5021 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5023 for (l = 0; l < pp->argc_stack; l++)
5024 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
5028 if (strstr(pp->ret_type.name, "int64"))
5031 po->flags |= OPF_DONE;
5037 // - process calls, stage 2
5038 // - handle some push/pop pairs
5039 // - scan for STD/CLD, propagate DF
5040 for (i = 0; i < opcnt; i++)
5043 if (po->flags & OPF_RMD)
5046 if (po->op == OP_CALL)
5048 if (!(po->flags & OPF_DONE)) {
5049 pp = process_call(i, opcnt);
5051 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
5052 // since we know the args, collect them
5053 collect_call_args(po, i, pp, ®mask, save_arg_vars,
5056 // for unresolved, collect after other passes
5060 ferr_assert(po, pp != NULL);
5062 po->regmask_src |= get_pp_arg_regmask_src(pp);
5063 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
5065 if (po->regmask_dst & mxST0)
5066 po->flags |= OPF_FPUSH;
5068 if (strstr(pp->ret_type.name, "int64"))
5074 if (po->flags & OPF_DONE)
5077 if (po->op == OP_PUSH && !(po->flags & OPF_FARG)
5078 && !(po->flags & OPF_RSAVE) && po->operand[0].type == OPT_CONST)
5080 scan_for_pop_const(i, opcnt, i + opcnt * 12);
5082 else if (po->op == OP_POP)
5083 scan_pushes_for_pop(i, opcnt, ®mask_pp);
5084 else if (po->op == OP_STD) {
5085 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
5086 scan_propagate_df(i + 1, opcnt);
5091 // - find POPs for PUSHes, rm both
5092 // - scan for all used registers
5093 memset(cbits, 0, sizeof(cbits));
5094 reg_use_pass(0, opcnt, cbits, 0, ®mask,
5095 0, ®mask_save, ®mask_init, regmask_arg);
5098 // - find flag set ops for their users
5099 // - do unresolved calls
5100 // - declare indirect functions
5101 for (i = 0; i < opcnt; i++)
5104 if (po->flags & (OPF_RMD|OPF_DONE))
5107 if (po->flags & OPF_CC)
5109 int setters[16], cnt = 0, branched = 0;
5111 ret = scan_for_flag_set(i, i + opcnt * 6,
5112 &branched, setters, &cnt);
5113 if (ret < 0 || cnt <= 0)
5114 ferr(po, "unable to trace flag setter(s)\n");
5115 if (cnt > ARRAY_SIZE(setters))
5116 ferr(po, "too many flag setters\n");
5118 for (j = 0; j < cnt; j++)
5120 tmp_op = &ops[setters[j]]; // flag setter
5123 // to get nicer code, we try to delay test and cmp;
5124 // if we can't because of operand modification, or if we
5125 // have arith op, or branch, make it calculate flags explicitly
5126 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
5128 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
5129 pfomask = 1 << po->pfo;
5131 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
5132 pfomask = 1 << po->pfo;
5135 // see if we'll be able to handle based on op result
5136 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
5137 && po->pfo != PFO_Z && po->pfo != PFO_S
5138 && po->pfo != PFO_P)
5140 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
5142 pfomask = 1 << po->pfo;
5145 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
5146 propagate_lmod(tmp_op, &tmp_op->operand[0],
5147 &tmp_op->operand[1]);
5148 if (tmp_op->operand[0].lmod == OPLM_DWORD)
5153 tmp_op->pfomask |= pfomask;
5154 cond_vars |= pfomask;
5156 // note: may overwrite, currently not a problem
5160 if (po->op == OP_RCL || po->op == OP_RCR
5161 || po->op == OP_ADC || po->op == OP_SBB)
5162 cond_vars |= 1 << PFO_C;
5165 if (po->op == OP_CMPS || po->op == OP_SCAS) {
5166 cond_vars |= 1 << PFO_Z;
5168 else if (po->op == OP_MUL
5169 || (po->op == OP_IMUL && po->operand_cnt == 1))
5171 if (po->operand[0].lmod == OPLM_DWORD)
5174 else if (po->op == OP_CALL) {
5175 // note: resolved non-reg calls are OPF_DONE already
5177 ferr_assert(po, pp != NULL);
5179 if (pp->is_unresolved) {
5180 int regmask_stack = 0;
5181 collect_call_args(po, i, pp, ®mask, save_arg_vars,
5184 // this is pretty rough guess:
5185 // see ecx and edx were pushed (and not their saved versions)
5186 for (arg = 0; arg < pp->argc; arg++) {
5187 if (pp->arg[arg].reg != NULL)
5190 tmp_op = pp->arg[arg].datap;
5192 ferr(po, "parsed_op missing for arg%d\n", arg);
5193 if (tmp_op->p_argnum == 0 && tmp_op->operand[0].type == OPT_REG)
5194 regmask_stack |= 1 << tmp_op->operand[0].reg;
5197 if (!((regmask_stack & (1 << xCX))
5198 && (regmask_stack & (1 << xDX))))
5200 if (pp->argc_stack != 0
5201 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
5203 pp_insert_reg_arg(pp, "ecx");
5204 pp->is_fastcall = 1;
5205 regmask_init |= 1 << xCX;
5206 regmask |= 1 << xCX;
5208 if (pp->argc_stack != 0
5209 || ((regmask | regmask_arg) & (1 << xDX)))
5211 pp_insert_reg_arg(pp, "edx");
5212 regmask_init |= 1 << xDX;
5213 regmask |= 1 << xDX;
5217 // note: __cdecl doesn't fall into is_unresolved category
5218 if (pp->argc_stack > 0)
5222 else if (po->op == OP_MOV && po->operand[0].pp != NULL
5223 && po->operand[1].pp != NULL)
5225 // <var> = offset <something>
5226 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
5227 && !IS_START(po->operand[1].name, "off_"))
5229 if (!po->operand[0].pp->is_fptr)
5230 ferr(po, "%s not declared as fptr when it should be\n",
5231 po->operand[0].name);
5232 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
5233 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
5234 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
5235 fnote(po, "var: %s\n", buf1);
5236 fnote(po, "func: %s\n", buf2);
5237 ferr(po, "^ mismatch\n");
5241 else if (po->op == OP_DIV || po->op == OP_IDIV) {
5242 if (po->operand[0].lmod == OPLM_DWORD) {
5243 // 32bit division is common, look for it
5244 if (po->op == OP_DIV)
5245 ret = scan_for_reg_clear(i, xDX);
5247 ret = scan_for_cdq_edx(i);
5249 po->flags |= OPF_32BIT;
5256 else if (po->op == OP_CLD)
5257 po->flags |= OPF_RMD | OPF_DONE;
5258 else if (po->op == OPP_FTOL) {
5259 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
5261 find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
5263 po->flags |= OPF_32BIT;
5266 if (po->op == OP_RCL || po->op == OP_RCR || po->op == OP_XCHG)
5270 // output starts here
5272 // define userstack size
5273 if (g_func_pp->is_userstack) {
5274 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
5275 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
5276 fprintf(fout, "#endif\n");
5279 // the function itself
5280 ferr_assert(ops, !g_func_pp->is_fptr);
5281 output_pp(fout, g_func_pp,
5282 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
5283 fprintf(fout, "\n{\n");
5285 // declare indirect functions
5286 for (i = 0; i < opcnt; i++) {
5288 if (po->flags & OPF_RMD)
5291 if (po->op == OP_CALL) {
5294 ferr(po, "NULL pp\n");
5296 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
5297 if (pp->name[0] != 0) {
5298 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
5299 memcpy(pp->name, "i_", 2);
5301 // might be declared already
5303 for (j = 0; j < i; j++) {
5304 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
5305 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
5315 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
5318 output_pp(fout, pp, OPP_SIMPLE_ARGS);
5319 fprintf(fout, ";\n");
5324 // output LUTs/jumptables
5325 for (i = 0; i < g_func_pd_cnt; i++) {
5327 fprintf(fout, " static const ");
5328 if (pd->type == OPT_OFFSET) {
5329 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
5331 for (j = 0; j < pd->count; j++) {
5333 fprintf(fout, ", ");
5334 fprintf(fout, "&&%s", pd->d[j].u.label);
5338 fprintf(fout, "%s %s[] =\n { ",
5339 lmod_type_u(ops, pd->lmod), pd->label);
5341 for (j = 0; j < pd->count; j++) {
5343 fprintf(fout, ", ");
5344 fprintf(fout, "%u", pd->d[j].u.val);
5347 fprintf(fout, " };\n");
5351 // declare stack frame, va_arg
5353 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
5354 if (g_func_lmods & (1 << OPLM_WORD))
5355 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
5356 if (g_func_lmods & (1 << OPLM_BYTE))
5357 fprintf(fout, " u8 b[%d];", g_stack_fsz);
5358 if (g_func_lmods & (1 << OPLM_QWORD))
5359 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
5360 fprintf(fout, " } sf;\n");
5364 if (g_func_pp->is_userstack) {
5365 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
5366 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
5370 if (g_func_pp->is_vararg) {
5371 fprintf(fout, " va_list ap;\n");
5375 // declare arg-registers
5376 for (i = 0; i < g_func_pp->argc; i++) {
5377 if (g_func_pp->arg[i].reg != NULL) {
5378 reg = char_array_i(regs_r32,
5379 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
5380 if (regmask & (1 << reg)) {
5381 if (g_func_pp->arg[i].type.is_retreg)
5382 fprintf(fout, " u32 %s = *r_%s;\n",
5383 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
5385 fprintf(fout, " u32 %s = (u32)a%d;\n",
5386 g_func_pp->arg[i].reg, i + 1);
5389 if (g_func_pp->arg[i].type.is_retreg)
5390 ferr(ops, "retreg '%s' is unused?\n",
5391 g_func_pp->arg[i].reg);
5392 fprintf(fout, " // %s = a%d; // unused\n",
5393 g_func_pp->arg[i].reg, i + 1);
5399 // declare normal registers
5400 regmask_now = regmask & ~regmask_arg;
5401 regmask_now &= ~(1 << xSP);
5402 if (regmask_now & 0x00ff) {
5403 for (reg = 0; reg < 8; reg++) {
5404 if (regmask_now & (1 << reg)) {
5405 fprintf(fout, " u32 %s", regs_r32[reg]);
5406 if (regmask_init & (1 << reg))
5407 fprintf(fout, " = 0");
5408 fprintf(fout, ";\n");
5414 if (regmask_now & 0xff00) {
5415 for (reg = 8; reg < 16; reg++) {
5416 if (regmask_now & (1 << reg)) {
5417 fprintf(fout, " mmxr %s", regs_r32[reg]);
5418 if (regmask_init & (1 << reg))
5419 fprintf(fout, " = { 0, }");
5420 fprintf(fout, ";\n");
5426 if (regmask_now & 0xff0000) {
5427 for (reg = 16; reg < 24; reg++) {
5428 if (regmask_now & (1 << reg)) {
5429 fprintf(fout, " double f_st%d", reg - 16);
5430 if (regmask_init & (1 << reg))
5431 fprintf(fout, " = 0");
5432 fprintf(fout, ";\n");
5439 for (reg = 0; reg < 8; reg++) {
5440 if (regmask_save & (1 << reg)) {
5441 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
5447 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
5448 if (save_arg_vars[i] == 0)
5450 for (reg = 0; reg < 32; reg++) {
5451 if (save_arg_vars[i] & (1 << reg)) {
5452 fprintf(fout, " u32 %s;\n",
5453 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
5459 // declare push-pop temporaries
5461 for (reg = 0; reg < 8; reg++) {
5462 if (regmask_pp & (1 << reg)) {
5463 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
5470 for (i = 0; i < 8; i++) {
5471 if (cond_vars & (1 << i)) {
5472 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
5479 fprintf(fout, " u32 tmp;\n");
5484 fprintf(fout, " u64 tmp64;\n");
5489 fprintf(fout, "\n");
5491 // do stack clear, if needed
5492 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
5494 if (g_stack_clear_len != 0) {
5495 if (g_stack_clear_len <= 4) {
5496 for (i = 0; i < g_stack_clear_len; i++)
5497 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
5498 fprintf(fout, "0;\n");
5501 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
5502 g_stack_clear_start, g_stack_clear_len * 4);
5506 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
5509 if (g_func_pp->is_vararg) {
5510 if (g_func_pp->argc_stack == 0)
5511 ferr(ops, "vararg func without stack args?\n");
5512 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
5516 for (i = 0; i < opcnt; i++)
5518 if (g_labels[i] != NULL) {
5519 fprintf(fout, "\n%s:\n", g_labels[i]);
5522 delayed_flag_op = NULL;
5523 last_arith_dst = NULL;
5527 if (po->flags & OPF_RMD)
5532 #define assert_operand_cnt(n_) \
5533 if (po->operand_cnt != n_) \
5534 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
5536 // conditional/flag using op?
5537 if (po->flags & OPF_CC)
5543 // we go through all this trouble to avoid using parsed_flag_op,
5544 // which makes generated code much nicer
5545 if (delayed_flag_op != NULL)
5547 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
5548 po->pfo, po->pfo_inv);
5551 else if (last_arith_dst != NULL
5552 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
5553 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
5556 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
5557 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
5558 last_arith_dst->lmod, buf3);
5561 else if (tmp_op != NULL) {
5562 // use preprocessed flag calc results
5563 if (!(tmp_op->pfomask & (1 << po->pfo)))
5564 ferr(po, "not prepared for pfo %d\n", po->pfo);
5566 // note: pfo_inv was not yet applied
5567 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
5568 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
5571 ferr(po, "all methods of finding comparison failed\n");
5574 if (po->flags & OPF_JMP) {
5575 fprintf(fout, " if %s", buf1);
5577 else if (po->op == OP_RCL || po->op == OP_RCR
5578 || po->op == OP_ADC || po->op == OP_SBB)
5581 fprintf(fout, " cond_%s = %s;\n",
5582 parsed_flag_op_names[po->pfo], buf1);
5584 else if (po->flags & OPF_DATA) { // SETcc
5585 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
5586 fprintf(fout, " %s = %s;", buf2, buf1);
5589 ferr(po, "unhandled conditional op\n");
5593 pfomask = po->pfomask;
5595 if (po->flags & (OPF_REPZ|OPF_REPNZ)) {
5596 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
5597 ret = try_resolve_const(i, &opr, opcnt * 7 + i, &uval);
5599 if (ret != 1 || uval == 0) {
5600 // we need initial flags for ecx=0 case..
5601 if (i > 0 && ops[i - 1].op == OP_XOR
5602 && IS(ops[i - 1].operand[0].name,
5603 ops[i - 1].operand[1].name))
5605 fprintf(fout, " cond_z = ");
5606 if (pfomask & (1 << PFO_C))
5607 fprintf(fout, "cond_c = ");
5608 fprintf(fout, "0;\n");
5610 else if (last_arith_dst != NULL) {
5611 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
5612 out_test_for_cc(buf1, sizeof(buf1), po, PFO_Z, 0,
5613 last_arith_dst->lmod, buf3);
5614 fprintf(fout, " cond_z = %s;\n", buf1);
5617 ferr(po, "missing initial ZF\n");
5624 assert_operand_cnt(2);
5625 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5626 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5627 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
5628 fprintf(fout, " %s = %s;", buf1,
5629 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5634 assert_operand_cnt(2);
5635 po->operand[1].lmod = OPLM_DWORD; // always
5636 fprintf(fout, " %s = %s;",
5637 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5638 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5643 assert_operand_cnt(2);
5644 fprintf(fout, " %s = %s;",
5645 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5646 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5650 assert_operand_cnt(2);
5651 switch (po->operand[1].lmod) {
5653 strcpy(buf3, "(s8)");
5656 strcpy(buf3, "(s16)");
5659 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
5661 fprintf(fout, " %s = %s;",
5662 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5663 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5668 assert_operand_cnt(2);
5669 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5670 fprintf(fout, " tmp = %s;",
5671 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
5672 fprintf(fout, " %s = %s;",
5673 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5674 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5675 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
5676 fprintf(fout, " %s = %stmp;",
5677 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
5678 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
5679 snprintf(g_comment, sizeof(g_comment), "xchg");
5683 assert_operand_cnt(1);
5684 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5685 fprintf(fout, " %s = ~%s;", buf1, buf1);
5689 assert_operand_cnt(2);
5690 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5691 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
5692 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
5693 strcpy(g_comment, "xlat");
5697 assert_operand_cnt(2);
5698 fprintf(fout, " %s = (s32)%s >> 31;",
5699 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5700 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5701 strcpy(g_comment, "cdq");
5705 if (po->flags & OPF_REP) {
5706 assert_operand_cnt(3);
5711 assert_operand_cnt(2);
5712 fprintf(fout, " %s = %sesi; esi %c= %d;",
5713 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
5714 lmod_cast_u_ptr(po, po->operand[1].lmod),
5715 (po->flags & OPF_DF) ? '-' : '+',
5716 lmod_bytes(po, po->operand[1].lmod));
5717 strcpy(g_comment, "lods");
5722 if (po->flags & OPF_REP) {
5723 assert_operand_cnt(3);
5724 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
5725 (po->flags & OPF_DF) ? '-' : '+',
5726 lmod_bytes(po, po->operand[1].lmod));
5727 fprintf(fout, " %sedi = eax;",
5728 lmod_cast_u_ptr(po, po->operand[1].lmod));
5729 strcpy(g_comment, "rep stos");
5732 assert_operand_cnt(2);
5733 fprintf(fout, " %sedi = eax; edi %c= %d;",
5734 lmod_cast_u_ptr(po, po->operand[1].lmod),
5735 (po->flags & OPF_DF) ? '-' : '+',
5736 lmod_bytes(po, po->operand[1].lmod));
5737 strcpy(g_comment, "stos");
5742 j = lmod_bytes(po, po->operand[0].lmod);
5743 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
5744 l = (po->flags & OPF_DF) ? '-' : '+';
5745 if (po->flags & OPF_REP) {
5746 assert_operand_cnt(3);
5748 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
5751 " %sedi = %sesi;", buf1, buf1);
5752 strcpy(g_comment, "rep movs");
5755 assert_operand_cnt(2);
5756 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
5757 buf1, buf1, l, j, l, j);
5758 strcpy(g_comment, "movs");
5763 // repe ~ repeat while ZF=1
5764 j = lmod_bytes(po, po->operand[0].lmod);
5765 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
5766 l = (po->flags & OPF_DF) ? '-' : '+';
5767 if (po->flags & OPF_REP) {
5768 assert_operand_cnt(3);
5770 " for (; ecx != 0; ecx--) {\n");
5771 if (pfomask & (1 << PFO_C)) {
5774 " cond_c = %sesi < %sedi;\n", buf1, buf1);
5775 pfomask &= ~(1 << PFO_C);
5778 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
5779 buf1, buf1, l, j, l, j);
5781 " if (cond_z %s 0) break;\n",
5782 (po->flags & OPF_REPZ) ? "==" : "!=");
5785 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
5786 (po->flags & OPF_REPZ) ? "e" : "ne");
5789 assert_operand_cnt(2);
5791 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
5792 buf1, buf1, l, j, l, j);
5793 strcpy(g_comment, "cmps");
5795 pfomask &= ~(1 << PFO_Z);
5796 last_arith_dst = NULL;
5797 delayed_flag_op = NULL;
5801 // only does ZF (for now)
5802 // repe ~ repeat while ZF=1
5803 j = lmod_bytes(po, po->operand[1].lmod);
5804 l = (po->flags & OPF_DF) ? '-' : '+';
5805 if (po->flags & OPF_REP) {
5806 assert_operand_cnt(3);
5808 " for (; ecx != 0; ecx--) {\n");
5810 " cond_z = (%seax == %sedi); edi %c= %d;\n",
5811 lmod_cast_u(po, po->operand[1].lmod),
5812 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
5814 " if (cond_z %s 0) break;\n",
5815 (po->flags & OPF_REPZ) ? "==" : "!=");
5818 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
5819 (po->flags & OPF_REPZ) ? "e" : "ne");
5822 assert_operand_cnt(2);
5823 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
5824 lmod_cast_u(po, po->operand[1].lmod),
5825 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
5826 strcpy(g_comment, "scas");
5828 pfomask &= ~(1 << PFO_Z);
5829 last_arith_dst = NULL;
5830 delayed_flag_op = NULL;
5833 // arithmetic w/flags
5835 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
5836 goto dualop_arith_const;
5837 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5841 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5842 if (po->operand[1].type == OPT_CONST) {
5843 j = lmod_bytes(po, po->operand[0].lmod);
5844 if (((1ull << j * 8) - 1) == po->operand[1].val)
5845 goto dualop_arith_const;
5850 assert_operand_cnt(2);
5851 fprintf(fout, " %s %s= %s;",
5852 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5854 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5855 output_std_flags(fout, po, &pfomask, buf1);
5856 last_arith_dst = &po->operand[0];
5857 delayed_flag_op = NULL;
5861 // and 0, or ~0 used instead mov
5862 assert_operand_cnt(2);
5863 fprintf(fout, " %s = %s;",
5864 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5865 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5866 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
5867 output_std_flags(fout, po, &pfomask, buf1);
5868 last_arith_dst = &po->operand[0];
5869 delayed_flag_op = NULL;
5874 assert_operand_cnt(2);
5875 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5876 if (pfomask & (1 << PFO_C)) {
5877 if (po->operand[1].type == OPT_CONST) {
5878 l = lmod_bytes(po, po->operand[0].lmod) * 8;
5879 j = po->operand[1].val;
5882 if (po->op == OP_SHL)
5886 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
5890 ferr(po, "zero shift?\n");
5894 pfomask &= ~(1 << PFO_C);
5896 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
5897 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5898 if (po->operand[1].type != OPT_CONST)
5899 fprintf(fout, " & 0x1f");
5901 output_std_flags(fout, po, &pfomask, buf1);
5902 last_arith_dst = &po->operand[0];
5903 delayed_flag_op = NULL;
5907 assert_operand_cnt(2);
5908 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5909 fprintf(fout, " %s = %s%s >> %s;", buf1,
5910 lmod_cast_s(po, po->operand[0].lmod), buf1,
5911 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5912 output_std_flags(fout, po, &pfomask, buf1);
5913 last_arith_dst = &po->operand[0];
5914 delayed_flag_op = NULL;
5919 assert_operand_cnt(3);
5920 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5921 l = lmod_bytes(po, po->operand[0].lmod) * 8;
5922 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
5923 if (po->operand[2].type != OPT_CONST) {
5924 // no handling for "undefined" case, hopefully not needed
5925 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
5928 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
5929 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5930 if (po->op == OP_SHLD) {
5931 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
5932 buf1, buf3, buf1, buf2, l, buf3);
5933 strcpy(g_comment, "shld");
5936 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
5937 buf1, buf3, buf1, buf2, l, buf3);
5938 strcpy(g_comment, "shrd");
5940 output_std_flags(fout, po, &pfomask, buf1);
5941 last_arith_dst = &po->operand[0];
5942 delayed_flag_op = NULL;
5947 assert_operand_cnt(2);
5948 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5949 if (po->operand[1].type == OPT_CONST) {
5950 j = po->operand[1].val;
5951 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
5952 fprintf(fout, po->op == OP_ROL ?
5953 " %s = (%s << %d) | (%s >> %d);" :
5954 " %s = (%s >> %d) | (%s << %d);",
5955 buf1, buf1, j, buf1,
5956 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
5960 output_std_flags(fout, po, &pfomask, buf1);
5961 last_arith_dst = &po->operand[0];
5962 delayed_flag_op = NULL;
5967 assert_operand_cnt(2);
5968 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5969 l = lmod_bytes(po, po->operand[0].lmod) * 8;
5970 if (po->operand[1].type == OPT_CONST) {
5971 j = po->operand[1].val % l;
5973 ferr(po, "zero rotate\n");
5974 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
5975 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
5976 if (po->op == OP_RCL) {
5978 " %s = (%s << %d) | (cond_c << %d)",
5979 buf1, buf1, j, j - 1);
5981 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
5985 " %s = (%s >> %d) | (cond_c << %d)",
5986 buf1, buf1, j, l - j);
5988 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
5990 fprintf(fout, ";\n");
5991 fprintf(fout, " cond_c = tmp;");
5995 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
5996 output_std_flags(fout, po, &pfomask, buf1);
5997 last_arith_dst = &po->operand[0];
5998 delayed_flag_op = NULL;
6002 assert_operand_cnt(2);
6003 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6004 if (IS(opr_name(po, 0), opr_name(po, 1))) {
6005 // special case for XOR
6006 if (pfomask & (1 << PFO_BE)) { // weird, but it happens..
6007 fprintf(fout, " cond_be = 1;\n");
6008 pfomask &= ~(1 << PFO_BE);
6010 fprintf(fout, " %s = 0;",
6011 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6012 last_arith_dst = &po->operand[0];
6013 delayed_flag_op = NULL;
6019 assert_operand_cnt(2);
6020 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6021 if (pfomask & (1 << PFO_C)) {
6022 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6023 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6024 if (po->operand[0].lmod == OPLM_DWORD) {
6025 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
6026 fprintf(fout, " cond_c = tmp64 >> 32;\n");
6027 fprintf(fout, " %s = (u32)tmp64;",
6028 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6029 strcat(g_comment, " add64");
6032 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
6033 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
6034 fprintf(fout, " %s += %s;",
6035 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6038 pfomask &= ~(1 << PFO_C);
6039 output_std_flags(fout, po, &pfomask, buf1);
6040 last_arith_dst = &po->operand[0];
6041 delayed_flag_op = NULL;
6047 assert_operand_cnt(2);
6048 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6049 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
6050 for (j = 0; j <= PFO_LE; j++) {
6051 if (!(pfomask & (1 << j)))
6053 if (j == PFO_Z || j == PFO_S)
6056 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0);
6057 fprintf(fout, " cond_%s = %s;\n",
6058 parsed_flag_op_names[j], buf1);
6059 pfomask &= ~(1 << j);
6066 assert_operand_cnt(2);
6067 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6068 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6069 if (po->op == OP_SBB
6070 && IS(po->operand[0].name, po->operand[1].name))
6072 // avoid use of unitialized var
6073 fprintf(fout, " %s = -cond_c;", buf1);
6074 // carry remains what it was
6075 pfomask &= ~(1 << PFO_C);
6078 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
6079 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6081 output_std_flags(fout, po, &pfomask, buf1);
6082 last_arith_dst = &po->operand[0];
6083 delayed_flag_op = NULL;
6087 assert_operand_cnt(2);
6088 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6089 fprintf(fout, " %s = %s ? __builtin_ffs(%s) - 1 : 0;",
6090 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6092 output_std_flags(fout, po, &pfomask, buf1);
6093 last_arith_dst = &po->operand[0];
6094 delayed_flag_op = NULL;
6095 strcat(g_comment, " bsf");
6099 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
6100 for (j = 0; j <= PFO_LE; j++) {
6101 if (!(pfomask & (1 << j)))
6103 if (j == PFO_Z || j == PFO_S || j == PFO_C)
6106 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0);
6107 fprintf(fout, " cond_%s = %s;\n",
6108 parsed_flag_op_names[j], buf1);
6109 pfomask &= ~(1 << j);
6115 if (pfomask & (1 << PFO_C))
6116 // carry is unaffected by inc/dec.. wtf?
6117 ferr(po, "carry propagation needed\n");
6119 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6120 if (po->operand[0].type == OPT_REG) {
6121 strcpy(buf2, po->op == OP_INC ? "++" : "--");
6122 fprintf(fout, " %s%s;", buf1, buf2);
6125 strcpy(buf2, po->op == OP_INC ? "+" : "-");
6126 fprintf(fout, " %s %s= 1;", buf1, buf2);
6128 output_std_flags(fout, po, &pfomask, buf1);
6129 last_arith_dst = &po->operand[0];
6130 delayed_flag_op = NULL;
6134 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6135 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
6136 fprintf(fout, " %s = -%s%s;", buf1,
6137 lmod_cast_s(po, po->operand[0].lmod), buf2);
6138 last_arith_dst = &po->operand[0];
6139 delayed_flag_op = NULL;
6140 if (pfomask & (1 << PFO_C)) {
6141 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
6142 pfomask &= ~(1 << PFO_C);
6147 if (po->operand_cnt == 2) {
6148 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6151 if (po->operand_cnt == 3)
6152 ferr(po, "TODO imul3\n");
6155 assert_operand_cnt(1);
6156 switch (po->operand[0].lmod) {
6158 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
6159 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
6160 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
6161 fprintf(fout, " edx = tmp64 >> 32;\n");
6162 fprintf(fout, " eax = tmp64;");
6165 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
6166 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
6167 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
6171 ferr(po, "TODO: unhandled mul type\n");
6174 last_arith_dst = NULL;
6175 delayed_flag_op = NULL;
6180 assert_operand_cnt(1);
6181 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6182 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
6183 po->op == OP_IDIV));
6184 switch (po->operand[0].lmod) {
6186 if (po->flags & OPF_32BIT)
6187 snprintf(buf2, sizeof(buf2), "%seax", cast);
6189 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
6190 snprintf(buf2, sizeof(buf2), "%stmp64",
6191 (po->op == OP_IDIV) ? "(s64)" : "");
6193 if (po->operand[0].type == OPT_REG
6194 && po->operand[0].reg == xDX)
6196 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
6197 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
6200 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
6201 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
6205 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
6206 snprintf(buf2, sizeof(buf2), "%stmp",
6207 (po->op == OP_IDIV) ? "(s32)" : "");
6208 if (po->operand[0].type == OPT_REG
6209 && po->operand[0].reg == xDX)
6211 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
6213 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
6217 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
6219 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
6222 strcat(g_comment, " div16");
6225 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
6227 last_arith_dst = NULL;
6228 delayed_flag_op = NULL;
6233 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6235 for (j = 0; j < 8; j++) {
6236 if (pfomask & (1 << j)) {
6237 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
6238 fprintf(fout, " cond_%s = %s;",
6239 parsed_flag_op_names[j], buf1);
6246 last_arith_dst = NULL;
6247 delayed_flag_op = po;
6251 // SETcc - should already be handled
6254 // note: we reuse OP_Jcc for SETcc, only flags differ
6256 fprintf(fout, "\n goto %s;", po->operand[0].name);
6260 fprintf(fout, " if (ecx == 0)\n");
6261 fprintf(fout, " goto %s;", po->operand[0].name);
6262 strcat(g_comment, " jecxz");
6266 fprintf(fout, " if (--ecx != 0)\n");
6267 fprintf(fout, " goto %s;", po->operand[0].name);
6268 strcat(g_comment, " loop");
6272 assert_operand_cnt(1);
6273 last_arith_dst = NULL;
6274 delayed_flag_op = NULL;
6276 if (po->operand[0].type == OPT_REGMEM) {
6277 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
6280 ferr(po, "parse failure for jmp '%s'\n",
6281 po->operand[0].name);
6282 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
6285 else if (po->operand[0].type != OPT_LABEL)
6286 ferr(po, "unhandled jmp type\n");
6288 fprintf(fout, " goto %s;", po->operand[0].name);
6292 assert_operand_cnt(1);
6294 my_assert_not(pp, NULL);
6297 if (po->flags & OPF_CC) {
6298 // we treat conditional branch to another func
6299 // (yes such code exists..) as conditional tailcall
6301 fprintf(fout, " {\n");
6304 if (pp->is_fptr && !pp->is_arg) {
6305 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
6306 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6308 if (pp->is_unresolved)
6309 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
6310 buf3, asmfn, po->asmln, pp->name);
6313 fprintf(fout, "%s", buf3);
6314 if (strstr(pp->ret_type.name, "int64")) {
6315 if (po->flags & OPF_TAIL)
6316 ferr(po, "int64 and tail?\n");
6317 fprintf(fout, "tmp64 = ");
6319 else if (!IS(pp->ret_type.name, "void")) {
6320 if (po->flags & OPF_TAIL) {
6321 if (regmask_ret & mxAX) {
6322 fprintf(fout, "return ");
6323 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
6324 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
6326 else if (regmask_ret & mxST0)
6327 ferr(po, "float tailcall\n");
6329 else if (po->regmask_dst & mxAX) {
6330 fprintf(fout, "eax = ");
6331 if (pp->ret_type.is_ptr)
6332 fprintf(fout, "(u32)");
6334 else if (po->regmask_dst & mxST0) {
6335 fprintf(fout, "f_st0 = ");
6339 if (pp->name[0] == 0)
6340 ferr(po, "missing pp->name\n");
6341 fprintf(fout, "%s%s(", pp->name,
6342 pp->has_structarg ? "_sa" : "");
6344 if (po->flags & OPF_ATAIL) {
6345 if (pp->argc_stack != g_func_pp->argc_stack
6346 || (pp->argc_stack > 0
6347 && pp->is_stdcall != g_func_pp->is_stdcall))
6348 ferr(po, "incompatible tailcall\n");
6349 if (g_func_pp->has_retreg)
6350 ferr(po, "TODO: retreg+tailcall\n");
6352 for (arg = j = 0; arg < pp->argc; arg++) {
6354 fprintf(fout, ", ");
6357 if (pp->arg[arg].type.is_ptr)
6358 snprintf(cast, sizeof(cast), "(%s)",
6359 pp->arg[arg].type.name);
6361 if (pp->arg[arg].reg != NULL) {
6362 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6366 for (; j < g_func_pp->argc; j++)
6367 if (g_func_pp->arg[j].reg == NULL)
6369 fprintf(fout, "%sa%d", cast, j + 1);
6374 for (arg = 0; arg < pp->argc; arg++) {
6376 fprintf(fout, ", ");
6379 if (pp->arg[arg].type.is_ptr)
6380 snprintf(cast, sizeof(cast), "(%s)",
6381 pp->arg[arg].type.name);
6383 if (pp->arg[arg].reg != NULL) {
6384 if (pp->arg[arg].type.is_retreg)
6385 fprintf(fout, "&%s", pp->arg[arg].reg);
6387 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6392 tmp_op = pp->arg[arg].datap;
6394 ferr(po, "parsed_op missing for arg%d\n", arg);
6396 if (tmp_op->flags & OPF_VAPUSH) {
6397 fprintf(fout, "ap");
6399 else if (tmp_op->p_argpass != 0) {
6400 fprintf(fout, "a%d", tmp_op->p_argpass);
6402 else if (tmp_op->p_argnum != 0) {
6403 fprintf(fout, "%s%s", cast,
6404 saved_arg_name(buf1, sizeof(buf1),
6405 tmp_op->p_arggrp, tmp_op->p_argnum));
6409 out_src_opr(buf1, sizeof(buf1),
6410 tmp_op, &tmp_op->operand[0], cast, 0));
6414 fprintf(fout, ");");
6416 if (strstr(pp->ret_type.name, "int64")) {
6417 fprintf(fout, "\n");
6418 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
6419 fprintf(fout, "%seax = tmp64;", buf3);
6422 if (pp->is_unresolved) {
6423 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
6425 strcat(g_comment, buf2);
6428 if (po->flags & OPF_TAIL) {
6430 if (i == opcnt - 1 || pp->is_noreturn)
6432 else if (IS(pp->ret_type.name, "void"))
6434 else if (!(regmask_ret & (1 << xAX)))
6436 // else already handled as 'return f()'
6439 fprintf(fout, "\n%sreturn;", buf3);
6440 strcat(g_comment, " ^ tailcall");
6443 strcat(g_comment, " tailcall");
6445 if ((regmask_ret & (1 << xAX))
6446 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
6448 ferr(po, "int func -> void func tailcall?\n");
6451 if (pp->is_noreturn)
6452 strcat(g_comment, " noreturn");
6453 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
6454 strcat(g_comment, " argframe");
6455 if (po->flags & OPF_CC)
6456 strcat(g_comment, " cond");
6458 if (po->flags & OPF_CC)
6459 fprintf(fout, "\n }");
6461 delayed_flag_op = NULL;
6462 last_arith_dst = NULL;
6466 if (g_func_pp->is_vararg)
6467 fprintf(fout, " va_end(ap);\n");
6468 if (g_func_pp->has_retreg) {
6469 for (arg = 0; arg < g_func_pp->argc; arg++)
6470 if (g_func_pp->arg[arg].type.is_retreg)
6471 fprintf(fout, " *r_%s = %s;\n",
6472 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
6475 if (!(regmask_ret & (1 << xAX))) {
6476 if (i != opcnt - 1 || label_pending)
6477 fprintf(fout, " return;");
6479 else if (g_func_pp->ret_type.is_ptr) {
6480 fprintf(fout, " return (%s)eax;",
6481 g_func_pp->ret_type.name);
6483 else if (IS(g_func_pp->ret_type.name, "__int64"))
6484 fprintf(fout, " return ((u64)edx << 32) | eax;");
6486 fprintf(fout, " return eax;");
6488 last_arith_dst = NULL;
6489 delayed_flag_op = NULL;
6493 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6494 if (po->p_argnum != 0) {
6495 // special case - saved func arg
6496 fprintf(fout, " %s = %s;",
6497 saved_arg_name(buf2, sizeof(buf2),
6498 po->p_arggrp, po->p_argnum), buf1);
6501 else if (po->flags & OPF_RSAVE) {
6502 fprintf(fout, " s_%s = %s;", buf1, buf1);
6505 else if (po->flags & OPF_PPUSH) {
6507 ferr_assert(po, tmp_op != NULL);
6508 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
6509 fprintf(fout, " pp_%s = %s;", buf2, buf1);
6512 else if (g_func_pp->is_userstack) {
6513 fprintf(fout, " *(--esp) = %s;", buf1);
6516 if (!(g_ida_func_attr & IDAFA_NORETURN))
6517 ferr(po, "stray push encountered\n");
6522 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6523 if (po->flags & OPF_RSAVE) {
6524 fprintf(fout, " %s = s_%s;", buf1, buf1);
6527 else if (po->flags & OPF_PPUSH) {
6528 // push/pop graph / non-const
6529 ferr_assert(po, po->datap == NULL);
6530 fprintf(fout, " %s = pp_%s;", buf1, buf1);
6533 else if (po->datap != NULL) {
6536 fprintf(fout, " %s = %s;", buf1,
6537 out_src_opr(buf2, sizeof(buf2),
6538 tmp_op, &tmp_op->operand[0],
6539 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6542 else if (g_func_pp->is_userstack) {
6543 fprintf(fout, " %s = *esp++;", buf1);
6547 ferr(po, "stray pop encountered\n");
6556 if (po->flags & OPF_FSHIFT)
6557 fprintf(fout, " f_st1 = f_st0;\n");
6558 if (po->operand[0].type == OPT_REG
6559 && po->operand[0].reg == xST0)
6561 strcat(g_comment, " fld st");
6564 fprintf(fout, " f_st0 = %s;",
6565 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0]));
6566 strcat(g_comment, " fld");
6570 if (po->flags & OPF_FSHIFT)
6571 fprintf(fout, " f_st1 = f_st0;\n");
6572 fprintf(fout, " f_st0 = (double)%s;",
6573 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6574 lmod_cast(po, po->operand[0].lmod, 1), 0));
6575 strcat(g_comment, " fild");
6579 if (po->flags & OPF_FSHIFT)
6580 fprintf(fout, " f_st1 = f_st0;\n");
6581 fprintf(fout, " f_st0 = ");
6582 switch (po->operand[0].val) {
6583 case X87_CONST_1: fprintf(fout, "1.0;"); break;
6584 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
6585 default: ferr(po, "TODO\n"); break;
6590 if ((po->flags & OPF_FPOP) && po->operand[0].type == OPT_REG
6591 && po->operand[0].reg == xST0)
6596 fprintf(fout, " %s = f_st0;",
6597 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0]));
6598 if (po->flags & OPF_FSHIFT)
6599 fprintf(fout, "\n f_st0 = f_st1;");
6600 strcat(g_comment, " fst");
6608 case OP_FADD: j = '+'; break;
6609 case OP_FDIV: j = '/'; break;
6610 case OP_FMUL: j = '*'; break;
6611 case OP_FSUB: j = '-'; break;
6612 default: j = 'x'; break;
6614 if (po->flags & OPF_FSHIFT) {
6615 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
6618 fprintf(fout, " %s %c= %s;",
6619 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0]),
6621 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1]));
6627 if (po->flags & OPF_FSHIFT)
6628 snprintf(buf1, sizeof(buf1), "f_st0");
6630 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0]);
6631 fprintf(fout, " %s = %s %c %s;", buf1,
6632 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1]),
6633 po->op == OP_FDIVR ? '/' : '-',
6634 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0]));
6642 case OP_FIADD: j = '+'; break;
6643 case OP_FIDIV: j = '/'; break;
6644 case OP_FIMUL: j = '*'; break;
6645 case OP_FISUB: j = '-'; break;
6646 default: j = 'x'; break;
6648 fprintf(fout, " f_st0 %c= (double)%s;", j,
6649 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6650 lmod_cast(po, po->operand[0].lmod, 1), 0));
6655 fprintf(fout, " f_st0 = %s %c f_st0;",
6656 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1]),
6657 po->op == OP_FIDIVR ? '/' : '-');
6661 ferr_assert(po, po->flags & OPF_32BIT);
6662 fprintf(fout, " eax = (s32)f_st0;");
6663 if (po->flags & OPF_FSHIFT)
6664 fprintf(fout, "\n f_st0 = f_st1;");
6665 strcat(g_comment, " ftol");
6670 strcpy(g_comment, " (emms)");
6675 ferr(po, "unhandled op type %d, flags %x\n",
6680 if (g_comment[0] != 0) {
6681 char *p = g_comment;
6682 while (my_isblank(*p))
6684 fprintf(fout, " // %s", p);
6689 fprintf(fout, "\n");
6691 // some sanity checking
6692 if (po->flags & OPF_REP) {
6693 if (po->op != OP_STOS && po->op != OP_MOVS
6694 && po->op != OP_CMPS && po->op != OP_SCAS)
6695 ferr(po, "unexpected rep\n");
6696 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
6697 && (po->op == OP_CMPS || po->op == OP_SCAS))
6698 ferr(po, "cmps/scas with plain rep\n");
6700 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
6701 && po->op != OP_CMPS && po->op != OP_SCAS)
6702 ferr(po, "unexpected repz/repnz\n");
6705 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
6707 // see is delayed flag stuff is still valid
6708 if (delayed_flag_op != NULL && delayed_flag_op != po) {
6709 if (is_any_opr_modified(delayed_flag_op, po, 0))
6710 delayed_flag_op = NULL;
6713 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
6714 if (is_opr_modified(last_arith_dst, po))
6715 last_arith_dst = NULL;
6721 if (g_stack_fsz && !g_stack_frame_used)
6722 fprintf(fout, " (void)sf;\n");
6724 fprintf(fout, "}\n\n");
6726 gen_x_cleanup(opcnt);
6729 static void gen_x_cleanup(int opcnt)
6733 for (i = 0; i < opcnt; i++) {
6734 struct label_ref *lr, *lr_del;
6736 lr = g_label_refs[i].next;
6737 while (lr != NULL) {
6742 g_label_refs[i].i = -1;
6743 g_label_refs[i].next = NULL;
6745 if (ops[i].op == OP_CALL) {
6747 proto_release(ops[i].pp);
6753 struct func_proto_dep;
6755 struct func_prototype {
6760 int has_ret:3; // -1, 0, 1: unresolved, no, yes
6761 unsigned int dep_resolved:1;
6762 unsigned int is_stdcall:1;
6763 struct func_proto_dep *dep_func;
6765 const struct parsed_proto *pp; // seed pp, if any
6768 struct func_proto_dep {
6770 struct func_prototype *proto;
6771 int regmask_live; // .. at the time of call
6772 unsigned int ret_dep:1; // return from this is caller's return
6775 static struct func_prototype *hg_fp;
6776 static int hg_fp_cnt;
6778 static struct scanned_var {
6780 enum opr_lenmod lmod;
6781 unsigned int is_seeded:1;
6782 unsigned int is_c_str:1;
6783 const struct parsed_proto *pp; // seed pp, if any
6785 static int hg_var_cnt;
6787 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
6790 struct func_prototype *hg_fp_add(const char *funcn)
6792 struct func_prototype *fp;
6794 if ((hg_fp_cnt & 0xff) == 0) {
6795 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
6796 my_assert_not(hg_fp, NULL);
6797 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
6800 fp = &hg_fp[hg_fp_cnt];
6801 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
6803 fp->argc_stack = -1;
6809 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
6814 for (i = 0; i < fp->dep_func_cnt; i++)
6815 if (IS(fp->dep_func[i].name, name))
6816 return &fp->dep_func[i];
6821 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
6824 if (hg_fp_find_dep(fp, name))
6827 if ((fp->dep_func_cnt & 0xff) == 0) {
6828 fp->dep_func = realloc(fp->dep_func,
6829 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
6830 my_assert_not(fp->dep_func, NULL);
6831 memset(&fp->dep_func[fp->dep_func_cnt], 0,
6832 sizeof(fp->dep_func[0]) * 0x100);
6834 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
6838 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
6840 const struct func_prototype *p1 = p1_, *p2 = p2_;
6841 return strcmp(p1->name, p2->name);
6845 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
6847 const struct func_prototype *p1 = p1_, *p2 = p2_;
6848 return p1->id - p2->id;
6852 // recursive register dep pass
6853 // - track saved regs (part 2)
6854 // - try to figure out arg-regs
6855 // - calculate reg deps
6856 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
6857 struct func_prototype *fp, int regmask_save, int regmask_dst,
6858 int *regmask_dep, int *has_ret)
6860 struct func_proto_dep *dep;
6861 struct parsed_op *po;
6862 int from_caller = 0;
6867 for (; i < opcnt; i++)
6869 if (cbits[i >> 3] & (1 << (i & 7)))
6871 cbits[i >> 3] |= (1 << (i & 7));
6875 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
6876 if (po->flags & OPF_RMD)
6879 if (po->btj != NULL) {
6881 for (j = 0; j < po->btj->count; j++) {
6882 check_i(po, po->btj->d[j].bt_i);
6883 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
6884 regmask_save, regmask_dst, regmask_dep, has_ret);
6889 check_i(po, po->bt_i);
6890 if (po->flags & OPF_CJMP) {
6891 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
6892 regmask_save, regmask_dst, regmask_dep, has_ret);
6900 if (po->flags & OPF_FARG)
6901 /* (just calculate register deps) */;
6902 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
6904 reg = po->operand[0].reg;
6905 ferr_assert(po, reg >= 0);
6907 if (po->flags & OPF_RSAVE) {
6908 regmask_save |= 1 << reg;
6911 if (po->flags & OPF_DONE)
6914 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0);
6916 regmask_save |= 1 << reg;
6917 po->flags |= OPF_RMD;
6918 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, OPF_RMD);
6922 else if (po->flags & OPF_RMD)
6924 else if (po->op == OP_CALL) {
6925 po->regmask_dst |= 1 << xAX;
6927 dep = hg_fp_find_dep(fp, po->operand[0].name);
6929 dep->regmask_live = regmask_save | regmask_dst;
6931 else if (po->op == OP_RET) {
6932 if (po->operand_cnt > 0) {
6934 if (fp->argc_stack >= 0
6935 && fp->argc_stack != po->operand[0].val / 4)
6936 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
6937 fp->argc_stack = po->operand[0].val / 4;
6941 // if has_ret is 0, there is uninitialized eax path,
6942 // which means it's most likely void func
6943 if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
6944 if (po->op == OP_CALL) {
6949 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
6952 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
6955 if (ret != 1 && from_caller) {
6956 // unresolved eax - probably void func
6960 if (j >= 0 && ops[j].op == OP_CALL) {
6961 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
6972 l = regmask_save | regmask_dst;
6973 if (g_bp_frame && !(po->flags & OPF_EBP_S))
6976 l = po->regmask_src & ~l;
6979 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
6980 l, regmask_dst, regmask_save, po->flags);
6983 regmask_dst |= po->regmask_dst;
6985 if (po->flags & OPF_TAIL)
6990 static void gen_hdr(const char *funcn, int opcnt)
6992 int save_arg_vars[MAX_ARG_GRP] = { 0, };
6993 unsigned char cbits[MAX_OPS / 8];
6994 const struct parsed_proto *pp_c;
6995 struct parsed_proto *pp;
6996 struct func_prototype *fp;
6997 struct parsed_op *po;
6998 int regmask_dummy = 0;
7000 int max_bp_offset = 0;
7005 pp_c = proto_parse(g_fhdr, funcn, 1);
7007 // already in seed, will add to hg_fp later
7010 fp = hg_fp_add(funcn);
7012 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
7013 g_stack_frame_used = 0;
7016 // - resolve all branches
7017 // - parse calls with labels
7018 resolve_branches_parse_calls(opcnt);
7021 // - handle ebp/esp frame, remove ops related to it
7022 scan_prologue_epilogue(opcnt);
7025 // - remove dead labels
7027 for (i = 0; i < opcnt; i++)
7029 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7035 if (po->flags & (OPF_RMD|OPF_DONE))
7038 if (po->op == OP_CALL) {
7039 if (po->operand[0].type == OPT_LABEL)
7040 hg_fp_add_dep(fp, opr_name(po, 0));
7041 else if (po->pp != NULL)
7042 hg_fp_add_dep(fp, po->pp->name);
7047 // - remove dead labels
7048 // - handle push <const>/pop pairs
7049 for (i = 0; i < opcnt; i++)
7051 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7057 if (po->flags & (OPF_RMD|OPF_DONE))
7060 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
7061 scan_for_pop_const(i, opcnt, i + opcnt * 13);
7065 // - process trivial calls
7066 for (i = 0; i < opcnt; i++)
7069 if (po->flags & (OPF_RMD|OPF_DONE))
7072 if (po->op == OP_CALL)
7074 pp = process_call_early(i, opcnt, &j);
7076 if (!(po->flags & OPF_ATAIL))
7077 // since we know the args, try to collect them
7078 if (collect_call_args_early(po, i, pp, ®mask_dummy) != 0)
7084 // commit esp adjust
7085 if (ops[j].op != OP_POP)
7086 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
7088 for (l = 0; l < pp->argc_stack; l++)
7089 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
7093 po->flags |= OPF_DONE;
7099 // - track saved regs (simple)
7101 for (i = 0; i < opcnt; i++)
7104 if (po->flags & (OPF_RMD|OPF_DONE))
7107 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
7108 && po->operand[0].reg != xCX)
7110 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
7112 // regmask_save |= 1 << po->operand[0].reg; // do it later
7113 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
7114 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
7117 else if (po->op == OP_CALL)
7119 pp = process_call(i, opcnt);
7121 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
7122 // since we know the args, collect them
7123 ret = collect_call_args(po, i, pp, ®mask_dummy, save_arg_vars,
7130 memset(cbits, 0, sizeof(cbits));
7134 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, ®mask_dep, &has_ret);
7136 // find unreachable code - must be fixed in IDA
7137 for (i = 0; i < opcnt; i++)
7139 if (cbits[i >> 3] & (1 << (i & 7)))
7142 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
7143 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
7145 // the compiler sometimes still generates code after
7146 // noreturn OS functions
7149 if (ops[i].op != OP_NOP)
7150 ferr(&ops[i], "unreachable code\n");
7153 for (i = 0; i < g_eqcnt; i++) {
7154 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
7155 max_bp_offset = g_eqs[i].offset;
7158 if (fp->argc_stack < 0) {
7159 max_bp_offset = (max_bp_offset + 3) & ~3;
7160 fp->argc_stack = max_bp_offset / 4;
7161 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
7165 fp->regmask_dep = regmask_dep & ~(1 << xSP);
7166 fp->has_ret = has_ret;
7168 printf("// has_ret %d, regmask_dep %x\n",
7169 fp->has_ret, fp->regmask_dep);
7170 output_hdr_fp(stdout, fp, 1);
7171 if (IS(funcn, "sub_10007F72")) exit(1);
7174 gen_x_cleanup(opcnt);
7177 static void hg_fp_resolve_deps(struct func_prototype *fp)
7179 struct func_prototype fp_s;
7183 // this thing is recursive, so mark first..
7184 fp->dep_resolved = 1;
7186 for (i = 0; i < fp->dep_func_cnt; i++) {
7187 strcpy(fp_s.name, fp->dep_func[i].name);
7188 fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
7189 sizeof(hg_fp[0]), hg_fp_cmp_name);
7190 if (fp->dep_func[i].proto != NULL) {
7191 if (!fp->dep_func[i].proto->dep_resolved)
7192 hg_fp_resolve_deps(fp->dep_func[i].proto);
7194 dep = ~fp->dep_func[i].regmask_live
7195 & fp->dep_func[i].proto->regmask_dep;
7196 fp->regmask_dep |= dep;
7197 // printf("dep %s %s |= %x\n", fp->name,
7198 // fp->dep_func[i].name, dep);
7200 if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
7201 fp->has_ret = fp->dep_func[i].proto->has_ret;
7206 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7209 const struct parsed_proto *pp;
7210 char *p, namebuf[NAMELEN];
7216 for (; count > 0; count--, fp++) {
7217 if (fp->has_ret == -1)
7218 fprintf(fout, "// ret unresolved\n");
7220 fprintf(fout, "// dep:");
7221 for (j = 0; j < fp->dep_func_cnt; j++) {
7222 fprintf(fout, " %s/", fp->dep_func[j].name);
7223 if (fp->dep_func[j].proto != NULL)
7224 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
7225 fp->dep_func[j].proto->has_ret);
7227 fprintf(fout, "\n");
7230 p = strchr(fp->name, '@');
7232 memcpy(namebuf, fp->name, p - fp->name);
7233 namebuf[p - fp->name] = 0;
7241 pp = proto_parse(g_fhdr, name, 1);
7242 if (pp != NULL && pp->is_include)
7245 if (fp->pp != NULL) {
7246 // part of seed, output later
7250 regmask_dep = fp->regmask_dep;
7251 argc_stack = fp->argc_stack;
7253 fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
7254 (fp->has_ret ? "int" : "void"));
7255 if (regmask_dep && (fp->is_stdcall || argc_stack == 0)
7256 && (regmask_dep & ~((1 << xCX) | (1 << xDX))) == 0)
7258 fprintf(fout, " __fastcall ");
7259 if (!(regmask_dep & (1 << xDX)) && argc_stack == 0)
7265 else if (regmask_dep && !fp->is_stdcall) {
7266 fprintf(fout, "/*__usercall*/ ");
7268 else if (regmask_dep) {
7269 fprintf(fout, "/*__userpurge*/ ");
7271 else if (fp->is_stdcall)
7272 fprintf(fout, " __stdcall ");
7274 fprintf(fout, " __cdecl ");
7276 fprintf(fout, "%s(", name);
7279 for (j = 0; j < xSP; j++) {
7280 if (regmask_dep & (1 << j)) {
7283 fprintf(fout, ", ");
7285 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
7287 fprintf(fout, "int");
7288 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
7292 for (j = 0; j < argc_stack; j++) {
7295 fprintf(fout, ", ");
7296 if (fp->pp != NULL) {
7297 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
7298 if (!fp->pp->arg[arg - 1].type.is_ptr)
7302 fprintf(fout, "int ");
7303 fprintf(fout, "a%d", arg);
7306 fprintf(fout, ");\n");
7310 static void output_hdr(FILE *fout)
7312 static const char *lmod_c_names[] = {
7313 [OPLM_UNSPEC] = "???",
7314 [OPLM_BYTE] = "uint8_t",
7315 [OPLM_WORD] = "uint16_t",
7316 [OPLM_DWORD] = "uint32_t",
7317 [OPLM_QWORD] = "uint64_t",
7319 const struct scanned_var *var;
7320 struct func_prototype *fp;
7321 char line[256] = { 0, };
7325 // add stuff from headers
7326 for (i = 0; i < pp_cache_size; i++) {
7327 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
7328 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
7330 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
7331 fp = hg_fp_add(name);
7332 fp->pp = &pp_cache[i];
7333 fp->argc_stack = fp->pp->argc_stack;
7334 fp->is_stdcall = fp->pp->is_stdcall;
7335 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
7336 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
7340 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
7341 for (i = 0; i < hg_fp_cnt; i++)
7342 hg_fp_resolve_deps(&hg_fp[i]);
7344 // note: messes up .proto ptr, don't use
7345 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
7348 for (i = 0; i < hg_var_cnt; i++) {
7351 if (var->pp != NULL)
7354 else if (var->is_c_str)
7355 fprintf(fout, "extern %-8s %s[];", "char", var->name);
7357 fprintf(fout, "extern %-8s %s;",
7358 lmod_c_names[var->lmod], var->name);
7361 fprintf(fout, " // seeded");
7362 fprintf(fout, "\n");
7365 fprintf(fout, "\n");
7367 // output function prototypes
7368 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
7371 fprintf(fout, "\n// - seed -\n");
7374 while (fgets(line, sizeof(line), g_fhdr))
7375 fwrite(line, 1, strlen(line), fout);
7378 // '=' needs special treatment
7380 static char *next_word_s(char *w, size_t wsize, char *s)
7389 for (i = 1; i < wsize - 1; i++) {
7391 printf("warning: missing closing quote: \"%s\"\n", s);
7400 for (; i < wsize - 1; i++) {
7401 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
7407 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
7408 printf("warning: '%s' truncated\n", w);
7413 static int cmpstringp(const void *p1, const void *p2)
7415 return strcmp(*(char * const *)p1, *(char * const *)p2);
7418 static int is_xref_needed(char *p, char **rlist, int rlist_len)
7423 if (strstr(p, "..."))
7424 // unable to determine, assume needed
7427 if (*p == '.') // .text, .data, ...
7428 // ref from other data or non-function -> no
7431 p2 = strpbrk(p, "+:\r\n\x18");
7434 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
7435 // referenced from removed code
7441 static int xrefs_show_need(FILE *fasm, char *p,
7442 char **rlist, int rlist_len)
7448 p = strrchr(p, ';');
7449 if (p != NULL && *p == ';' && IS_START(p + 2, "DATA XREF: ")) {
7451 if (is_xref_needed(p, rlist, rlist_len))
7458 if (!my_fgets(line, sizeof(line), fasm))
7460 // non-first line is always indented
7461 if (!my_isblank(line[0]))
7464 // should be no content, just comment
7469 p = strrchr(p, ';');
7471 // it's printed once, but no harm to check again
7472 if (IS_START(p, "DATA XREF: "))
7475 if (is_xref_needed(p, rlist, rlist_len)) {
7480 fseek(fasm, pos, SEEK_SET);
7484 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
7486 struct scanned_var *var;
7487 char line[256] = { 0, };
7495 // skip to next data section
7496 while (my_fgets(line, sizeof(line), fasm))
7501 if (*p == 0 || *p == ';')
7504 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
7505 if (*p == 0 || *p == ';')
7508 if (*p != 's' || !IS_START(p, "segment para public"))
7514 if (p == NULL || !IS_START(p, "segment para public"))
7518 if (!IS_START(p, "'DATA'"))
7522 while (my_fgets(line, sizeof(line), fasm))
7531 if (*p == 0 || *p == ';')
7534 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
7535 words[wordc][0] = 0;
7536 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
7537 if (*p == 0 || *p == ';') {
7543 if (wordc == 2 && IS(words[1], "ends"))
7548 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
7549 // when this starts, we don't need anything from this section
7553 // check refs comment(s)
7554 if (!xrefs_show_need(fasm, p, rlist, rlist_len))
7557 if ((hg_var_cnt & 0xff) == 0) {
7558 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
7559 * (hg_var_cnt + 0x100));
7560 my_assert_not(hg_vars, NULL);
7561 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
7564 var = &hg_vars[hg_var_cnt++];
7565 snprintf(var->name, sizeof(var->name), "%s", words[0]);
7567 // maybe already in seed header?
7568 var->pp = proto_parse(g_fhdr, var->name, 1);
7569 if (var->pp != NULL) {
7570 if (var->pp->is_fptr) {
7571 var->lmod = OPLM_DWORD;
7574 else if (var->pp->is_func)
7576 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
7577 aerr("unhandled C type '%s' for '%s'\n",
7578 var->pp->type.name, var->name);
7584 if (IS(words[1], "dd"))
7585 var->lmod = OPLM_DWORD;
7586 else if (IS(words[1], "dw"))
7587 var->lmod = OPLM_WORD;
7588 else if (IS(words[1], "db")) {
7589 var->lmod = OPLM_BYTE;
7590 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
7591 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
7595 else if (IS(words[1], "dq"))
7596 var->lmod = OPLM_QWORD;
7597 //else if (IS(words[1], "dt"))
7599 aerr("type '%s' not known\n", words[1]);
7607 static void set_label(int i, const char *name)
7613 p = strchr(name, ':');
7617 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
7618 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
7619 g_labels[i] = realloc(g_labels[i], len + 1);
7620 my_assert_not(g_labels[i], NULL);
7621 memcpy(g_labels[i], name, len);
7622 g_labels[i][len] = 0;
7631 static struct chunk_item *func_chunks;
7632 static int func_chunk_cnt;
7633 static int func_chunk_alloc;
7635 static void add_func_chunk(FILE *fasm, const char *name, int line)
7637 if (func_chunk_cnt >= func_chunk_alloc) {
7638 func_chunk_alloc *= 2;
7639 func_chunks = realloc(func_chunks,
7640 func_chunk_alloc * sizeof(func_chunks[0]));
7641 my_assert_not(func_chunks, NULL);
7643 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
7644 func_chunks[func_chunk_cnt].name = strdup(name);
7645 func_chunks[func_chunk_cnt].asmln = line;
7649 static int cmp_chunks(const void *p1, const void *p2)
7651 const struct chunk_item *c1 = p1, *c2 = p2;
7652 return strcmp(c1->name, c2->name);
7655 static void scan_ahead(FILE *fasm)
7665 oldpos = ftell(fasm);
7668 while (my_fgets(line, sizeof(line), fasm))
7679 // get rid of random tabs
7680 for (i = 0; line[i] != 0; i++)
7681 if (line[i] == '\t')
7684 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
7687 next_word(words[0], sizeof(words[0]), p);
7688 if (words[0][0] == 0)
7689 aerr("missing name for func chunk?\n");
7691 add_func_chunk(fasm, words[0], asmln);
7693 else if (IS_START(p, "; sctend"))
7699 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
7700 words[wordc][0] = 0;
7701 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
7702 if (*p == 0 || *p == ';') {
7708 if (wordc == 2 && IS(words[1], "ends"))
7712 fseek(fasm, oldpos, SEEK_SET);
7716 int main(int argc, char *argv[])
7718 FILE *fout, *fasm, *frlist;
7719 struct parsed_data *pd = NULL;
7721 char **rlist = NULL;
7723 int rlist_alloc = 0;
7724 int func_chunks_used = 0;
7725 int func_chunks_sorted = 0;
7726 int func_chunk_i = -1;
7727 long func_chunk_ret = 0;
7728 int func_chunk_ret_ln = 0;
7729 int scanned_ahead = 0;
7731 char words[20][256];
7732 enum opr_lenmod lmod;
7733 char *sctproto = NULL;
7735 int pending_endp = 0;
7737 int skip_warned = 0;
7750 for (arg = 1; arg < argc; arg++) {
7751 if (IS(argv[arg], "-v"))
7753 else if (IS(argv[arg], "-rf"))
7754 g_allow_regfunc = 1;
7755 else if (IS(argv[arg], "-m"))
7757 else if (IS(argv[arg], "-hdr"))
7758 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
7763 if (argc < arg + 3) {
7764 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
7765 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
7767 " -hdr - header generation mode\n"
7768 " -rf - allow unannotated indirect calls\n"
7769 " -m - allow multiple .text sections\n"
7770 "[rlist] is a file with function names to skip,"
7778 asmfn = argv[arg++];
7779 fasm = fopen(asmfn, "r");
7780 my_assert_not(fasm, NULL);
7782 hdrfn = argv[arg++];
7783 g_fhdr = fopen(hdrfn, "r");
7784 my_assert_not(g_fhdr, NULL);
7787 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
7788 my_assert_not(rlist, NULL);
7789 // needs special handling..
7790 rlist[rlist_len++] = "__alloca_probe";
7792 func_chunk_alloc = 32;
7793 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
7794 my_assert_not(func_chunks, NULL);
7796 memset(words, 0, sizeof(words));
7798 for (; arg < argc; arg++) {
7799 frlist = fopen(argv[arg], "r");
7800 my_assert_not(frlist, NULL);
7802 while (my_fgets(line, sizeof(line), frlist)) {
7804 if (*p == 0 || *p == ';')
7807 if (IS_START(p, "#if 0")
7808 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
7812 else if (IS_START(p, "#endif"))
7819 p = next_word(words[0], sizeof(words[0]), p);
7820 if (words[0][0] == 0)
7823 if (rlist_len >= rlist_alloc) {
7824 rlist_alloc = rlist_alloc * 2 + 64;
7825 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
7826 my_assert_not(rlist, NULL);
7828 rlist[rlist_len++] = strdup(words[0]);
7837 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
7839 fout = fopen(argv[arg_out], "w");
7840 my_assert_not(fout, NULL);
7843 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
7844 my_assert_not(g_eqs, NULL);
7846 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
7847 g_label_refs[i].i = -1;
7848 g_label_refs[i].next = NULL;
7852 scan_variables(fasm, rlist, rlist_len);
7854 while (my_fgets(line, sizeof(line), fasm))
7863 // get rid of random tabs
7864 for (i = 0; line[i] != 0; i++)
7865 if (line[i] == '\t')
7870 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
7871 goto do_pending_endp; // eww..
7873 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
7875 static const char *attrs[] = {
7884 // parse IDA's attribute-list comment
7885 g_ida_func_attr = 0;
7888 for (; *p != 0; p = sskip(p)) {
7889 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
7890 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
7891 g_ida_func_attr |= 1 << i;
7892 p += strlen(attrs[i]);
7896 if (i == ARRAY_SIZE(attrs)) {
7897 anote("unparsed IDA attr: %s\n", p);
7900 if (IS(attrs[i], "fpd=")) {
7901 p = next_word(words[0], sizeof(words[0]), p);
7906 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
7908 static const char *attrs[] = {
7912 // parse manual attribute-list comment
7913 g_sct_func_attr = 0;
7916 for (; *p != 0; p = sskip(p)) {
7917 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
7918 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
7919 g_sct_func_attr |= 1 << i;
7920 p += strlen(attrs[i]);
7924 if (i == 0 && *p == '=') {
7925 // clear_sf=start,len (in dwords)
7926 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
7927 &g_stack_clear_len, &j);
7929 anote("unparsed clear_sf attr value: %s\n", p);
7934 else if (i == ARRAY_SIZE(attrs)) {
7935 anote("unparsed sct attr: %s\n", p);
7940 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
7943 next_word(words[0], sizeof(words[0]), p);
7944 if (words[0][0] == 0)
7945 aerr("missing name for func chunk?\n");
7947 if (!scanned_ahead) {
7948 add_func_chunk(fasm, words[0], asmln);
7949 func_chunks_sorted = 0;
7952 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
7954 if (func_chunk_i >= 0) {
7955 if (func_chunk_i < func_chunk_cnt
7956 && IS(func_chunks[func_chunk_i].name, g_func))
7958 // move on to next chunk
7959 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
7961 aerr("seek failed for '%s' chunk #%d\n",
7962 g_func, func_chunk_i);
7963 asmln = func_chunks[func_chunk_i].asmln;
7967 if (func_chunk_ret == 0)
7968 aerr("no return from chunk?\n");
7969 fseek(fasm, func_chunk_ret, SEEK_SET);
7970 asmln = func_chunk_ret_ln;
7976 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
7977 func_chunks_used = 1;
7979 if (IS_START(g_func, "sub_")) {
7980 unsigned long addr = strtoul(p, NULL, 16);
7981 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
7982 if (addr > f_addr && !scanned_ahead) {
7983 //anote("scan_ahead caused by '%s', addr %lx\n",
7987 func_chunks_sorted = 0;
7995 for (i = wordc; i < ARRAY_SIZE(words); i++)
7997 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
7998 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
7999 if (*p == 0 || *p == ';') {
8004 if (*p != 0 && *p != ';')
8005 aerr("too many words\n");
8007 // alow asm patches in comments
8009 if (IS_START(p, "; sctpatch:")) {
8011 if (*p == 0 || *p == ';')
8013 goto parse_words; // lame
8015 if (IS_START(p, "; sctproto:")) {
8016 sctproto = strdup(p + 11);
8018 else if (IS_START(p, "; sctend")) {
8027 awarn("wordc == 0?\n");
8031 // don't care about this:
8032 if (words[0][0] == '.'
8033 || IS(words[0], "include")
8034 || IS(words[0], "assume") || IS(words[1], "segment")
8035 || IS(words[0], "align"))
8041 // do delayed endp processing to collect switch jumptables
8043 if (in_func && !g_skip_func && !end && wordc >= 2
8044 && ((words[0][0] == 'd' && words[0][2] == 0)
8045 || (words[1][0] == 'd' && words[1][2] == 0)))
8048 if (words[1][0] == 'd' && words[1][2] == 0) {
8050 if (g_func_pd_cnt >= pd_alloc) {
8051 pd_alloc = pd_alloc * 2 + 16;
8052 g_func_pd = realloc(g_func_pd,
8053 sizeof(g_func_pd[0]) * pd_alloc);
8054 my_assert_not(g_func_pd, NULL);
8056 pd = &g_func_pd[g_func_pd_cnt];
8058 memset(pd, 0, sizeof(*pd));
8059 strcpy(pd->label, words[0]);
8060 pd->type = OPT_CONST;
8061 pd->lmod = lmod_from_directive(words[1]);
8067 anote("skipping alignment byte?\n");
8070 lmod = lmod_from_directive(words[0]);
8071 if (lmod != pd->lmod)
8072 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
8075 if (pd->count_alloc < pd->count + wordc) {
8076 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
8077 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
8078 my_assert_not(pd->d, NULL);
8080 for (; i < wordc; i++) {
8081 if (IS(words[i], "offset")) {
8082 pd->type = OPT_OFFSET;
8085 p = strchr(words[i], ',');
8088 if (pd->type == OPT_OFFSET)
8089 pd->d[pd->count].u.label = strdup(words[i]);
8091 pd->d[pd->count].u.val = parse_number(words[i]);
8092 pd->d[pd->count].bt_i = -1;
8098 if (in_func && !g_skip_func) {
8100 gen_hdr(g_func, pi);
8102 gen_func(fout, g_fhdr, g_func, pi);
8107 g_ida_func_attr = 0;
8108 g_sct_func_attr = 0;
8109 g_stack_clear_start = 0;
8110 g_stack_clear_len = 0;
8114 func_chunks_used = 0;
8117 memset(&ops, 0, pi * sizeof(ops[0]));
8122 for (i = 0; i < g_func_pd_cnt; i++) {
8124 if (pd->type == OPT_OFFSET) {
8125 for (j = 0; j < pd->count; j++)
8126 free(pd->d[j].u.label);
8141 if (IS(words[1], "proc")) {
8143 aerr("proc '%s' while in_func '%s'?\n",
8146 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8148 strcpy(g_func, words[0]);
8149 set_label(0, words[0]);
8154 if (IS(words[1], "endp"))
8157 aerr("endp '%s' while not in_func?\n", words[0]);
8158 if (!IS(g_func, words[0]))
8159 aerr("endp '%s' while in_func '%s'?\n",
8162 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
8163 && ops[0].op == OP_JMP && ops[0].operand[0].had_ds)
8169 if (!g_skip_func && func_chunks_used) {
8170 // start processing chunks
8171 struct chunk_item *ci, key = { g_func, 0 };
8173 func_chunk_ret = ftell(fasm);
8174 func_chunk_ret_ln = asmln;
8175 if (!func_chunks_sorted) {
8176 qsort(func_chunks, func_chunk_cnt,
8177 sizeof(func_chunks[0]), cmp_chunks);
8178 func_chunks_sorted = 1;
8180 ci = bsearch(&key, func_chunks, func_chunk_cnt,
8181 sizeof(func_chunks[0]), cmp_chunks);
8183 aerr("'%s' needs chunks, but none found\n", g_func);
8184 func_chunk_i = ci - func_chunks;
8185 for (; func_chunk_i > 0; func_chunk_i--)
8186 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
8189 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
8191 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
8192 asmln = func_chunks[func_chunk_i].asmln;
8200 if (wordc == 2 && IS(words[1], "ends")) {
8204 goto do_pending_endp;
8208 // scan for next text segment
8209 while (my_fgets(line, sizeof(line), fasm)) {
8212 if (*p == 0 || *p == ';')
8215 if (strstr(p, "segment para public 'CODE' use32"))
8222 p = strchr(words[0], ':');
8224 set_label(pi, words[0]);
8228 if (!in_func || g_skip_func) {
8229 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
8231 anote("skipping from '%s'\n", g_labels[pi]);
8235 g_labels[pi] = NULL;
8239 if (wordc > 1 && IS(words[1], "="))
8242 aerr("unhandled equ, wc=%d\n", wordc);
8243 if (g_eqcnt >= eq_alloc) {
8245 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
8246 my_assert_not(g_eqs, NULL);
8249 len = strlen(words[0]);
8250 if (len > sizeof(g_eqs[0].name) - 1)
8251 aerr("equ name too long: %d\n", len);
8252 strcpy(g_eqs[g_eqcnt].name, words[0]);
8254 if (!IS(words[3], "ptr"))
8255 aerr("unhandled equ\n");
8256 if (IS(words[2], "dword"))
8257 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
8258 else if (IS(words[2], "word"))
8259 g_eqs[g_eqcnt].lmod = OPLM_WORD;
8260 else if (IS(words[2], "byte"))
8261 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
8262 else if (IS(words[2], "qword"))
8263 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
8265 aerr("bad lmod: '%s'\n", words[2]);
8267 g_eqs[g_eqcnt].offset = parse_number(words[4]);
8272 if (pi >= ARRAY_SIZE(ops))
8273 aerr("too many ops\n");
8275 parse_op(&ops[pi], words, wordc);
8277 ops[pi].datap = sctproto;
8292 // vim:ts=2:shiftwidth=2:expandtab