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)
3461 if (strstr(pp->ret_type.name, "int64"))
3462 return (1 << xAX) | (1 << xDX);
3463 if (IS(pp->ret_type.name, "float")
3464 || IS(pp->ret_type.name, "double"))
3468 if (strcasecmp(pp->ret_type.name, "void") == 0)
3474 static void resolve_branches_parse_calls(int opcnt)
3476 static const struct {
3480 unsigned int regmask_src;
3481 unsigned int regmask_dst;
3483 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3485 const struct parsed_proto *pp_c;
3486 struct parsed_proto *pp;
3487 struct parsed_data *pd;
3488 struct parsed_op *po;
3489 const char *tmpname;
3493 for (i = 0; i < opcnt; i++)
3499 if (po->datap != NULL) {
3500 pp = calloc(1, sizeof(*pp));
3501 my_assert_not(pp, NULL);
3503 ret = parse_protostr(po->datap, pp);
3505 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3511 if (po->op == OP_CALL) {
3516 else if (po->operand[0].type == OPT_LABEL)
3518 tmpname = opr_name(po, 0);
3519 if (IS_START(tmpname, "loc_"))
3520 ferr(po, "call to loc_*\n");
3522 // convert some calls to pseudo-ops
3523 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3524 if (!IS(tmpname, pseudo_ops[l].name))
3527 po->op = pseudo_ops[l].op;
3528 po->operand_cnt = 0;
3529 po->regmask_src = pseudo_ops[l].regmask_src;
3530 po->regmask_dst = pseudo_ops[l].regmask_dst;
3531 po->flags = pseudo_ops[l].flags;
3532 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3535 if (l < ARRAY_SIZE(pseudo_ops))
3538 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3539 if (!g_header_mode && pp_c == NULL)
3540 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3543 pp = proto_clone(pp_c);
3544 my_assert_not(pp, NULL);
3550 check_func_pp(po, pp, "fptr var call");
3551 if (pp->is_noreturn)
3552 po->flags |= OPF_TAIL;
3558 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3561 if (po->operand[0].type == OPT_REGMEM) {
3562 pd = try_resolve_jumptab(i, opcnt);
3570 for (l = 0; l < opcnt; l++) {
3571 if (g_labels[l] != NULL
3572 && IS(po->operand[0].name, g_labels[l]))
3574 if (l == i + 1 && po->op == OP_JMP) {
3575 // yet another alignment type..
3576 po->flags |= OPF_RMD|OPF_DONE;
3579 add_label_ref(&g_label_refs[l], i);
3585 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3588 if (po->operand[0].type == OPT_LABEL)
3592 ferr(po, "unhandled branch\n");
3596 po->flags |= OPF_TAIL;
3597 if (i > 0 && ops[i - 1].op == OP_POP)
3598 po->flags |= OPF_ATAIL;
3603 static void scan_prologue_epilogue(int opcnt)
3605 int ecx_push = 0, esp_sub = 0;
3609 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
3610 && ops[1].op == OP_MOV
3611 && IS(opr_name(&ops[1], 0), "ebp")
3612 && IS(opr_name(&ops[1], 1), "esp"))
3615 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3616 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3619 if (ops[2].op == OP_SUB && IS(opr_name(&ops[2], 0), "esp")) {
3620 g_stack_fsz = opr_const(&ops[2], 1);
3621 ops[2].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3625 // another way msvc builds stack frame..
3627 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3629 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3633 // and another way..
3634 if (i == 2 && ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3635 && ops[i].operand[1].type == OPT_CONST
3636 && ops[i + 1].op == OP_CALL
3637 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3639 g_stack_fsz += ops[i].operand[1].val;
3640 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3642 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3649 for (; i < opcnt; i++)
3650 if (ops[i].flags & OPF_TAIL)
3653 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3654 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3660 if ((ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
3661 || ops[j].op == OP_LEAVE)
3663 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3665 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
3666 && ops[i].pp->is_noreturn)
3668 // on noreturn, msvc sometimes cleans stack, sometimes not
3673 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3674 ferr(&ops[j], "'pop ebp' expected\n");
3676 if (g_stack_fsz != 0) {
3677 if (ops[j].op == OP_LEAVE)
3679 else if (ops[j].op == OP_POP
3680 && ops[j - 1].op == OP_MOV
3681 && IS(opr_name(&ops[j - 1], 0), "esp")
3682 && IS(opr_name(&ops[j - 1], 1), "ebp"))
3684 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3687 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3689 ferr(&ops[j], "esp restore expected\n");
3692 if (ecx_push && j >= 0 && ops[j].op == OP_POP
3693 && IS(opr_name(&ops[j], 0), "ecx"))
3695 ferr(&ops[j], "unexpected ecx pop\n");
3701 } while (i < opcnt);
3704 ferr(ops, "missing ebp epilogue\n");
3710 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3711 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3717 for (; i < opcnt; i++) {
3718 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
3720 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
3721 && ops[i].operand[1].type == OPT_CONST)
3723 g_stack_fsz = ops[i].operand[1].val;
3724 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3730 if (ecx_push && !esp_sub) {
3731 // could actually be args for a call..
3732 for (; i < opcnt; i++)
3733 if (ops[i].op != OP_PUSH)
3736 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
3737 const struct parsed_proto *pp;
3738 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
3739 j = pp ? pp->argc_stack : 0;
3740 while (i > 0 && j > 0) {
3742 if (ops[i].op == OP_PUSH) {
3743 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
3748 ferr(&ops[i], "unhandled prologue\n");
3751 i = g_stack_fsz = ecx_push = 0;
3752 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3753 if (!(ops[i].flags & OPF_RMD))
3763 if (ecx_push || esp_sub)
3769 for (; i < opcnt; i++)
3770 if (ops[i].flags & OPF_TAIL)
3773 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3774 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3781 for (l = 0; l < ecx_push; l++) {
3782 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
3784 else if (ops[j].op == OP_ADD
3785 && IS(opr_name(&ops[j], 0), "esp")
3786 && ops[j].operand[1].type == OPT_CONST)
3789 l += ops[j].operand[1].val / 4 - 1;
3792 ferr(&ops[j], "'pop ecx' expected\n");
3794 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3798 ferr(&ops[j], "epilogue scan failed\n");
3804 if (ops[j].op != OP_ADD
3805 || !IS(opr_name(&ops[j], 0), "esp")
3806 || ops[j].operand[1].type != OPT_CONST
3807 || ops[j].operand[1].val != g_stack_fsz)
3808 ferr(&ops[j], "'add esp' expected\n");
3810 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3811 ops[j].operand[1].val = 0; // hack for stack arg scanner
3816 } while (i < opcnt);
3819 ferr(ops, "missing esp epilogue\n");
3823 // find an instruction that changed opr before i op
3824 // *op_i must be set to -1 by the caller
3825 // *is_caller is set to 1 if one source is determined to be g_func arg
3826 // returns 1 if found, *op_i is then set to origin
3827 // returns -1 if multiple origins are found
3828 static int resolve_origin(int i, const struct parsed_opr *opr,
3829 int magic, int *op_i, int *is_caller)
3831 struct label_ref *lr;
3834 if (ops[i].cc_scratch == magic)
3836 ops[i].cc_scratch = magic;
3839 if (g_labels[i] != NULL) {
3840 lr = &g_label_refs[i];
3841 for (; lr != NULL; lr = lr->next) {
3842 check_i(&ops[i], lr->i);
3843 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
3845 if (i > 0 && LAST_OP(i - 1))
3851 if (is_caller != NULL)
3856 if (ops[i].cc_scratch == magic)
3858 ops[i].cc_scratch = magic;
3860 if (!(ops[i].flags & OPF_DATA))
3862 if (!is_opr_modified(opr, &ops[i]))
3869 // XXX: could check if the other op does the same
3878 // find an instruction that previously referenced opr
3879 // if multiple results are found - fail
3880 // *op_i must be set to -1 by the caller
3881 // returns 1 if found, *op_i is then set to referencer insn
3882 static int resolve_last_ref(int i, const struct parsed_opr *opr,
3883 int magic, int *op_i)
3885 struct label_ref *lr;
3888 if (ops[i].cc_scratch == magic)
3890 ops[i].cc_scratch = magic;
3893 if (g_labels[i] != NULL) {
3894 lr = &g_label_refs[i];
3895 for (; lr != NULL; lr = lr->next) {
3896 check_i(&ops[i], lr->i);
3897 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
3899 if (i > 0 && LAST_OP(i - 1))
3907 if (ops[i].cc_scratch == magic)
3909 ops[i].cc_scratch = magic;
3911 if (!is_opr_referenced(opr, &ops[i]))
3922 // find next instruction that reads opr
3923 // *op_i must be set to -1 by the caller
3924 // on return, *op_i is set to first referencer insn
3925 // returns 1 if exactly 1 referencer is found
3926 static int find_next_read(int i, int opcnt,
3927 const struct parsed_opr *opr, int magic, int *op_i)
3929 struct parsed_op *po;
3932 for (; i < opcnt; i++)
3934 if (ops[i].cc_scratch == magic)
3936 ops[i].cc_scratch = magic;
3939 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3940 if (po->btj != NULL) {
3942 for (j = 0; j < po->btj->count; j++) {
3943 check_i(po, po->btj->d[j].bt_i);
3944 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
3950 if (po->flags & OPF_RMD)
3952 check_i(po, po->bt_i);
3953 if (po->flags & OPF_CJMP) {
3954 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
3963 if (!is_opr_read(opr, po)) {
3964 if (is_opr_modified(opr, po)
3965 && (po->op == OP_CALL
3966 || ((po->flags & OPF_DATA)
3967 && po->operand[0].lmod == OPLM_DWORD)))
3972 if (po->flags & OPF_TAIL)
3987 static int try_resolve_const(int i, const struct parsed_opr *opr,
3988 int magic, unsigned int *val)
3993 ret = resolve_origin(i, opr, magic, &s_i, NULL);
3996 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
3999 *val = ops[i].operand[1].val;
4006 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4007 int *pp_i, int *multi_src)
4009 const struct parsed_proto *pp = NULL;
4010 int search_advice = 0;
4020 switch (ops[i].operand[0].type) {
4022 // try to resolve struct member calls
4023 ret = sscanf(ops[i].operand[0].name, "%3s+%x%n",
4024 s_reg, &offset, &len);
4025 if (ret == 2 && len == strlen(ops[i].operand[0].name))
4027 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4029 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, reg);
4031 ret = resolve_origin(i, &opr, i + opcnt * 19, &j, NULL);
4034 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4035 && ops[j].operand[0].lmod == OPLM_DWORD
4036 && ops[j].pp == NULL) // no hint
4038 // allow one simple dereference (directx)
4039 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4040 ops[j].operand[1].name);
4043 struct parsed_opr opr2 = OPR_INIT(OPT_REG, OPLM_DWORD, reg);
4045 ret = resolve_origin(j, &opr2, j + opcnt * 19, &k, NULL);
4050 if (ops[j].op != OP_MOV)
4052 if (ops[j].operand[0].lmod != OPLM_DWORD)
4054 if (ops[j].pp != NULL) {
4058 else if (ops[j].operand[1].type == OPT_REGMEM) {
4059 // allow 'hello[ecx]' - assume array of same type items
4060 ret = sscanf(ops[j].operand[1].name, "%[^[][e%2s]",
4064 pp = proto_parse(g_fhdr, name, g_quiet_pp);
4066 else if (ops[j].operand[1].type == OPT_LABEL)
4067 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4072 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4076 pp = proto_lookup_struct(g_fhdr, pp->type.name, offset);
4083 pp = try_recover_pp(&ops[i], &ops[i].operand[0], &search_advice);
4088 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4096 static struct parsed_proto *process_call_early(int i, int opcnt,
4099 struct parsed_op *po = &ops[i];
4100 struct parsed_proto *pp;
4106 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4110 // look for and make use of esp adjust
4112 if (!pp->is_stdcall && pp->argc_stack > 0)
4113 ret = scan_for_esp_adjust(i + 1, opcnt,
4114 pp->argc_stack * 4, &adj, &multipath, 0);
4116 if (pp->argc_stack > adj / 4)
4120 if (ops[ret].op == OP_POP) {
4121 for (j = 1; j < adj / 4; j++) {
4122 if (ops[ret + j].op != OP_POP
4123 || ops[ret + j].operand[0].reg != xCX)
4135 static struct parsed_proto *process_call(int i, int opcnt)
4137 struct parsed_op *po = &ops[i];
4138 const struct parsed_proto *pp_c;
4139 struct parsed_proto *pp;
4140 const char *tmpname;
4141 int call_i = -1, ref_i = -1;
4142 int adj = 0, multipath = 0;
4145 tmpname = opr_name(po, 0);
4150 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4152 if (!pp_c->is_func && !pp_c->is_fptr)
4153 ferr(po, "call to non-func: %s\n", pp_c->name);
4154 pp = proto_clone(pp_c);
4155 my_assert_not(pp, NULL);
4157 // not resolved just to single func
4160 switch (po->operand[0].type) {
4162 // we resolved this call and no longer need the register
4163 po->regmask_src &= ~(1 << po->operand[0].reg);
4165 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4166 && ops[call_i].operand[1].type == OPT_LABEL)
4168 // no other source users?
4169 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4171 if (ret == 1 && call_i == ref_i) {
4172 // and nothing uses it after us?
4174 find_next_read(i + 1, opcnt, &po->operand[0],
4175 i + opcnt * 11, &ref_i);
4177 // then also don't need the source mov
4178 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4190 pp = calloc(1, sizeof(*pp));
4191 my_assert_not(pp, NULL);
4194 ret = scan_for_esp_adjust(i + 1, opcnt,
4195 -1, &adj, &multipath, 0);
4196 if (ret < 0 || adj < 0) {
4197 if (!g_allow_regfunc)
4198 ferr(po, "non-__cdecl indirect call unhandled yet\n");
4199 pp->is_unresolved = 1;
4203 if (adj > ARRAY_SIZE(pp->arg))
4204 ferr(po, "esp adjust too large: %d\n", adj);
4205 pp->ret_type.name = strdup("int");
4206 pp->argc = pp->argc_stack = adj;
4207 for (arg = 0; arg < pp->argc; arg++)
4208 pp->arg[arg].type.name = strdup("int");
4213 // look for and make use of esp adjust
4216 if (!pp->is_stdcall && pp->argc_stack > 0) {
4217 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
4218 ret = scan_for_esp_adjust(i + 1, opcnt,
4219 adj_expect, &adj, &multipath, 0);
4222 if (pp->is_vararg) {
4223 if (adj / 4 < pp->argc_stack) {
4224 fnote(po, "(this call)\n");
4225 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
4226 adj, pp->argc_stack * 4);
4228 // modify pp to make it have varargs as normal args
4230 pp->argc += adj / 4 - pp->argc_stack;
4231 for (; arg < pp->argc; arg++) {
4232 pp->arg[arg].type.name = strdup("int");
4235 if (pp->argc > ARRAY_SIZE(pp->arg))
4236 ferr(po, "too many args for '%s'\n", tmpname);
4238 if (pp->argc_stack > adj / 4) {
4239 fnote(po, "(this call)\n");
4240 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
4241 tmpname, pp->argc_stack * 4, adj);
4244 scan_for_esp_adjust(i + 1, opcnt,
4245 pp->argc_stack * 4, &adj, &multipath, 1);
4247 else if (pp->is_vararg)
4248 ferr(po, "missing esp_adjust for vararg func '%s'\n",
4254 static int collect_call_args_early(struct parsed_op *po, int i,
4255 struct parsed_proto *pp, int *regmask)
4260 for (arg = 0; arg < pp->argc; arg++)
4261 if (pp->arg[arg].reg == NULL)
4264 // first see if it can be easily done
4265 for (j = i; j > 0 && arg < pp->argc; )
4267 if (g_labels[j] != NULL)
4271 if (ops[j].op == OP_CALL)
4273 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP)
4275 else if (ops[j].op == OP_POP)
4277 else if (ops[j].flags & OPF_CJMP)
4279 else if (ops[j].op == OP_PUSH) {
4280 if (ops[j].flags & (OPF_FARG|OPF_FARGNR))
4282 ret = scan_for_mod(&ops[j], j + 1, i, 1);
4286 if (pp->arg[arg].type.is_va_list)
4290 for (arg++; arg < pp->argc; arg++)
4291 if (pp->arg[arg].reg == NULL)
4300 for (arg = 0; arg < pp->argc; arg++)
4301 if (pp->arg[arg].reg == NULL)
4304 for (j = i; j > 0 && arg < pp->argc; )
4308 if (ops[j].op == OP_PUSH)
4310 ops[j].p_argnext = -1;
4311 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
4312 pp->arg[arg].datap = &ops[j];
4314 if (ops[j].operand[0].type == OPT_REG)
4315 *regmask |= 1 << ops[j].operand[0].reg;
4317 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4318 ops[j].flags &= ~OPF_RSAVE;
4321 for (arg++; arg < pp->argc; arg++)
4322 if (pp->arg[arg].reg == NULL)
4330 static int collect_call_args_r(struct parsed_op *po, int i,
4331 struct parsed_proto *pp, int *regmask, int *save_arg_vars,
4332 int *arg_grp, int arg, int magic, int need_op_saving, int may_reuse)
4334 struct parsed_proto *pp_tmp;
4335 struct parsed_op *po_tmp;
4336 struct label_ref *lr;
4337 int need_to_save_current;
4338 int arg_grp_current = 0;
4339 int save_args_seen = 0;
4347 ferr(po, "dead label encountered\n");
4351 for (; arg < pp->argc; arg++)
4352 if (pp->arg[arg].reg == NULL)
4354 magic = (magic & 0xffffff) | (arg << 24);
4356 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
4358 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
4359 if (ops[j].cc_scratch != magic) {
4360 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
4364 // ok: have already been here
4367 ops[j].cc_scratch = magic;
4369 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
4370 lr = &g_label_refs[j];
4371 if (lr->next != NULL)
4373 for (; lr->next; lr = lr->next) {
4374 check_i(&ops[j], lr->i);
4375 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4377 ret = collect_call_args_r(po, lr->i, pp, regmask, save_arg_vars,
4378 arg_grp, arg, magic, need_op_saving, may_reuse);
4383 check_i(&ops[j], lr->i);
4384 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4386 if (j > 0 && LAST_OP(j - 1)) {
4387 // follow last branch in reverse
4392 ret = collect_call_args_r(po, lr->i, pp, regmask, save_arg_vars,
4393 arg_grp, arg, magic, need_op_saving, may_reuse);
4399 if (ops[j].op == OP_CALL)
4401 if (pp->is_unresolved)
4406 ferr(po, "arg collect hit unparsed call '%s'\n",
4407 ops[j].operand[0].name);
4408 if (may_reuse && pp_tmp->argc_stack > 0)
4409 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
4410 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
4412 // esp adjust of 0 means we collected it before
4413 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
4414 && (ops[j].operand[1].type != OPT_CONST
4415 || ops[j].operand[1].val != 0))
4417 if (pp->is_unresolved)
4420 fnote(po, "(this call)\n");
4421 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
4422 arg, pp->argc, ops[j].operand[1].val);
4424 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
4426 if (pp->is_unresolved)
4429 fnote(po, "(this call)\n");
4430 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
4432 else if (ops[j].flags & OPF_CJMP)
4434 if (pp->is_unresolved)
4439 else if (ops[j].op == OP_PUSH
4440 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
4442 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
4445 ops[j].p_argnext = -1;
4446 po_tmp = pp->arg[arg].datap;
4448 ops[j].p_argnext = po_tmp - ops;
4449 pp->arg[arg].datap = &ops[j];
4451 need_to_save_current = 0;
4454 if (ops[j].operand[0].type == OPT_REG)
4455 reg = ops[j].operand[0].reg;
4457 if (!need_op_saving) {
4458 ret = scan_for_mod(&ops[j], j + 1, i, 1);
4459 need_to_save_current = (ret >= 0);
4461 if (need_op_saving || need_to_save_current) {
4462 // mark this push as one that needs operand saving
4463 ops[j].flags &= ~OPF_RMD;
4464 if (ops[j].p_argnum == 0) {
4465 ops[j].p_argnum = arg + 1;
4466 save_args |= 1 << arg;
4468 else if (ops[j].p_argnum < arg + 1) {
4469 // XXX: might kill valid var..
4470 //*save_arg_vars &= ~(1 << (ops[j].p_argnum - 1));
4471 ops[j].p_argnum = arg + 1;
4472 save_args |= 1 << arg;
4475 if (save_args_seen & (1 << (ops[j].p_argnum - 1))) {
4478 if (arg_grp_current >= MAX_ARG_GRP)
4479 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
4480 ops[j].p_argnum, pp->name);
4483 else if (ops[j].p_argnum == 0)
4484 ops[j].flags |= OPF_RMD;
4486 // some PUSHes are reused by different calls on other branches,
4487 // but that can't happen if we didn't branch, so they
4488 // can be removed from future searches (handles nested calls)
4490 ops[j].flags |= OPF_FARGNR;
4492 ops[j].flags |= OPF_FARG;
4493 ops[j].flags &= ~OPF_RSAVE;
4495 // check for __VALIST
4496 if (!pp->is_unresolved && g_func_pp != NULL
4497 && pp->arg[arg].type.is_va_list)
4500 ret = resolve_origin(j, &ops[j].operand[0],
4501 magic + 1, &k, NULL);
4502 if (ret == 1 && k >= 0)
4504 if (ops[k].op == OP_LEA) {
4505 if (!g_func_pp->is_vararg)
4506 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
4509 snprintf(buf, sizeof(buf), "arg_%X",
4510 g_func_pp->argc_stack * 4);
4511 if (strstr(ops[k].operand[1].name, buf)
4512 || strstr(ops[k].operand[1].name, "arglist"))
4514 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
4515 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
4516 save_args &= ~(1 << arg);
4520 ferr(&ops[k], "va_list arg detection failed\n");
4522 // check for va_list from g_func_pp arg too
4523 else if (ops[k].op == OP_MOV
4524 && is_stack_access(&ops[k], &ops[k].operand[1]))
4526 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
4527 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
4529 ops[k].flags |= OPF_RMD | OPF_DONE;
4530 ops[j].flags |= OPF_RMD;
4531 ops[j].p_argpass = ret + 1;
4532 save_args &= ~(1 << arg);
4539 *save_arg_vars |= save_args;
4541 // tracking reg usage
4543 *regmask |= 1 << reg;
4546 if (!pp->is_unresolved) {
4548 for (; arg < pp->argc; arg++)
4549 if (pp->arg[arg].reg == NULL)
4552 magic = (magic & 0xffffff) | (arg << 24);
4555 if (ops[j].p_arggrp > arg_grp_current) {
4557 arg_grp_current = ops[j].p_arggrp;
4559 if (ops[j].p_argnum > 0)
4560 save_args_seen |= 1 << (ops[j].p_argnum - 1);
4563 if (arg < pp->argc) {
4564 ferr(po, "arg collect failed for '%s': %d/%d\n",
4565 pp->name, arg, pp->argc);
4569 if (arg_grp_current > *arg_grp)
4570 *arg_grp = arg_grp_current;
4575 static int collect_call_args(struct parsed_op *po, int i,
4576 struct parsed_proto *pp, int *regmask, int *save_arg_vars,
4579 // arg group is for cases when pushes for
4580 // multiple funcs are going on
4581 struct parsed_op *po_tmp;
4582 int save_arg_vars_current = 0;
4587 ret = collect_call_args_r(po, i, pp, regmask,
4588 &save_arg_vars_current, &arg_grp, 0, magic, 0, 0);
4593 // propagate arg_grp
4594 for (a = 0; a < pp->argc; a++) {
4595 if (pp->arg[a].reg != NULL)
4598 po_tmp = pp->arg[a].datap;
4599 while (po_tmp != NULL) {
4600 po_tmp->p_arggrp = arg_grp;
4601 if (po_tmp->p_argnext > 0)
4602 po_tmp = &ops[po_tmp->p_argnext];
4608 save_arg_vars[arg_grp] |= save_arg_vars_current;
4610 if (pp->is_unresolved) {
4612 pp->argc_stack += ret;
4613 for (a = 0; a < pp->argc; a++)
4614 if (pp->arg[a].type.name == NULL)
4615 pp->arg[a].type.name = strdup("int");
4621 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
4622 int regmask_now, int *regmask,
4623 int regmask_save_now, int *regmask_save,
4624 int *regmask_init, int regmask_arg)
4626 struct parsed_op *po;
4635 for (; i < opcnt; i++)
4638 if (cbits[i >> 3] & (1 << (i & 7)))
4640 cbits[i >> 3] |= (1 << (i & 7));
4642 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4643 if (po->flags & (OPF_RMD|OPF_DONE))
4645 if (po->btj != NULL) {
4646 for (j = 0; j < po->btj->count; j++) {
4647 check_i(po, po->btj->d[j].bt_i);
4648 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
4649 regmask_now, regmask, regmask_save_now, regmask_save,
4650 regmask_init, regmask_arg);
4655 check_i(po, po->bt_i);
4656 if (po->flags & OPF_CJMP)
4657 reg_use_pass(po->bt_i, opcnt, cbits,
4658 regmask_now, regmask, regmask_save_now, regmask_save,
4659 regmask_init, regmask_arg);
4665 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
4666 && !g_func_pp->is_userstack
4667 && po->operand[0].type == OPT_REG)
4669 reg = po->operand[0].reg;
4670 ferr_assert(po, reg >= 0);
4673 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
4674 if (regmask_now & (1 << reg)) {
4675 already_saved = regmask_save_now & (1 << reg);
4676 flags_set = OPF_RSAVE | OPF_DONE;
4679 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0);
4681 scan_for_pop(i + 1, opcnt, i + opcnt * 4, reg, 0, flags_set);
4684 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
4686 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
4691 ferr_assert(po, !already_saved);
4692 po->flags |= flags_set;
4694 if (regmask_now & (1 << reg)) {
4695 regmask_save_now |= (1 << reg);
4696 *regmask_save |= regmask_save_now;
4701 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
4702 reg = po->operand[0].reg;
4703 ferr_assert(po, reg >= 0);
4705 if (regmask_save_now & (1 << reg))
4706 regmask_save_now &= ~(1 << reg);
4708 regmask_now &= ~(1 << reg);
4711 else if (po->op == OP_CALL) {
4712 if ((po->regmask_dst & (1 << xAX))
4713 && !(po->regmask_dst & (1 << xDX)))
4715 if (po->flags & OPF_TAIL)
4716 // don't need eax, will do "return f();" or "f(); return;"
4717 po->regmask_dst &= ~(1 << xAX);
4719 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
4721 find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
4724 po->regmask_dst &= ~(1 << xAX);
4729 if (po->flags & OPF_NOREGS)
4732 if (po->flags & OPF_FPUSH) {
4733 if (regmask_now & mxST1)
4734 ferr(po, "TODO: FPUSH on active ST1\n");
4735 if (regmask_now & mxST0)
4736 po->flags |= OPF_FSHIFT;
4737 mask = mxST0 | mxST1;
4738 regmask_now = (regmask_now & ~mask) | ((regmask_now & mxST0) << 1);
4741 // if incomplete register is used, clear it on init to avoid
4742 // later use of uninitialized upper part in some situations
4743 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
4744 && po->operand[0].lmod != OPLM_DWORD)
4746 reg = po->operand[0].reg;
4747 ferr_assert(po, reg >= 0);
4749 if (!(regmask_now & (1 << reg)))
4750 *regmask_init |= 1 << reg;
4753 regmask_op = po->regmask_src | po->regmask_dst;
4755 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
4756 regmask_new &= ~(1 << xSP);
4757 if (g_bp_frame && !(po->flags & OPF_EBP_S))
4758 regmask_new &= ~(1 << xBP);
4760 if (po->op == OP_CALL) {
4761 // allow fastcall calls from anywhere, calee may be also sitting
4762 // in some fastcall table even when it's not using reg args
4763 if (regmask_new & po->regmask_src & (1 << xCX)) {
4764 *regmask_init |= (1 << xCX);
4765 regmask_now |= (1 << xCX);
4766 regmask_new &= ~(1 << xCX);
4768 if (regmask_new & po->regmask_src & (1 << xDX)) {
4769 *regmask_init |= (1 << xDX);
4770 regmask_now |= (1 << xDX);
4771 regmask_new &= ~(1 << xDX);
4775 if (regmask_new != 0)
4776 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
4778 if (regmask_op & (1 << xBP)) {
4779 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
4780 if (po->regmask_dst & (1 << xBP))
4781 // compiler decided to drop bp frame and use ebp as scratch
4782 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
4784 regmask_op &= ~(1 << xBP);
4788 regmask_now |= regmask_op;
4789 *regmask |= regmask_now;
4792 if (po->flags & OPF_FPOP) {
4793 mask = mxST0 | mxST1;
4794 if (!(regmask_now & mask))
4795 ferr(po, "float pop on empty stack?\n");
4796 if (regmask_now & mxST1)
4797 po->flags |= OPF_FSHIFT;
4798 regmask_now = (regmask_now & ~mask) | ((regmask_now & mxST1) >> 1);
4801 if (po->flags & OPF_TAIL) {
4802 if (regmask_now & (mxST0 | mxST1))
4803 ferr(po, "float regs on tail: %x\n", regmask_now);
4809 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
4813 for (i = 0; i < pp->argc; i++)
4814 if (pp->arg[i].reg == NULL)
4818 memmove(&pp->arg[i + 1], &pp->arg[i],
4819 sizeof(pp->arg[0]) * pp->argc_stack);
4820 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
4821 pp->arg[i].reg = strdup(reg);
4822 pp->arg[i].type.name = strdup("int");
4827 static void output_std_flags(FILE *fout, struct parsed_op *po,
4828 int *pfomask, const char *dst_opr_text)
4830 if (*pfomask & (1 << PFO_Z)) {
4831 fprintf(fout, "\n cond_z = (%s%s == 0);",
4832 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
4833 *pfomask &= ~(1 << PFO_Z);
4835 if (*pfomask & (1 << PFO_S)) {
4836 fprintf(fout, "\n cond_s = (%s%s < 0);",
4837 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
4838 *pfomask &= ~(1 << PFO_S);
4843 OPP_FORCE_NORETURN = (1 << 0),
4844 OPP_SIMPLE_ARGS = (1 << 1),
4845 OPP_ALIGN = (1 << 2),
4848 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
4851 const char *cconv = "";
4853 if (pp->is_fastcall)
4854 cconv = "__fastcall ";
4855 else if (pp->is_stdcall && pp->argc_reg == 0)
4856 cconv = "__stdcall ";
4858 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
4860 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
4861 fprintf(fout, "noreturn ");
4864 static void output_pp(FILE *fout, const struct parsed_proto *pp,
4869 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
4873 output_pp_attrs(fout, pp, flags);
4876 fprintf(fout, "%s", pp->name);
4881 for (i = 0; i < pp->argc; i++) {
4883 fprintf(fout, ", ");
4884 if (pp->arg[i].fptr != NULL && !(flags & OPP_SIMPLE_ARGS)) {
4886 output_pp(fout, pp->arg[i].fptr, 0);
4888 else if (pp->arg[i].type.is_retreg) {
4889 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
4892 fprintf(fout, "%s", pp->arg[i].type.name);
4894 fprintf(fout, " a%d", i + 1);
4897 if (pp->is_vararg) {
4899 fprintf(fout, ", ");
4900 fprintf(fout, "...");
4905 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
4911 snprintf(buf1, sizeof(buf1), "%d", grp);
4912 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
4917 static void gen_x_cleanup(int opcnt);
4919 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
4921 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
4922 struct parsed_opr *last_arith_dst = NULL;
4923 char buf1[256], buf2[256], buf3[256], cast[64];
4924 struct parsed_proto *pp, *pp_tmp;
4925 struct parsed_data *pd;
4927 int save_arg_vars[MAX_ARG_GRP] = { 0, };
4928 unsigned char cbits[MAX_OPS / 8];
4930 int need_tmp_var = 0;
4933 int label_pending = 0;
4934 int regmask_save = 0; // regs saved/restored in this func
4935 int regmask_arg; // regs from this function args (fastcall, etc)
4936 int regmask_ret; // regs needed on ret
4937 int regmask_now; // temp
4938 int regmask_init = 0; // regs that need zero initialization
4939 int regmask_pp = 0; // regs used in complex push-pop graph
4940 int regmask = 0; // used regs
4949 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
4950 g_stack_frame_used = 0;
4952 g_func_pp = proto_parse(fhdr, funcn, 0);
4953 if (g_func_pp == NULL)
4954 ferr(ops, "proto_parse failed for '%s'\n", funcn);
4956 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
4957 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
4959 if (g_func_pp->has_retreg) {
4960 for (arg = 0; arg < g_func_pp->argc; arg++) {
4961 if (g_func_pp->arg[arg].type.is_retreg) {
4962 reg = char_array_i(regs_r32,
4963 ARRAY_SIZE(regs_r32), g_func_pp->arg[arg].reg);
4964 ferr_assert(ops, reg >= 0);
4965 regmask_ret |= 1 << reg;
4971 // - resolve all branches
4972 // - parse calls with labels
4973 resolve_branches_parse_calls(opcnt);
4976 // - handle ebp/esp frame, remove ops related to it
4977 scan_prologue_epilogue(opcnt);
4980 // - remove dead labels
4981 // - set regs needed at ret
4982 for (i = 0; i < opcnt; i++)
4984 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
4989 if (ops[i].op == OP_RET)
4990 ops[i].regmask_src |= regmask_ret;
4994 // - process trivial calls
4995 for (i = 0; i < opcnt; i++)
4998 if (po->flags & (OPF_RMD|OPF_DONE))
5001 if (po->op == OP_CALL)
5003 pp = process_call_early(i, opcnt, &j);
5005 if (!(po->flags & OPF_ATAIL))
5006 // since we know the args, try to collect them
5007 if (collect_call_args_early(po, i, pp, ®mask) != 0)
5013 // commit esp adjust
5014 if (ops[j].op != OP_POP)
5015 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5017 for (l = 0; l < pp->argc_stack; l++)
5018 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
5022 if (strstr(pp->ret_type.name, "int64"))
5025 po->flags |= OPF_DONE;
5031 // - process calls, stage 2
5032 // - handle some push/pop pairs
5033 // - scan for STD/CLD, propagate DF
5034 for (i = 0; i < opcnt; i++)
5037 if (po->flags & OPF_RMD)
5040 if (po->op == OP_CALL)
5042 if (!(po->flags & OPF_DONE)) {
5043 pp = process_call(i, opcnt);
5045 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
5046 // since we know the args, collect them
5047 collect_call_args(po, i, pp, ®mask, save_arg_vars,
5050 // for unresolved, collect after other passes
5054 ferr_assert(po, pp != NULL);
5056 po->regmask_src |= get_pp_arg_regmask_src(pp);
5057 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
5059 if (po->regmask_dst & mxST0)
5060 po->flags |= OPF_FPUSH;
5062 if (strstr(pp->ret_type.name, "int64"))
5068 if (po->flags & OPF_DONE)
5071 if (po->op == OP_PUSH && !(po->flags & OPF_FARG)
5072 && !(po->flags & OPF_RSAVE) && po->operand[0].type == OPT_CONST)
5074 scan_for_pop_const(i, opcnt, i + opcnt * 12);
5076 else if (po->op == OP_POP)
5077 scan_pushes_for_pop(i, opcnt, ®mask_pp);
5078 else if (po->op == OP_STD) {
5079 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
5080 scan_propagate_df(i + 1, opcnt);
5085 // - find POPs for PUSHes, rm both
5086 // - scan for all used registers
5087 memset(cbits, 0, sizeof(cbits));
5088 reg_use_pass(0, opcnt, cbits, 0, ®mask,
5089 0, ®mask_save, ®mask_init, regmask_arg);
5092 // - find flag set ops for their users
5093 // - do unresolved calls
5094 // - declare indirect functions
5095 for (i = 0; i < opcnt; i++)
5098 if (po->flags & (OPF_RMD|OPF_DONE))
5101 if (po->flags & OPF_CC)
5103 int setters[16], cnt = 0, branched = 0;
5105 ret = scan_for_flag_set(i, i + opcnt * 6,
5106 &branched, setters, &cnt);
5107 if (ret < 0 || cnt <= 0)
5108 ferr(po, "unable to trace flag setter(s)\n");
5109 if (cnt > ARRAY_SIZE(setters))
5110 ferr(po, "too many flag setters\n");
5112 for (j = 0; j < cnt; j++)
5114 tmp_op = &ops[setters[j]]; // flag setter
5117 // to get nicer code, we try to delay test and cmp;
5118 // if we can't because of operand modification, or if we
5119 // have arith op, or branch, make it calculate flags explicitly
5120 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
5122 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
5123 pfomask = 1 << po->pfo;
5125 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
5126 pfomask = 1 << po->pfo;
5129 // see if we'll be able to handle based on op result
5130 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
5131 && po->pfo != PFO_Z && po->pfo != PFO_S
5132 && po->pfo != PFO_P)
5134 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
5136 pfomask = 1 << po->pfo;
5139 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
5140 propagate_lmod(tmp_op, &tmp_op->operand[0],
5141 &tmp_op->operand[1]);
5142 if (tmp_op->operand[0].lmod == OPLM_DWORD)
5147 tmp_op->pfomask |= pfomask;
5148 cond_vars |= pfomask;
5150 // note: may overwrite, currently not a problem
5154 if (po->op == OP_RCL || po->op == OP_RCR
5155 || po->op == OP_ADC || po->op == OP_SBB)
5156 cond_vars |= 1 << PFO_C;
5159 if (po->op == OP_CMPS || po->op == OP_SCAS) {
5160 cond_vars |= 1 << PFO_Z;
5162 else if (po->op == OP_MUL
5163 || (po->op == OP_IMUL && po->operand_cnt == 1))
5165 if (po->operand[0].lmod == OPLM_DWORD)
5168 else if (po->op == OP_CALL) {
5169 // note: resolved non-reg calls are OPF_DONE already
5171 ferr_assert(po, pp != NULL);
5173 if (pp->is_unresolved) {
5174 int regmask_stack = 0;
5175 collect_call_args(po, i, pp, ®mask, save_arg_vars,
5178 // this is pretty rough guess:
5179 // see ecx and edx were pushed (and not their saved versions)
5180 for (arg = 0; arg < pp->argc; arg++) {
5181 if (pp->arg[arg].reg != NULL)
5184 tmp_op = pp->arg[arg].datap;
5186 ferr(po, "parsed_op missing for arg%d\n", arg);
5187 if (tmp_op->p_argnum == 0 && tmp_op->operand[0].type == OPT_REG)
5188 regmask_stack |= 1 << tmp_op->operand[0].reg;
5191 if (!((regmask_stack & (1 << xCX))
5192 && (regmask_stack & (1 << xDX))))
5194 if (pp->argc_stack != 0
5195 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
5197 pp_insert_reg_arg(pp, "ecx");
5198 pp->is_fastcall = 1;
5199 regmask_init |= 1 << xCX;
5200 regmask |= 1 << xCX;
5202 if (pp->argc_stack != 0
5203 || ((regmask | regmask_arg) & (1 << xDX)))
5205 pp_insert_reg_arg(pp, "edx");
5206 regmask_init |= 1 << xDX;
5207 regmask |= 1 << xDX;
5211 // note: __cdecl doesn't fall into is_unresolved category
5212 if (pp->argc_stack > 0)
5216 else if (po->op == OP_MOV && po->operand[0].pp != NULL
5217 && po->operand[1].pp != NULL)
5219 // <var> = offset <something>
5220 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
5221 && !IS_START(po->operand[1].name, "off_"))
5223 if (!po->operand[0].pp->is_fptr)
5224 ferr(po, "%s not declared as fptr when it should be\n",
5225 po->operand[0].name);
5226 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
5227 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
5228 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
5229 fnote(po, "var: %s\n", buf1);
5230 fnote(po, "func: %s\n", buf2);
5231 ferr(po, "^ mismatch\n");
5235 else if (po->op == OP_DIV || po->op == OP_IDIV) {
5236 if (po->operand[0].lmod == OPLM_DWORD) {
5237 // 32bit division is common, look for it
5238 if (po->op == OP_DIV)
5239 ret = scan_for_reg_clear(i, xDX);
5241 ret = scan_for_cdq_edx(i);
5243 po->flags |= OPF_32BIT;
5250 else if (po->op == OP_CLD)
5251 po->flags |= OPF_RMD | OPF_DONE;
5252 else if (po->op == OPP_FTOL) {
5253 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
5255 find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
5257 po->flags |= OPF_32BIT;
5260 if (po->op == OP_RCL || po->op == OP_RCR || po->op == OP_XCHG)
5264 // output starts here
5266 // define userstack size
5267 if (g_func_pp->is_userstack) {
5268 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
5269 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
5270 fprintf(fout, "#endif\n");
5273 // the function itself
5274 ferr_assert(ops, !g_func_pp->is_fptr);
5275 output_pp(fout, g_func_pp,
5276 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
5277 fprintf(fout, "\n{\n");
5279 // declare indirect functions
5280 for (i = 0; i < opcnt; i++) {
5282 if (po->flags & OPF_RMD)
5285 if (po->op == OP_CALL) {
5288 ferr(po, "NULL pp\n");
5290 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
5291 if (pp->name[0] != 0) {
5292 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
5293 memcpy(pp->name, "i_", 2);
5295 // might be declared already
5297 for (j = 0; j < i; j++) {
5298 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
5299 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
5309 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
5312 output_pp(fout, pp, OPP_SIMPLE_ARGS);
5313 fprintf(fout, ";\n");
5318 // output LUTs/jumptables
5319 for (i = 0; i < g_func_pd_cnt; i++) {
5321 fprintf(fout, " static const ");
5322 if (pd->type == OPT_OFFSET) {
5323 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
5325 for (j = 0; j < pd->count; j++) {
5327 fprintf(fout, ", ");
5328 fprintf(fout, "&&%s", pd->d[j].u.label);
5332 fprintf(fout, "%s %s[] =\n { ",
5333 lmod_type_u(ops, pd->lmod), pd->label);
5335 for (j = 0; j < pd->count; j++) {
5337 fprintf(fout, ", ");
5338 fprintf(fout, "%u", pd->d[j].u.val);
5341 fprintf(fout, " };\n");
5345 // declare stack frame, va_arg
5347 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
5348 if (g_func_lmods & (1 << OPLM_WORD))
5349 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
5350 if (g_func_lmods & (1 << OPLM_BYTE))
5351 fprintf(fout, " u8 b[%d];", g_stack_fsz);
5352 if (g_func_lmods & (1 << OPLM_QWORD))
5353 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
5354 fprintf(fout, " } sf;\n");
5358 if (g_func_pp->is_userstack) {
5359 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
5360 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
5364 if (g_func_pp->is_vararg) {
5365 fprintf(fout, " va_list ap;\n");
5369 // declare arg-registers
5370 for (i = 0; i < g_func_pp->argc; i++) {
5371 if (g_func_pp->arg[i].reg != NULL) {
5372 reg = char_array_i(regs_r32,
5373 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
5374 if (regmask & (1 << reg)) {
5375 if (g_func_pp->arg[i].type.is_retreg)
5376 fprintf(fout, " u32 %s = *r_%s;\n",
5377 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
5379 fprintf(fout, " u32 %s = (u32)a%d;\n",
5380 g_func_pp->arg[i].reg, i + 1);
5383 if (g_func_pp->arg[i].type.is_retreg)
5384 ferr(ops, "retreg '%s' is unused?\n",
5385 g_func_pp->arg[i].reg);
5386 fprintf(fout, " // %s = a%d; // unused\n",
5387 g_func_pp->arg[i].reg, i + 1);
5393 // declare normal registers
5394 regmask_now = regmask & ~regmask_arg;
5395 regmask_now &= ~(1 << xSP);
5396 if (regmask_now & 0x00ff) {
5397 for (reg = 0; reg < 8; reg++) {
5398 if (regmask_now & (1 << reg)) {
5399 fprintf(fout, " u32 %s", regs_r32[reg]);
5400 if (regmask_init & (1 << reg))
5401 fprintf(fout, " = 0");
5402 fprintf(fout, ";\n");
5408 if (regmask_now & 0xff00) {
5409 for (reg = 8; reg < 16; reg++) {
5410 if (regmask_now & (1 << reg)) {
5411 fprintf(fout, " mmxr %s", regs_r32[reg]);
5412 if (regmask_init & (1 << reg))
5413 fprintf(fout, " = { 0, }");
5414 fprintf(fout, ";\n");
5420 if (regmask_now & 0xff0000) {
5421 for (reg = 16; reg < 24; reg++) {
5422 if (regmask_now & (1 << reg)) {
5423 fprintf(fout, " double f_st%d", reg - 16);
5424 if (regmask_init & (1 << reg))
5425 fprintf(fout, " = 0");
5426 fprintf(fout, ";\n");
5433 for (reg = 0; reg < 8; reg++) {
5434 if (regmask_save & (1 << reg)) {
5435 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
5441 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
5442 if (save_arg_vars[i] == 0)
5444 for (reg = 0; reg < 32; reg++) {
5445 if (save_arg_vars[i] & (1 << reg)) {
5446 fprintf(fout, " u32 %s;\n",
5447 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
5453 // declare push-pop temporaries
5455 for (reg = 0; reg < 8; reg++) {
5456 if (regmask_pp & (1 << reg)) {
5457 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
5464 for (i = 0; i < 8; i++) {
5465 if (cond_vars & (1 << i)) {
5466 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
5473 fprintf(fout, " u32 tmp;\n");
5478 fprintf(fout, " u64 tmp64;\n");
5483 fprintf(fout, "\n");
5485 // do stack clear, if needed
5486 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
5488 if (g_stack_clear_len != 0) {
5489 if (g_stack_clear_len <= 4) {
5490 for (i = 0; i < g_stack_clear_len; i++)
5491 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
5492 fprintf(fout, "0;\n");
5495 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
5496 g_stack_clear_start, g_stack_clear_len * 4);
5500 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
5503 if (g_func_pp->is_vararg) {
5504 if (g_func_pp->argc_stack == 0)
5505 ferr(ops, "vararg func without stack args?\n");
5506 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
5510 for (i = 0; i < opcnt; i++)
5512 if (g_labels[i] != NULL) {
5513 fprintf(fout, "\n%s:\n", g_labels[i]);
5516 delayed_flag_op = NULL;
5517 last_arith_dst = NULL;
5521 if (po->flags & OPF_RMD)
5526 #define assert_operand_cnt(n_) \
5527 if (po->operand_cnt != n_) \
5528 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
5530 // conditional/flag using op?
5531 if (po->flags & OPF_CC)
5537 // we go through all this trouble to avoid using parsed_flag_op,
5538 // which makes generated code much nicer
5539 if (delayed_flag_op != NULL)
5541 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
5542 po->pfo, po->pfo_inv);
5545 else if (last_arith_dst != NULL
5546 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
5547 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
5550 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
5551 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
5552 last_arith_dst->lmod, buf3);
5555 else if (tmp_op != NULL) {
5556 // use preprocessed flag calc results
5557 if (!(tmp_op->pfomask & (1 << po->pfo)))
5558 ferr(po, "not prepared for pfo %d\n", po->pfo);
5560 // note: pfo_inv was not yet applied
5561 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
5562 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
5565 ferr(po, "all methods of finding comparison failed\n");
5568 if (po->flags & OPF_JMP) {
5569 fprintf(fout, " if %s", buf1);
5571 else if (po->op == OP_RCL || po->op == OP_RCR
5572 || po->op == OP_ADC || po->op == OP_SBB)
5575 fprintf(fout, " cond_%s = %s;\n",
5576 parsed_flag_op_names[po->pfo], buf1);
5578 else if (po->flags & OPF_DATA) { // SETcc
5579 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
5580 fprintf(fout, " %s = %s;", buf2, buf1);
5583 ferr(po, "unhandled conditional op\n");
5587 pfomask = po->pfomask;
5589 if (po->flags & (OPF_REPZ|OPF_REPNZ)) {
5590 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
5591 ret = try_resolve_const(i, &opr, opcnt * 7 + i, &uval);
5593 if (ret != 1 || uval == 0) {
5594 // we need initial flags for ecx=0 case..
5595 if (i > 0 && ops[i - 1].op == OP_XOR
5596 && IS(ops[i - 1].operand[0].name,
5597 ops[i - 1].operand[1].name))
5599 fprintf(fout, " cond_z = ");
5600 if (pfomask & (1 << PFO_C))
5601 fprintf(fout, "cond_c = ");
5602 fprintf(fout, "0;\n");
5604 else if (last_arith_dst != NULL) {
5605 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
5606 out_test_for_cc(buf1, sizeof(buf1), po, PFO_Z, 0,
5607 last_arith_dst->lmod, buf3);
5608 fprintf(fout, " cond_z = %s;\n", buf1);
5611 ferr(po, "missing initial ZF\n");
5618 assert_operand_cnt(2);
5619 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5620 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5621 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
5622 fprintf(fout, " %s = %s;", buf1,
5623 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5628 assert_operand_cnt(2);
5629 po->operand[1].lmod = OPLM_DWORD; // always
5630 fprintf(fout, " %s = %s;",
5631 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5632 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5637 assert_operand_cnt(2);
5638 fprintf(fout, " %s = %s;",
5639 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5640 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5644 assert_operand_cnt(2);
5645 switch (po->operand[1].lmod) {
5647 strcpy(buf3, "(s8)");
5650 strcpy(buf3, "(s16)");
5653 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
5655 fprintf(fout, " %s = %s;",
5656 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5657 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5662 assert_operand_cnt(2);
5663 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5664 fprintf(fout, " tmp = %s;",
5665 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
5666 fprintf(fout, " %s = %s;",
5667 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5668 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5669 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
5670 fprintf(fout, " %s = %stmp;",
5671 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
5672 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
5673 snprintf(g_comment, sizeof(g_comment), "xchg");
5677 assert_operand_cnt(1);
5678 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5679 fprintf(fout, " %s = ~%s;", buf1, buf1);
5683 assert_operand_cnt(2);
5684 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5685 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
5686 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
5687 strcpy(g_comment, "xlat");
5691 assert_operand_cnt(2);
5692 fprintf(fout, " %s = (s32)%s >> 31;",
5693 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5694 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5695 strcpy(g_comment, "cdq");
5699 if (po->flags & OPF_REP) {
5700 assert_operand_cnt(3);
5705 assert_operand_cnt(2);
5706 fprintf(fout, " %s = %sesi; esi %c= %d;",
5707 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
5708 lmod_cast_u_ptr(po, po->operand[1].lmod),
5709 (po->flags & OPF_DF) ? '-' : '+',
5710 lmod_bytes(po, po->operand[1].lmod));
5711 strcpy(g_comment, "lods");
5716 if (po->flags & OPF_REP) {
5717 assert_operand_cnt(3);
5718 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
5719 (po->flags & OPF_DF) ? '-' : '+',
5720 lmod_bytes(po, po->operand[1].lmod));
5721 fprintf(fout, " %sedi = eax;",
5722 lmod_cast_u_ptr(po, po->operand[1].lmod));
5723 strcpy(g_comment, "rep stos");
5726 assert_operand_cnt(2);
5727 fprintf(fout, " %sedi = eax; edi %c= %d;",
5728 lmod_cast_u_ptr(po, po->operand[1].lmod),
5729 (po->flags & OPF_DF) ? '-' : '+',
5730 lmod_bytes(po, po->operand[1].lmod));
5731 strcpy(g_comment, "stos");
5736 j = lmod_bytes(po, po->operand[0].lmod);
5737 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
5738 l = (po->flags & OPF_DF) ? '-' : '+';
5739 if (po->flags & OPF_REP) {
5740 assert_operand_cnt(3);
5742 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
5745 " %sedi = %sesi;", buf1, buf1);
5746 strcpy(g_comment, "rep movs");
5749 assert_operand_cnt(2);
5750 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
5751 buf1, buf1, l, j, l, j);
5752 strcpy(g_comment, "movs");
5757 // repe ~ repeat while ZF=1
5758 j = lmod_bytes(po, po->operand[0].lmod);
5759 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
5760 l = (po->flags & OPF_DF) ? '-' : '+';
5761 if (po->flags & OPF_REP) {
5762 assert_operand_cnt(3);
5764 " for (; ecx != 0; ecx--) {\n");
5765 if (pfomask & (1 << PFO_C)) {
5768 " cond_c = %sesi < %sedi;\n", buf1, buf1);
5769 pfomask &= ~(1 << PFO_C);
5772 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
5773 buf1, buf1, l, j, l, j);
5775 " if (cond_z %s 0) break;\n",
5776 (po->flags & OPF_REPZ) ? "==" : "!=");
5779 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
5780 (po->flags & OPF_REPZ) ? "e" : "ne");
5783 assert_operand_cnt(2);
5785 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
5786 buf1, buf1, l, j, l, j);
5787 strcpy(g_comment, "cmps");
5789 pfomask &= ~(1 << PFO_Z);
5790 last_arith_dst = NULL;
5791 delayed_flag_op = NULL;
5795 // only does ZF (for now)
5796 // repe ~ repeat while ZF=1
5797 j = lmod_bytes(po, po->operand[1].lmod);
5798 l = (po->flags & OPF_DF) ? '-' : '+';
5799 if (po->flags & OPF_REP) {
5800 assert_operand_cnt(3);
5802 " for (; ecx != 0; ecx--) {\n");
5804 " cond_z = (%seax == %sedi); edi %c= %d;\n",
5805 lmod_cast_u(po, po->operand[1].lmod),
5806 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
5808 " if (cond_z %s 0) break;\n",
5809 (po->flags & OPF_REPZ) ? "==" : "!=");
5812 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
5813 (po->flags & OPF_REPZ) ? "e" : "ne");
5816 assert_operand_cnt(2);
5817 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
5818 lmod_cast_u(po, po->operand[1].lmod),
5819 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
5820 strcpy(g_comment, "scas");
5822 pfomask &= ~(1 << PFO_Z);
5823 last_arith_dst = NULL;
5824 delayed_flag_op = NULL;
5827 // arithmetic w/flags
5829 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
5830 goto dualop_arith_const;
5831 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5835 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5836 if (po->operand[1].type == OPT_CONST) {
5837 j = lmod_bytes(po, po->operand[0].lmod);
5838 if (((1ull << j * 8) - 1) == po->operand[1].val)
5839 goto dualop_arith_const;
5844 assert_operand_cnt(2);
5845 fprintf(fout, " %s %s= %s;",
5846 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5848 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5849 output_std_flags(fout, po, &pfomask, buf1);
5850 last_arith_dst = &po->operand[0];
5851 delayed_flag_op = NULL;
5855 // and 0, or ~0 used instead mov
5856 assert_operand_cnt(2);
5857 fprintf(fout, " %s = %s;",
5858 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5859 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5860 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
5861 output_std_flags(fout, po, &pfomask, buf1);
5862 last_arith_dst = &po->operand[0];
5863 delayed_flag_op = NULL;
5868 assert_operand_cnt(2);
5869 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5870 if (pfomask & (1 << PFO_C)) {
5871 if (po->operand[1].type == OPT_CONST) {
5872 l = lmod_bytes(po, po->operand[0].lmod) * 8;
5873 j = po->operand[1].val;
5876 if (po->op == OP_SHL)
5880 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
5884 ferr(po, "zero shift?\n");
5888 pfomask &= ~(1 << PFO_C);
5890 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
5891 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5892 if (po->operand[1].type != OPT_CONST)
5893 fprintf(fout, " & 0x1f");
5895 output_std_flags(fout, po, &pfomask, buf1);
5896 last_arith_dst = &po->operand[0];
5897 delayed_flag_op = NULL;
5901 assert_operand_cnt(2);
5902 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5903 fprintf(fout, " %s = %s%s >> %s;", buf1,
5904 lmod_cast_s(po, po->operand[0].lmod), buf1,
5905 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5906 output_std_flags(fout, po, &pfomask, buf1);
5907 last_arith_dst = &po->operand[0];
5908 delayed_flag_op = NULL;
5913 assert_operand_cnt(3);
5914 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5915 l = lmod_bytes(po, po->operand[0].lmod) * 8;
5916 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
5917 if (po->operand[2].type != OPT_CONST) {
5918 // no handling for "undefined" case, hopefully not needed
5919 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
5922 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
5923 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5924 if (po->op == OP_SHLD) {
5925 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
5926 buf1, buf3, buf1, buf2, l, buf3);
5927 strcpy(g_comment, "shld");
5930 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
5931 buf1, buf3, buf1, buf2, l, buf3);
5932 strcpy(g_comment, "shrd");
5934 output_std_flags(fout, po, &pfomask, buf1);
5935 last_arith_dst = &po->operand[0];
5936 delayed_flag_op = NULL;
5941 assert_operand_cnt(2);
5942 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5943 if (po->operand[1].type == OPT_CONST) {
5944 j = po->operand[1].val;
5945 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
5946 fprintf(fout, po->op == OP_ROL ?
5947 " %s = (%s << %d) | (%s >> %d);" :
5948 " %s = (%s >> %d) | (%s << %d);",
5949 buf1, buf1, j, buf1,
5950 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
5954 output_std_flags(fout, po, &pfomask, buf1);
5955 last_arith_dst = &po->operand[0];
5956 delayed_flag_op = NULL;
5961 assert_operand_cnt(2);
5962 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5963 l = lmod_bytes(po, po->operand[0].lmod) * 8;
5964 if (po->operand[1].type == OPT_CONST) {
5965 j = po->operand[1].val % l;
5967 ferr(po, "zero rotate\n");
5968 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
5969 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
5970 if (po->op == OP_RCL) {
5972 " %s = (%s << %d) | (cond_c << %d)",
5973 buf1, buf1, j, j - 1);
5975 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
5979 " %s = (%s >> %d) | (cond_c << %d)",
5980 buf1, buf1, j, l - j);
5982 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
5984 fprintf(fout, ";\n");
5985 fprintf(fout, " cond_c = tmp;");
5989 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
5990 output_std_flags(fout, po, &pfomask, buf1);
5991 last_arith_dst = &po->operand[0];
5992 delayed_flag_op = NULL;
5996 assert_operand_cnt(2);
5997 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5998 if (IS(opr_name(po, 0), opr_name(po, 1))) {
5999 // special case for XOR
6000 if (pfomask & (1 << PFO_BE)) { // weird, but it happens..
6001 fprintf(fout, " cond_be = 1;\n");
6002 pfomask &= ~(1 << PFO_BE);
6004 fprintf(fout, " %s = 0;",
6005 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6006 last_arith_dst = &po->operand[0];
6007 delayed_flag_op = NULL;
6013 assert_operand_cnt(2);
6014 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6015 if (pfomask & (1 << PFO_C)) {
6016 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6017 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6018 if (po->operand[0].lmod == OPLM_DWORD) {
6019 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
6020 fprintf(fout, " cond_c = tmp64 >> 32;\n");
6021 fprintf(fout, " %s = (u32)tmp64;",
6022 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6023 strcat(g_comment, " add64");
6026 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
6027 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
6028 fprintf(fout, " %s += %s;",
6029 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6032 pfomask &= ~(1 << PFO_C);
6033 output_std_flags(fout, po, &pfomask, buf1);
6034 last_arith_dst = &po->operand[0];
6035 delayed_flag_op = NULL;
6041 assert_operand_cnt(2);
6042 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6043 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
6044 for (j = 0; j <= PFO_LE; j++) {
6045 if (!(pfomask & (1 << j)))
6047 if (j == PFO_Z || j == PFO_S)
6050 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0);
6051 fprintf(fout, " cond_%s = %s;\n",
6052 parsed_flag_op_names[j], buf1);
6053 pfomask &= ~(1 << j);
6060 assert_operand_cnt(2);
6061 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6062 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6063 if (po->op == OP_SBB
6064 && IS(po->operand[0].name, po->operand[1].name))
6066 // avoid use of unitialized var
6067 fprintf(fout, " %s = -cond_c;", buf1);
6068 // carry remains what it was
6069 pfomask &= ~(1 << PFO_C);
6072 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
6073 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6075 output_std_flags(fout, po, &pfomask, buf1);
6076 last_arith_dst = &po->operand[0];
6077 delayed_flag_op = NULL;
6081 assert_operand_cnt(2);
6082 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6083 fprintf(fout, " %s = %s ? __builtin_ffs(%s) - 1 : 0;",
6084 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6086 output_std_flags(fout, po, &pfomask, buf1);
6087 last_arith_dst = &po->operand[0];
6088 delayed_flag_op = NULL;
6089 strcat(g_comment, " bsf");
6093 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
6094 for (j = 0; j <= PFO_LE; j++) {
6095 if (!(pfomask & (1 << j)))
6097 if (j == PFO_Z || j == PFO_S || j == PFO_C)
6100 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0);
6101 fprintf(fout, " cond_%s = %s;\n",
6102 parsed_flag_op_names[j], buf1);
6103 pfomask &= ~(1 << j);
6109 if (pfomask & (1 << PFO_C))
6110 // carry is unaffected by inc/dec.. wtf?
6111 ferr(po, "carry propagation needed\n");
6113 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6114 if (po->operand[0].type == OPT_REG) {
6115 strcpy(buf2, po->op == OP_INC ? "++" : "--");
6116 fprintf(fout, " %s%s;", buf1, buf2);
6119 strcpy(buf2, po->op == OP_INC ? "+" : "-");
6120 fprintf(fout, " %s %s= 1;", buf1, buf2);
6122 output_std_flags(fout, po, &pfomask, buf1);
6123 last_arith_dst = &po->operand[0];
6124 delayed_flag_op = NULL;
6128 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6129 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
6130 fprintf(fout, " %s = -%s%s;", buf1,
6131 lmod_cast_s(po, po->operand[0].lmod), buf2);
6132 last_arith_dst = &po->operand[0];
6133 delayed_flag_op = NULL;
6134 if (pfomask & (1 << PFO_C)) {
6135 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
6136 pfomask &= ~(1 << PFO_C);
6141 if (po->operand_cnt == 2) {
6142 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6145 if (po->operand_cnt == 3)
6146 ferr(po, "TODO imul3\n");
6149 assert_operand_cnt(1);
6150 switch (po->operand[0].lmod) {
6152 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
6153 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
6154 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
6155 fprintf(fout, " edx = tmp64 >> 32;\n");
6156 fprintf(fout, " eax = tmp64;");
6159 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
6160 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
6161 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
6165 ferr(po, "TODO: unhandled mul type\n");
6168 last_arith_dst = NULL;
6169 delayed_flag_op = NULL;
6174 assert_operand_cnt(1);
6175 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6176 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
6177 po->op == OP_IDIV));
6178 switch (po->operand[0].lmod) {
6180 if (po->flags & OPF_32BIT)
6181 snprintf(buf2, sizeof(buf2), "%seax", cast);
6183 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
6184 snprintf(buf2, sizeof(buf2), "%stmp64",
6185 (po->op == OP_IDIV) ? "(s64)" : "");
6187 if (po->operand[0].type == OPT_REG
6188 && po->operand[0].reg == xDX)
6190 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
6191 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
6194 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
6195 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
6199 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
6200 snprintf(buf2, sizeof(buf2), "%stmp",
6201 (po->op == OP_IDIV) ? "(s32)" : "");
6202 if (po->operand[0].type == OPT_REG
6203 && po->operand[0].reg == xDX)
6205 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
6207 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
6211 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
6213 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
6216 strcat(g_comment, " div16");
6219 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
6221 last_arith_dst = NULL;
6222 delayed_flag_op = NULL;
6227 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6229 for (j = 0; j < 8; j++) {
6230 if (pfomask & (1 << j)) {
6231 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
6232 fprintf(fout, " cond_%s = %s;",
6233 parsed_flag_op_names[j], buf1);
6240 last_arith_dst = NULL;
6241 delayed_flag_op = po;
6245 // SETcc - should already be handled
6248 // note: we reuse OP_Jcc for SETcc, only flags differ
6250 fprintf(fout, "\n goto %s;", po->operand[0].name);
6254 fprintf(fout, " if (ecx == 0)\n");
6255 fprintf(fout, " goto %s;", po->operand[0].name);
6256 strcat(g_comment, " jecxz");
6260 fprintf(fout, " if (--ecx != 0)\n");
6261 fprintf(fout, " goto %s;", po->operand[0].name);
6262 strcat(g_comment, " loop");
6266 assert_operand_cnt(1);
6267 last_arith_dst = NULL;
6268 delayed_flag_op = NULL;
6270 if (po->operand[0].type == OPT_REGMEM) {
6271 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
6274 ferr(po, "parse failure for jmp '%s'\n",
6275 po->operand[0].name);
6276 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
6279 else if (po->operand[0].type != OPT_LABEL)
6280 ferr(po, "unhandled jmp type\n");
6282 fprintf(fout, " goto %s;", po->operand[0].name);
6286 assert_operand_cnt(1);
6288 my_assert_not(pp, NULL);
6291 if (po->flags & OPF_CC) {
6292 // we treat conditional branch to another func
6293 // (yes such code exists..) as conditional tailcall
6295 fprintf(fout, " {\n");
6298 if (pp->is_fptr && !pp->is_arg) {
6299 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
6300 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6302 if (pp->is_unresolved)
6303 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
6304 buf3, asmfn, po->asmln, pp->name);
6307 fprintf(fout, "%s", buf3);
6308 if (strstr(pp->ret_type.name, "int64")) {
6309 if (po->flags & OPF_TAIL)
6310 ferr(po, "int64 and tail?\n");
6311 fprintf(fout, "tmp64 = ");
6313 else if (!IS(pp->ret_type.name, "void")) {
6314 if (po->flags & OPF_TAIL) {
6315 if (regmask_ret & mxAX) {
6316 fprintf(fout, "return ");
6317 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
6318 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
6320 else if (regmask_ret & mxST0)
6321 ferr(po, "float tailcall\n");
6323 else if (po->regmask_dst & mxAX) {
6324 fprintf(fout, "eax = ");
6325 if (pp->ret_type.is_ptr)
6326 fprintf(fout, "(u32)");
6328 else if (po->regmask_dst & mxST0) {
6329 fprintf(fout, "f_st0 = ");
6333 if (pp->name[0] == 0)
6334 ferr(po, "missing pp->name\n");
6335 fprintf(fout, "%s%s(", pp->name,
6336 pp->has_structarg ? "_sa" : "");
6338 if (po->flags & OPF_ATAIL) {
6339 if (pp->argc_stack != g_func_pp->argc_stack
6340 || (pp->argc_stack > 0
6341 && pp->is_stdcall != g_func_pp->is_stdcall))
6342 ferr(po, "incompatible tailcall\n");
6343 if (g_func_pp->has_retreg)
6344 ferr(po, "TODO: retreg+tailcall\n");
6346 for (arg = j = 0; arg < pp->argc; arg++) {
6348 fprintf(fout, ", ");
6351 if (pp->arg[arg].type.is_ptr)
6352 snprintf(cast, sizeof(cast), "(%s)",
6353 pp->arg[arg].type.name);
6355 if (pp->arg[arg].reg != NULL) {
6356 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6360 for (; j < g_func_pp->argc; j++)
6361 if (g_func_pp->arg[j].reg == NULL)
6363 fprintf(fout, "%sa%d", cast, j + 1);
6368 for (arg = 0; arg < pp->argc; arg++) {
6370 fprintf(fout, ", ");
6373 if (pp->arg[arg].type.is_ptr)
6374 snprintf(cast, sizeof(cast), "(%s)",
6375 pp->arg[arg].type.name);
6377 if (pp->arg[arg].reg != NULL) {
6378 if (pp->arg[arg].type.is_retreg)
6379 fprintf(fout, "&%s", pp->arg[arg].reg);
6381 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6386 tmp_op = pp->arg[arg].datap;
6388 ferr(po, "parsed_op missing for arg%d\n", arg);
6390 if (tmp_op->flags & OPF_VAPUSH) {
6391 fprintf(fout, "ap");
6393 else if (tmp_op->p_argpass != 0) {
6394 fprintf(fout, "a%d", tmp_op->p_argpass);
6396 else if (tmp_op->p_argnum != 0) {
6397 fprintf(fout, "%s%s", cast,
6398 saved_arg_name(buf1, sizeof(buf1),
6399 tmp_op->p_arggrp, tmp_op->p_argnum));
6403 out_src_opr(buf1, sizeof(buf1),
6404 tmp_op, &tmp_op->operand[0], cast, 0));
6408 fprintf(fout, ");");
6410 if (strstr(pp->ret_type.name, "int64")) {
6411 fprintf(fout, "\n");
6412 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
6413 fprintf(fout, "%seax = tmp64;", buf3);
6416 if (pp->is_unresolved) {
6417 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
6419 strcat(g_comment, buf2);
6422 if (po->flags & OPF_TAIL) {
6424 if (i == opcnt - 1 || pp->is_noreturn)
6426 else if (IS(pp->ret_type.name, "void"))
6428 else if (!(regmask_ret & (1 << xAX)))
6430 // else already handled as 'return f()'
6433 fprintf(fout, "\n%sreturn;", buf3);
6434 strcat(g_comment, " ^ tailcall");
6437 strcat(g_comment, " tailcall");
6439 if ((regmask_ret & (1 << xAX))
6440 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
6442 ferr(po, "int func -> void func tailcall?\n");
6445 if (pp->is_noreturn)
6446 strcat(g_comment, " noreturn");
6447 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
6448 strcat(g_comment, " argframe");
6449 if (po->flags & OPF_CC)
6450 strcat(g_comment, " cond");
6452 if (po->flags & OPF_CC)
6453 fprintf(fout, "\n }");
6455 delayed_flag_op = NULL;
6456 last_arith_dst = NULL;
6460 if (g_func_pp->is_vararg)
6461 fprintf(fout, " va_end(ap);\n");
6462 if (g_func_pp->has_retreg) {
6463 for (arg = 0; arg < g_func_pp->argc; arg++)
6464 if (g_func_pp->arg[arg].type.is_retreg)
6465 fprintf(fout, " *r_%s = %s;\n",
6466 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
6469 if (!(regmask_ret & (1 << xAX))) {
6470 if (i != opcnt - 1 || label_pending)
6471 fprintf(fout, " return;");
6473 else if (g_func_pp->ret_type.is_ptr) {
6474 fprintf(fout, " return (%s)eax;",
6475 g_func_pp->ret_type.name);
6477 else if (IS(g_func_pp->ret_type.name, "__int64"))
6478 fprintf(fout, " return ((u64)edx << 32) | eax;");
6480 fprintf(fout, " return eax;");
6482 last_arith_dst = NULL;
6483 delayed_flag_op = NULL;
6487 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6488 if (po->p_argnum != 0) {
6489 // special case - saved func arg
6490 fprintf(fout, " %s = %s;",
6491 saved_arg_name(buf2, sizeof(buf2),
6492 po->p_arggrp, po->p_argnum), buf1);
6495 else if (po->flags & OPF_RSAVE) {
6496 fprintf(fout, " s_%s = %s;", buf1, buf1);
6499 else if (po->flags & OPF_PPUSH) {
6501 ferr_assert(po, tmp_op != NULL);
6502 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
6503 fprintf(fout, " pp_%s = %s;", buf2, buf1);
6506 else if (g_func_pp->is_userstack) {
6507 fprintf(fout, " *(--esp) = %s;", buf1);
6510 if (!(g_ida_func_attr & IDAFA_NORETURN))
6511 ferr(po, "stray push encountered\n");
6516 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6517 if (po->flags & OPF_RSAVE) {
6518 fprintf(fout, " %s = s_%s;", buf1, buf1);
6521 else if (po->flags & OPF_PPUSH) {
6522 // push/pop graph / non-const
6523 ferr_assert(po, po->datap == NULL);
6524 fprintf(fout, " %s = pp_%s;", buf1, buf1);
6527 else if (po->datap != NULL) {
6530 fprintf(fout, " %s = %s;", buf1,
6531 out_src_opr(buf2, sizeof(buf2),
6532 tmp_op, &tmp_op->operand[0],
6533 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6536 else if (g_func_pp->is_userstack) {
6537 fprintf(fout, " %s = *esp++;", buf1);
6541 ferr(po, "stray pop encountered\n");
6550 if (po->flags & OPF_FSHIFT)
6551 fprintf(fout, " f_st1 = f_st0;\n");
6552 if (po->operand[0].type == OPT_REG
6553 && po->operand[0].reg == xST0)
6555 strcat(g_comment, " fld st");
6558 fprintf(fout, " f_st0 = %s;",
6559 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0]));
6560 strcat(g_comment, " fld");
6564 if (po->flags & OPF_FSHIFT)
6565 fprintf(fout, " f_st1 = f_st0;\n");
6566 fprintf(fout, " f_st0 = (double)%s;",
6567 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6568 lmod_cast(po, po->operand[0].lmod, 1), 0));
6569 strcat(g_comment, " fild");
6573 if (po->flags & OPF_FSHIFT)
6574 fprintf(fout, " f_st1 = f_st0;\n");
6575 fprintf(fout, " f_st0 = ");
6576 switch (po->operand[0].val) {
6577 case X87_CONST_1: fprintf(fout, "1.0;"); break;
6578 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
6579 default: ferr(po, "TODO\n"); break;
6584 if ((po->flags & OPF_FPOP) && po->operand[0].type == OPT_REG
6585 && po->operand[0].reg == xST0)
6590 fprintf(fout, " %s = f_st0;",
6591 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0]));
6592 if (po->flags & OPF_FSHIFT)
6593 fprintf(fout, "\n f_st0 = f_st1;");
6594 strcat(g_comment, " fst");
6602 case OP_FADD: j = '+'; break;
6603 case OP_FDIV: j = '/'; break;
6604 case OP_FMUL: j = '*'; break;
6605 case OP_FSUB: j = '-'; break;
6606 default: j = 'x'; break;
6608 if (po->flags & OPF_FSHIFT) {
6609 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
6612 fprintf(fout, " %s %c= %s;",
6613 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0]),
6615 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1]));
6621 if (po->flags & OPF_FSHIFT)
6622 snprintf(buf1, sizeof(buf1), "f_st0");
6624 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0]);
6625 fprintf(fout, " %s = %s %c %s;", buf1,
6626 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1]),
6627 po->op == OP_FDIVR ? '/' : '-',
6628 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0]));
6636 case OP_FIADD: j = '+'; break;
6637 case OP_FIDIV: j = '/'; break;
6638 case OP_FIMUL: j = '*'; break;
6639 case OP_FISUB: j = '-'; break;
6640 default: j = 'x'; break;
6642 fprintf(fout, " f_st0 %c= (double)%s;", j,
6643 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6644 lmod_cast(po, po->operand[0].lmod, 1), 0));
6649 fprintf(fout, " f_st0 = %s %c f_st0;",
6650 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1]),
6651 po->op == OP_FIDIVR ? '/' : '-');
6655 ferr_assert(po, po->flags & OPF_32BIT);
6656 fprintf(fout, " eax = (s32)f_st0;");
6657 if (po->flags & OPF_FSHIFT)
6658 fprintf(fout, "\n f_st0 = f_st1;");
6659 strcat(g_comment, " ftol");
6664 strcpy(g_comment, " (emms)");
6669 ferr(po, "unhandled op type %d, flags %x\n",
6674 if (g_comment[0] != 0) {
6675 char *p = g_comment;
6676 while (my_isblank(*p))
6678 fprintf(fout, " // %s", p);
6683 fprintf(fout, "\n");
6685 // some sanity checking
6686 if (po->flags & OPF_REP) {
6687 if (po->op != OP_STOS && po->op != OP_MOVS
6688 && po->op != OP_CMPS && po->op != OP_SCAS)
6689 ferr(po, "unexpected rep\n");
6690 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
6691 && (po->op == OP_CMPS || po->op == OP_SCAS))
6692 ferr(po, "cmps/scas with plain rep\n");
6694 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
6695 && po->op != OP_CMPS && po->op != OP_SCAS)
6696 ferr(po, "unexpected repz/repnz\n");
6699 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
6701 // see is delayed flag stuff is still valid
6702 if (delayed_flag_op != NULL && delayed_flag_op != po) {
6703 if (is_any_opr_modified(delayed_flag_op, po, 0))
6704 delayed_flag_op = NULL;
6707 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
6708 if (is_opr_modified(last_arith_dst, po))
6709 last_arith_dst = NULL;
6715 if (g_stack_fsz && !g_stack_frame_used)
6716 fprintf(fout, " (void)sf;\n");
6718 fprintf(fout, "}\n\n");
6720 gen_x_cleanup(opcnt);
6723 static void gen_x_cleanup(int opcnt)
6727 for (i = 0; i < opcnt; i++) {
6728 struct label_ref *lr, *lr_del;
6730 lr = g_label_refs[i].next;
6731 while (lr != NULL) {
6736 g_label_refs[i].i = -1;
6737 g_label_refs[i].next = NULL;
6739 if (ops[i].op == OP_CALL) {
6741 proto_release(ops[i].pp);
6747 struct func_proto_dep;
6749 struct func_prototype {
6754 int has_ret:3; // -1, 0, 1: unresolved, no, yes
6755 unsigned int dep_resolved:1;
6756 unsigned int is_stdcall:1;
6757 struct func_proto_dep *dep_func;
6759 const struct parsed_proto *pp; // seed pp, if any
6762 struct func_proto_dep {
6764 struct func_prototype *proto;
6765 int regmask_live; // .. at the time of call
6766 unsigned int ret_dep:1; // return from this is caller's return
6769 static struct func_prototype *hg_fp;
6770 static int hg_fp_cnt;
6772 static struct scanned_var {
6774 enum opr_lenmod lmod;
6775 unsigned int is_seeded:1;
6776 unsigned int is_c_str:1;
6777 const struct parsed_proto *pp; // seed pp, if any
6779 static int hg_var_cnt;
6781 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
6784 struct func_prototype *hg_fp_add(const char *funcn)
6786 struct func_prototype *fp;
6788 if ((hg_fp_cnt & 0xff) == 0) {
6789 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
6790 my_assert_not(hg_fp, NULL);
6791 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
6794 fp = &hg_fp[hg_fp_cnt];
6795 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
6797 fp->argc_stack = -1;
6803 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
6808 for (i = 0; i < fp->dep_func_cnt; i++)
6809 if (IS(fp->dep_func[i].name, name))
6810 return &fp->dep_func[i];
6815 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
6818 if (hg_fp_find_dep(fp, name))
6821 if ((fp->dep_func_cnt & 0xff) == 0) {
6822 fp->dep_func = realloc(fp->dep_func,
6823 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
6824 my_assert_not(fp->dep_func, NULL);
6825 memset(&fp->dep_func[fp->dep_func_cnt], 0,
6826 sizeof(fp->dep_func[0]) * 0x100);
6828 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
6832 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
6834 const struct func_prototype *p1 = p1_, *p2 = p2_;
6835 return strcmp(p1->name, p2->name);
6839 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
6841 const struct func_prototype *p1 = p1_, *p2 = p2_;
6842 return p1->id - p2->id;
6846 // recursive register dep pass
6847 // - track saved regs (part 2)
6848 // - try to figure out arg-regs
6849 // - calculate reg deps
6850 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
6851 struct func_prototype *fp, int regmask_save, int regmask_dst,
6852 int *regmask_dep, int *has_ret)
6854 struct func_proto_dep *dep;
6855 struct parsed_op *po;
6856 int from_caller = 0;
6861 for (; i < opcnt; i++)
6863 if (cbits[i >> 3] & (1 << (i & 7)))
6865 cbits[i >> 3] |= (1 << (i & 7));
6869 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
6870 if (po->flags & OPF_RMD)
6873 if (po->btj != NULL) {
6875 for (j = 0; j < po->btj->count; j++) {
6876 check_i(po, po->btj->d[j].bt_i);
6877 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
6878 regmask_save, regmask_dst, regmask_dep, has_ret);
6883 check_i(po, po->bt_i);
6884 if (po->flags & OPF_CJMP) {
6885 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
6886 regmask_save, regmask_dst, regmask_dep, has_ret);
6894 if (po->flags & OPF_FARG)
6895 /* (just calculate register deps) */;
6896 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
6898 reg = po->operand[0].reg;
6899 ferr_assert(po, reg >= 0);
6901 if (po->flags & OPF_RSAVE) {
6902 regmask_save |= 1 << reg;
6905 if (po->flags & OPF_DONE)
6908 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0);
6910 regmask_save |= 1 << reg;
6911 po->flags |= OPF_RMD;
6912 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, OPF_RMD);
6916 else if (po->flags & OPF_RMD)
6918 else if (po->op == OP_CALL) {
6919 po->regmask_dst |= 1 << xAX;
6921 dep = hg_fp_find_dep(fp, po->operand[0].name);
6923 dep->regmask_live = regmask_save | regmask_dst;
6925 else if (po->op == OP_RET) {
6926 if (po->operand_cnt > 0) {
6928 if (fp->argc_stack >= 0
6929 && fp->argc_stack != po->operand[0].val / 4)
6930 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
6931 fp->argc_stack = po->operand[0].val / 4;
6935 // if has_ret is 0, there is uninitialized eax path,
6936 // which means it's most likely void func
6937 if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
6938 if (po->op == OP_CALL) {
6943 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
6946 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
6949 if (ret != 1 && from_caller) {
6950 // unresolved eax - probably void func
6954 if (j >= 0 && ops[j].op == OP_CALL) {
6955 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
6966 l = regmask_save | regmask_dst;
6967 if (g_bp_frame && !(po->flags & OPF_EBP_S))
6970 l = po->regmask_src & ~l;
6973 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
6974 l, regmask_dst, regmask_save, po->flags);
6977 regmask_dst |= po->regmask_dst;
6979 if (po->flags & OPF_TAIL)
6984 static void gen_hdr(const char *funcn, int opcnt)
6986 int save_arg_vars[MAX_ARG_GRP] = { 0, };
6987 unsigned char cbits[MAX_OPS / 8];
6988 const struct parsed_proto *pp_c;
6989 struct parsed_proto *pp;
6990 struct func_prototype *fp;
6991 struct parsed_op *po;
6992 int regmask_dummy = 0;
6994 int max_bp_offset = 0;
6999 pp_c = proto_parse(g_fhdr, funcn, 1);
7001 // already in seed, will add to hg_fp later
7004 fp = hg_fp_add(funcn);
7006 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
7007 g_stack_frame_used = 0;
7010 // - resolve all branches
7011 // - parse calls with labels
7012 resolve_branches_parse_calls(opcnt);
7015 // - handle ebp/esp frame, remove ops related to it
7016 scan_prologue_epilogue(opcnt);
7019 // - remove dead labels
7021 for (i = 0; i < opcnt; i++)
7023 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7029 if (po->flags & (OPF_RMD|OPF_DONE))
7032 if (po->op == OP_CALL) {
7033 if (po->operand[0].type == OPT_LABEL)
7034 hg_fp_add_dep(fp, opr_name(po, 0));
7035 else if (po->pp != NULL)
7036 hg_fp_add_dep(fp, po->pp->name);
7041 // - remove dead labels
7042 // - handle push <const>/pop pairs
7043 for (i = 0; i < opcnt; i++)
7045 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7051 if (po->flags & (OPF_RMD|OPF_DONE))
7054 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
7055 scan_for_pop_const(i, opcnt, i + opcnt * 13);
7059 // - process trivial calls
7060 for (i = 0; i < opcnt; i++)
7063 if (po->flags & (OPF_RMD|OPF_DONE))
7066 if (po->op == OP_CALL)
7068 pp = process_call_early(i, opcnt, &j);
7070 if (!(po->flags & OPF_ATAIL))
7071 // since we know the args, try to collect them
7072 if (collect_call_args_early(po, i, pp, ®mask_dummy) != 0)
7078 // commit esp adjust
7079 if (ops[j].op != OP_POP)
7080 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
7082 for (l = 0; l < pp->argc_stack; l++)
7083 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
7087 po->flags |= OPF_DONE;
7093 // - track saved regs (simple)
7095 for (i = 0; i < opcnt; i++)
7098 if (po->flags & (OPF_RMD|OPF_DONE))
7101 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
7102 && po->operand[0].reg != xCX)
7104 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
7106 // regmask_save |= 1 << po->operand[0].reg; // do it later
7107 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
7108 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
7111 else if (po->op == OP_CALL)
7113 pp = process_call(i, opcnt);
7115 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
7116 // since we know the args, collect them
7117 ret = collect_call_args(po, i, pp, ®mask_dummy, save_arg_vars,
7124 memset(cbits, 0, sizeof(cbits));
7128 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, ®mask_dep, &has_ret);
7130 // find unreachable code - must be fixed in IDA
7131 for (i = 0; i < opcnt; i++)
7133 if (cbits[i >> 3] & (1 << (i & 7)))
7136 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
7137 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
7139 // the compiler sometimes still generates code after
7140 // noreturn OS functions
7143 if (ops[i].op != OP_NOP)
7144 ferr(&ops[i], "unreachable code\n");
7147 for (i = 0; i < g_eqcnt; i++) {
7148 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
7149 max_bp_offset = g_eqs[i].offset;
7152 if (fp->argc_stack < 0) {
7153 max_bp_offset = (max_bp_offset + 3) & ~3;
7154 fp->argc_stack = max_bp_offset / 4;
7155 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
7159 fp->regmask_dep = regmask_dep & ~(1 << xSP);
7160 fp->has_ret = has_ret;
7162 printf("// has_ret %d, regmask_dep %x\n",
7163 fp->has_ret, fp->regmask_dep);
7164 output_hdr_fp(stdout, fp, 1);
7165 if (IS(funcn, "sub_10007F72")) exit(1);
7168 gen_x_cleanup(opcnt);
7171 static void hg_fp_resolve_deps(struct func_prototype *fp)
7173 struct func_prototype fp_s;
7177 // this thing is recursive, so mark first..
7178 fp->dep_resolved = 1;
7180 for (i = 0; i < fp->dep_func_cnt; i++) {
7181 strcpy(fp_s.name, fp->dep_func[i].name);
7182 fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
7183 sizeof(hg_fp[0]), hg_fp_cmp_name);
7184 if (fp->dep_func[i].proto != NULL) {
7185 if (!fp->dep_func[i].proto->dep_resolved)
7186 hg_fp_resolve_deps(fp->dep_func[i].proto);
7188 dep = ~fp->dep_func[i].regmask_live
7189 & fp->dep_func[i].proto->regmask_dep;
7190 fp->regmask_dep |= dep;
7191 // printf("dep %s %s |= %x\n", fp->name,
7192 // fp->dep_func[i].name, dep);
7194 if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
7195 fp->has_ret = fp->dep_func[i].proto->has_ret;
7200 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7203 const struct parsed_proto *pp;
7204 char *p, namebuf[NAMELEN];
7210 for (; count > 0; count--, fp++) {
7211 if (fp->has_ret == -1)
7212 fprintf(fout, "// ret unresolved\n");
7214 fprintf(fout, "// dep:");
7215 for (j = 0; j < fp->dep_func_cnt; j++) {
7216 fprintf(fout, " %s/", fp->dep_func[j].name);
7217 if (fp->dep_func[j].proto != NULL)
7218 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
7219 fp->dep_func[j].proto->has_ret);
7221 fprintf(fout, "\n");
7224 p = strchr(fp->name, '@');
7226 memcpy(namebuf, fp->name, p - fp->name);
7227 namebuf[p - fp->name] = 0;
7235 pp = proto_parse(g_fhdr, name, 1);
7236 if (pp != NULL && pp->is_include)
7239 if (fp->pp != NULL) {
7240 // part of seed, output later
7244 regmask_dep = fp->regmask_dep;
7245 argc_stack = fp->argc_stack;
7247 fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
7248 (fp->has_ret ? "int" : "void"));
7249 if (regmask_dep && (fp->is_stdcall || argc_stack == 0)
7250 && (regmask_dep & ~((1 << xCX) | (1 << xDX))) == 0)
7252 fprintf(fout, " __fastcall ");
7253 if (!(regmask_dep & (1 << xDX)) && argc_stack == 0)
7259 else if (regmask_dep && !fp->is_stdcall) {
7260 fprintf(fout, "/*__usercall*/ ");
7262 else if (regmask_dep) {
7263 fprintf(fout, "/*__userpurge*/ ");
7265 else if (fp->is_stdcall)
7266 fprintf(fout, " __stdcall ");
7268 fprintf(fout, " __cdecl ");
7270 fprintf(fout, "%s(", name);
7273 for (j = 0; j < xSP; j++) {
7274 if (regmask_dep & (1 << j)) {
7277 fprintf(fout, ", ");
7279 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
7281 fprintf(fout, "int");
7282 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
7286 for (j = 0; j < argc_stack; j++) {
7289 fprintf(fout, ", ");
7290 if (fp->pp != NULL) {
7291 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
7292 if (!fp->pp->arg[arg - 1].type.is_ptr)
7296 fprintf(fout, "int ");
7297 fprintf(fout, "a%d", arg);
7300 fprintf(fout, ");\n");
7304 static void output_hdr(FILE *fout)
7306 static const char *lmod_c_names[] = {
7307 [OPLM_UNSPEC] = "???",
7308 [OPLM_BYTE] = "uint8_t",
7309 [OPLM_WORD] = "uint16_t",
7310 [OPLM_DWORD] = "uint32_t",
7311 [OPLM_QWORD] = "uint64_t",
7313 const struct scanned_var *var;
7314 struct func_prototype *fp;
7315 char line[256] = { 0, };
7319 // add stuff from headers
7320 for (i = 0; i < pp_cache_size; i++) {
7321 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
7322 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
7324 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
7325 fp = hg_fp_add(name);
7326 fp->pp = &pp_cache[i];
7327 fp->argc_stack = fp->pp->argc_stack;
7328 fp->is_stdcall = fp->pp->is_stdcall;
7329 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
7330 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
7334 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
7335 for (i = 0; i < hg_fp_cnt; i++)
7336 hg_fp_resolve_deps(&hg_fp[i]);
7338 // note: messes up .proto ptr, don't use
7339 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
7342 for (i = 0; i < hg_var_cnt; i++) {
7345 if (var->pp != NULL)
7348 else if (var->is_c_str)
7349 fprintf(fout, "extern %-8s %s[];", "char", var->name);
7351 fprintf(fout, "extern %-8s %s;",
7352 lmod_c_names[var->lmod], var->name);
7355 fprintf(fout, " // seeded");
7356 fprintf(fout, "\n");
7359 fprintf(fout, "\n");
7361 // output function prototypes
7362 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
7365 fprintf(fout, "\n// - seed -\n");
7368 while (fgets(line, sizeof(line), g_fhdr))
7369 fwrite(line, 1, strlen(line), fout);
7372 // '=' needs special treatment
7374 static char *next_word_s(char *w, size_t wsize, char *s)
7383 for (i = 1; i < wsize - 1; i++) {
7385 printf("warning: missing closing quote: \"%s\"\n", s);
7394 for (; i < wsize - 1; i++) {
7395 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
7401 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
7402 printf("warning: '%s' truncated\n", w);
7407 static int cmpstringp(const void *p1, const void *p2)
7409 return strcmp(*(char * const *)p1, *(char * const *)p2);
7412 static int is_xref_needed(char *p, char **rlist, int rlist_len)
7417 if (strstr(p, "..."))
7418 // unable to determine, assume needed
7421 if (*p == '.') // .text, .data, ...
7422 // ref from other data or non-function -> no
7425 p2 = strpbrk(p, "+:\r\n\x18");
7428 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
7429 // referenced from removed code
7435 static int xrefs_show_need(FILE *fasm, char *p,
7436 char **rlist, int rlist_len)
7442 p = strrchr(p, ';');
7443 if (p != NULL && *p == ';' && IS_START(p + 2, "DATA XREF: ")) {
7445 if (is_xref_needed(p, rlist, rlist_len))
7452 if (!my_fgets(line, sizeof(line), fasm))
7454 // non-first line is always indented
7455 if (!my_isblank(line[0]))
7458 // should be no content, just comment
7463 p = strrchr(p, ';');
7465 // it's printed once, but no harm to check again
7466 if (IS_START(p, "DATA XREF: "))
7469 if (is_xref_needed(p, rlist, rlist_len)) {
7474 fseek(fasm, pos, SEEK_SET);
7478 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
7480 struct scanned_var *var;
7481 char line[256] = { 0, };
7489 // skip to next data section
7490 while (my_fgets(line, sizeof(line), fasm))
7495 if (*p == 0 || *p == ';')
7498 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
7499 if (*p == 0 || *p == ';')
7502 if (*p != 's' || !IS_START(p, "segment para public"))
7508 if (p == NULL || !IS_START(p, "segment para public"))
7512 if (!IS_START(p, "'DATA'"))
7516 while (my_fgets(line, sizeof(line), fasm))
7525 if (*p == 0 || *p == ';')
7528 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
7529 words[wordc][0] = 0;
7530 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
7531 if (*p == 0 || *p == ';') {
7537 if (wordc == 2 && IS(words[1], "ends"))
7542 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
7543 // when this starts, we don't need anything from this section
7547 // check refs comment(s)
7548 if (!xrefs_show_need(fasm, p, rlist, rlist_len))
7551 if ((hg_var_cnt & 0xff) == 0) {
7552 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
7553 * (hg_var_cnt + 0x100));
7554 my_assert_not(hg_vars, NULL);
7555 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
7558 var = &hg_vars[hg_var_cnt++];
7559 snprintf(var->name, sizeof(var->name), "%s", words[0]);
7561 // maybe already in seed header?
7562 var->pp = proto_parse(g_fhdr, var->name, 1);
7563 if (var->pp != NULL) {
7564 if (var->pp->is_fptr) {
7565 var->lmod = OPLM_DWORD;
7568 else if (var->pp->is_func)
7570 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
7571 aerr("unhandled C type '%s' for '%s'\n",
7572 var->pp->type.name, var->name);
7578 if (IS(words[1], "dd"))
7579 var->lmod = OPLM_DWORD;
7580 else if (IS(words[1], "dw"))
7581 var->lmod = OPLM_WORD;
7582 else if (IS(words[1], "db")) {
7583 var->lmod = OPLM_BYTE;
7584 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
7585 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
7589 else if (IS(words[1], "dq"))
7590 var->lmod = OPLM_QWORD;
7591 //else if (IS(words[1], "dt"))
7593 aerr("type '%s' not known\n", words[1]);
7601 static void set_label(int i, const char *name)
7607 p = strchr(name, ':');
7611 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
7612 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
7613 g_labels[i] = realloc(g_labels[i], len + 1);
7614 my_assert_not(g_labels[i], NULL);
7615 memcpy(g_labels[i], name, len);
7616 g_labels[i][len] = 0;
7625 static struct chunk_item *func_chunks;
7626 static int func_chunk_cnt;
7627 static int func_chunk_alloc;
7629 static void add_func_chunk(FILE *fasm, const char *name, int line)
7631 if (func_chunk_cnt >= func_chunk_alloc) {
7632 func_chunk_alloc *= 2;
7633 func_chunks = realloc(func_chunks,
7634 func_chunk_alloc * sizeof(func_chunks[0]));
7635 my_assert_not(func_chunks, NULL);
7637 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
7638 func_chunks[func_chunk_cnt].name = strdup(name);
7639 func_chunks[func_chunk_cnt].asmln = line;
7643 static int cmp_chunks(const void *p1, const void *p2)
7645 const struct chunk_item *c1 = p1, *c2 = p2;
7646 return strcmp(c1->name, c2->name);
7649 static void scan_ahead(FILE *fasm)
7659 oldpos = ftell(fasm);
7662 while (my_fgets(line, sizeof(line), fasm))
7673 // get rid of random tabs
7674 for (i = 0; line[i] != 0; i++)
7675 if (line[i] == '\t')
7678 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
7681 next_word(words[0], sizeof(words[0]), p);
7682 if (words[0][0] == 0)
7683 aerr("missing name for func chunk?\n");
7685 add_func_chunk(fasm, words[0], asmln);
7687 else if (IS_START(p, "; sctend"))
7693 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
7694 words[wordc][0] = 0;
7695 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
7696 if (*p == 0 || *p == ';') {
7702 if (wordc == 2 && IS(words[1], "ends"))
7706 fseek(fasm, oldpos, SEEK_SET);
7710 int main(int argc, char *argv[])
7712 FILE *fout, *fasm, *frlist;
7713 struct parsed_data *pd = NULL;
7715 char **rlist = NULL;
7717 int rlist_alloc = 0;
7718 int func_chunks_used = 0;
7719 int func_chunks_sorted = 0;
7720 int func_chunk_i = -1;
7721 long func_chunk_ret = 0;
7722 int func_chunk_ret_ln = 0;
7723 int scanned_ahead = 0;
7725 char words[20][256];
7726 enum opr_lenmod lmod;
7727 char *sctproto = NULL;
7729 int pending_endp = 0;
7731 int skip_warned = 0;
7744 for (arg = 1; arg < argc; arg++) {
7745 if (IS(argv[arg], "-v"))
7747 else if (IS(argv[arg], "-rf"))
7748 g_allow_regfunc = 1;
7749 else if (IS(argv[arg], "-m"))
7751 else if (IS(argv[arg], "-hdr"))
7752 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
7757 if (argc < arg + 3) {
7758 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
7759 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
7761 " -hdr - header generation mode\n"
7762 " -rf - allow unannotated indirect calls\n"
7763 " -m - allow multiple .text sections\n"
7764 "[rlist] is a file with function names to skip,"
7772 asmfn = argv[arg++];
7773 fasm = fopen(asmfn, "r");
7774 my_assert_not(fasm, NULL);
7776 hdrfn = argv[arg++];
7777 g_fhdr = fopen(hdrfn, "r");
7778 my_assert_not(g_fhdr, NULL);
7781 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
7782 my_assert_not(rlist, NULL);
7783 // needs special handling..
7784 rlist[rlist_len++] = "__alloca_probe";
7786 func_chunk_alloc = 32;
7787 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
7788 my_assert_not(func_chunks, NULL);
7790 memset(words, 0, sizeof(words));
7792 for (; arg < argc; arg++) {
7793 frlist = fopen(argv[arg], "r");
7794 my_assert_not(frlist, NULL);
7796 while (my_fgets(line, sizeof(line), frlist)) {
7798 if (*p == 0 || *p == ';')
7801 if (IS_START(p, "#if 0")
7802 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
7806 else if (IS_START(p, "#endif"))
7813 p = next_word(words[0], sizeof(words[0]), p);
7814 if (words[0][0] == 0)
7817 if (rlist_len >= rlist_alloc) {
7818 rlist_alloc = rlist_alloc * 2 + 64;
7819 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
7820 my_assert_not(rlist, NULL);
7822 rlist[rlist_len++] = strdup(words[0]);
7831 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
7833 fout = fopen(argv[arg_out], "w");
7834 my_assert_not(fout, NULL);
7837 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
7838 my_assert_not(g_eqs, NULL);
7840 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
7841 g_label_refs[i].i = -1;
7842 g_label_refs[i].next = NULL;
7846 scan_variables(fasm, rlist, rlist_len);
7848 while (my_fgets(line, sizeof(line), fasm))
7857 // get rid of random tabs
7858 for (i = 0; line[i] != 0; i++)
7859 if (line[i] == '\t')
7864 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
7865 goto do_pending_endp; // eww..
7867 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
7869 static const char *attrs[] = {
7878 // parse IDA's attribute-list comment
7879 g_ida_func_attr = 0;
7882 for (; *p != 0; p = sskip(p)) {
7883 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
7884 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
7885 g_ida_func_attr |= 1 << i;
7886 p += strlen(attrs[i]);
7890 if (i == ARRAY_SIZE(attrs)) {
7891 anote("unparsed IDA attr: %s\n", p);
7894 if (IS(attrs[i], "fpd=")) {
7895 p = next_word(words[0], sizeof(words[0]), p);
7900 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
7902 static const char *attrs[] = {
7906 // parse manual attribute-list comment
7907 g_sct_func_attr = 0;
7910 for (; *p != 0; p = sskip(p)) {
7911 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
7912 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
7913 g_sct_func_attr |= 1 << i;
7914 p += strlen(attrs[i]);
7918 if (i == 0 && *p == '=') {
7919 // clear_sf=start,len (in dwords)
7920 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
7921 &g_stack_clear_len, &j);
7923 anote("unparsed clear_sf attr value: %s\n", p);
7928 else if (i == ARRAY_SIZE(attrs)) {
7929 anote("unparsed sct attr: %s\n", p);
7934 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
7937 next_word(words[0], sizeof(words[0]), p);
7938 if (words[0][0] == 0)
7939 aerr("missing name for func chunk?\n");
7941 if (!scanned_ahead) {
7942 add_func_chunk(fasm, words[0], asmln);
7943 func_chunks_sorted = 0;
7946 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
7948 if (func_chunk_i >= 0) {
7949 if (func_chunk_i < func_chunk_cnt
7950 && IS(func_chunks[func_chunk_i].name, g_func))
7952 // move on to next chunk
7953 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
7955 aerr("seek failed for '%s' chunk #%d\n",
7956 g_func, func_chunk_i);
7957 asmln = func_chunks[func_chunk_i].asmln;
7961 if (func_chunk_ret == 0)
7962 aerr("no return from chunk?\n");
7963 fseek(fasm, func_chunk_ret, SEEK_SET);
7964 asmln = func_chunk_ret_ln;
7970 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
7971 func_chunks_used = 1;
7973 if (IS_START(g_func, "sub_")) {
7974 unsigned long addr = strtoul(p, NULL, 16);
7975 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
7976 if (addr > f_addr && !scanned_ahead) {
7977 //anote("scan_ahead caused by '%s', addr %lx\n",
7981 func_chunks_sorted = 0;
7989 for (i = wordc; i < ARRAY_SIZE(words); i++)
7991 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
7992 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
7993 if (*p == 0 || *p == ';') {
7998 if (*p != 0 && *p != ';')
7999 aerr("too many words\n");
8001 // alow asm patches in comments
8003 if (IS_START(p, "; sctpatch:")) {
8005 if (*p == 0 || *p == ';')
8007 goto parse_words; // lame
8009 if (IS_START(p, "; sctproto:")) {
8010 sctproto = strdup(p + 11);
8012 else if (IS_START(p, "; sctend")) {
8021 awarn("wordc == 0?\n");
8025 // don't care about this:
8026 if (words[0][0] == '.'
8027 || IS(words[0], "include")
8028 || IS(words[0], "assume") || IS(words[1], "segment")
8029 || IS(words[0], "align"))
8035 // do delayed endp processing to collect switch jumptables
8037 if (in_func && !g_skip_func && !end && wordc >= 2
8038 && ((words[0][0] == 'd' && words[0][2] == 0)
8039 || (words[1][0] == 'd' && words[1][2] == 0)))
8042 if (words[1][0] == 'd' && words[1][2] == 0) {
8044 if (g_func_pd_cnt >= pd_alloc) {
8045 pd_alloc = pd_alloc * 2 + 16;
8046 g_func_pd = realloc(g_func_pd,
8047 sizeof(g_func_pd[0]) * pd_alloc);
8048 my_assert_not(g_func_pd, NULL);
8050 pd = &g_func_pd[g_func_pd_cnt];
8052 memset(pd, 0, sizeof(*pd));
8053 strcpy(pd->label, words[0]);
8054 pd->type = OPT_CONST;
8055 pd->lmod = lmod_from_directive(words[1]);
8061 anote("skipping alignment byte?\n");
8064 lmod = lmod_from_directive(words[0]);
8065 if (lmod != pd->lmod)
8066 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
8069 if (pd->count_alloc < pd->count + wordc) {
8070 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
8071 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
8072 my_assert_not(pd->d, NULL);
8074 for (; i < wordc; i++) {
8075 if (IS(words[i], "offset")) {
8076 pd->type = OPT_OFFSET;
8079 p = strchr(words[i], ',');
8082 if (pd->type == OPT_OFFSET)
8083 pd->d[pd->count].u.label = strdup(words[i]);
8085 pd->d[pd->count].u.val = parse_number(words[i]);
8086 pd->d[pd->count].bt_i = -1;
8092 if (in_func && !g_skip_func) {
8094 gen_hdr(g_func, pi);
8096 gen_func(fout, g_fhdr, g_func, pi);
8101 g_ida_func_attr = 0;
8102 g_sct_func_attr = 0;
8103 g_stack_clear_start = 0;
8104 g_stack_clear_len = 0;
8108 func_chunks_used = 0;
8111 memset(&ops, 0, pi * sizeof(ops[0]));
8116 for (i = 0; i < g_func_pd_cnt; i++) {
8118 if (pd->type == OPT_OFFSET) {
8119 for (j = 0; j < pd->count; j++)
8120 free(pd->d[j].u.label);
8135 if (IS(words[1], "proc")) {
8137 aerr("proc '%s' while in_func '%s'?\n",
8140 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8142 strcpy(g_func, words[0]);
8143 set_label(0, words[0]);
8148 if (IS(words[1], "endp"))
8151 aerr("endp '%s' while not in_func?\n", words[0]);
8152 if (!IS(g_func, words[0]))
8153 aerr("endp '%s' while in_func '%s'?\n",
8156 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
8157 && ops[0].op == OP_JMP && ops[0].operand[0].had_ds)
8163 if (!g_skip_func && func_chunks_used) {
8164 // start processing chunks
8165 struct chunk_item *ci, key = { g_func, 0 };
8167 func_chunk_ret = ftell(fasm);
8168 func_chunk_ret_ln = asmln;
8169 if (!func_chunks_sorted) {
8170 qsort(func_chunks, func_chunk_cnt,
8171 sizeof(func_chunks[0]), cmp_chunks);
8172 func_chunks_sorted = 1;
8174 ci = bsearch(&key, func_chunks, func_chunk_cnt,
8175 sizeof(func_chunks[0]), cmp_chunks);
8177 aerr("'%s' needs chunks, but none found\n", g_func);
8178 func_chunk_i = ci - func_chunks;
8179 for (; func_chunk_i > 0; func_chunk_i--)
8180 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
8183 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
8185 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
8186 asmln = func_chunks[func_chunk_i].asmln;
8194 if (wordc == 2 && IS(words[1], "ends")) {
8198 goto do_pending_endp;
8202 // scan for next text segment
8203 while (my_fgets(line, sizeof(line), fasm)) {
8206 if (*p == 0 || *p == ';')
8209 if (strstr(p, "segment para public 'CODE' use32"))
8216 p = strchr(words[0], ':');
8218 set_label(pi, words[0]);
8222 if (!in_func || g_skip_func) {
8223 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
8225 anote("skipping from '%s'\n", g_labels[pi]);
8229 g_labels[pi] = NULL;
8233 if (wordc > 1 && IS(words[1], "="))
8236 aerr("unhandled equ, wc=%d\n", wordc);
8237 if (g_eqcnt >= eq_alloc) {
8239 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
8240 my_assert_not(g_eqs, NULL);
8243 len = strlen(words[0]);
8244 if (len > sizeof(g_eqs[0].name) - 1)
8245 aerr("equ name too long: %d\n", len);
8246 strcpy(g_eqs[g_eqcnt].name, words[0]);
8248 if (!IS(words[3], "ptr"))
8249 aerr("unhandled equ\n");
8250 if (IS(words[2], "dword"))
8251 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
8252 else if (IS(words[2], "word"))
8253 g_eqs[g_eqcnt].lmod = OPLM_WORD;
8254 else if (IS(words[2], "byte"))
8255 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
8256 else if (IS(words[2], "qword"))
8257 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
8259 aerr("bad lmod: '%s'\n", words[2]);
8261 g_eqs[g_eqcnt].offset = parse_number(words[4]);
8266 if (pi >= ARRAY_SIZE(ops))
8267 aerr("too many ops\n");
8269 parse_op(&ops[pi], words, wordc);
8271 ops[pi].datap = sctproto;
8286 // vim:ts=2:shiftwidth=2:expandtab