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),
262 // note: limited to 32k due to p_argnext
264 #define MAX_ARG_GRP 2
266 static struct parsed_op ops[MAX_OPS];
267 static struct parsed_equ *g_eqs;
269 static char *g_labels[MAX_OPS];
270 static struct label_ref g_label_refs[MAX_OPS];
271 static const struct parsed_proto *g_func_pp;
272 static struct parsed_data *g_func_pd;
273 static int g_func_pd_cnt;
274 static int g_func_lmods;
275 static char g_func[256];
276 static char g_comment[256];
277 static int g_bp_frame;
278 static int g_sp_frame;
279 static int g_stack_frame_used;
280 static int g_stack_fsz;
281 static int g_ida_func_attr;
282 static int g_skip_func;
283 static int g_allow_regfunc;
284 static int g_quiet_pp;
285 static int g_header_mode;
287 #define ferr(op_, fmt, ...) do { \
288 printf("%s:%d: error %u: [%s] '%s': " fmt, asmfn, (op_)->asmln, \
289 __LINE__, g_func, dump_op(op_), ##__VA_ARGS__); \
293 #define fnote(op_, fmt, ...) \
294 printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
295 dump_op(op_), ##__VA_ARGS__)
297 #define ferr_assert(op_, cond) do { \
298 if (!(cond)) ferr(op_, "assertion '%s' failed\n", #cond); \
301 const char *regs_r32[] = {
302 "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
303 // not r32, but list here for easy parsing and printing
304 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
305 "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"
307 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
308 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
309 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
315 xMM0, xMM1, xMM2, xMM3, // mmx
316 xMM4, xMM5, xMM6, xMM7,
317 xST0, xST1, xST2, xST3, // x87
318 xST4, xST5, xST6, xST7,
321 #define mxAX (1 << xAX)
322 #define mxDX (1 << xDX)
323 #define mxST0 (1 << xST0)
324 #define mxST1 (1 << xST1)
326 // possible basic comparison types (without inversion)
327 enum parsed_flag_op {
331 PFO_BE, // 6 CF=1||ZF=1
335 PFO_LE, // e ZF=1||SF!=OF
338 #define PFOB_O (1 << PFO_O)
339 #define PFOB_C (1 << PFO_C)
340 #define PFOB_Z (1 << PFO_Z)
341 #define PFOB_S (1 << PFO_S)
343 static const char *parsed_flag_op_names[] = {
344 "o", "c", "z", "be", "s", "p", "l", "le"
347 static int char_array_i(const char *array[], size_t len, const char *s)
351 for (i = 0; i < len; i++)
358 static void printf_number(char *buf, size_t buf_size,
359 unsigned long number)
361 // output in C-friendly form
362 snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
365 static int check_segment_prefix(const char *s)
367 if (s[0] == 0 || s[1] != 's' || s[2] != ':')
381 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
385 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
387 *reg_lmod = OPLM_QWORD;
391 *reg_lmod = OPLM_DWORD;
394 reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
396 *reg_lmod = OPLM_WORD;
399 reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
401 *reg_lmod = OPLM_BYTE;
404 reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
406 *reg_lmod = OPLM_BYTE;
413 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
415 enum opr_lenmod lmod;
428 while (my_isblank(*s))
430 for (; my_issep(*s); d++, s++)
432 while (my_isblank(*s))
436 // skip '?s:' prefixes
437 if (check_segment_prefix(s))
440 s = next_idt(w, sizeof(w), s);
445 reg = parse_reg(&lmod, w);
447 *regmask |= 1 << reg;
451 if ('0' <= w[0] && w[0] <= '9') {
452 number = parse_number(w);
453 printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
457 // probably some label/identifier - pass
460 snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
464 strcpy(name, cvtbuf);
469 static int is_reg_in_str(const char *s)
473 if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
476 for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
477 if (!strncmp(s, regs_r32[i], 3))
483 static const char *parse_stack_el(const char *name, char *extra_reg,
486 const char *p, *p2, *s;
492 if (g_bp_frame || early_try)
495 if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
497 if (extra_reg != NULL) {
498 strncpy(extra_reg, name, 3);
503 if (IS_START(p, "ebp+")) {
507 if (p2 != NULL && is_reg_in_str(p)) {
508 if (extra_reg != NULL) {
509 strncpy(extra_reg, p, p2 - p);
510 extra_reg[p2 - p] = 0;
515 if (!('0' <= *p && *p <= '9'))
522 if (!IS_START(name, "esp+"))
528 if (is_reg_in_str(s)) {
529 if (extra_reg != NULL) {
530 strncpy(extra_reg, s, p - s);
531 extra_reg[p - s] = 0;
536 aerr("%s IDA stackvar not set?\n", __func__);
538 if (!('0' <= *s && *s <= '9')) {
539 aerr("%s IDA stackvar offset not set?\n", __func__);
542 if (s[0] == '0' && s[1] == 'x')
545 if (len < sizeof(buf) - 1) {
546 strncpy(buf, s, len);
548 val = strtol(buf, &endp, 16);
549 if (val == 0 || *endp != 0) {
550 aerr("%s num parse fail for '%s'\n", __func__, buf);
559 if ('0' <= *p && *p <= '9')
565 static int guess_lmod_from_name(struct parsed_opr *opr)
567 if (IS_START(opr->name, "dword_") || IS_START(opr->name, "off_")) {
568 opr->lmod = OPLM_DWORD;
571 if (IS_START(opr->name, "word_")) {
572 opr->lmod = OPLM_WORD;
575 if (IS_START(opr->name, "byte_")) {
576 opr->lmod = OPLM_BYTE;
579 if (IS_START(opr->name, "qword_")) {
580 opr->lmod = OPLM_QWORD;
586 static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
587 const struct parsed_type *c_type)
589 static const char *dword_types[] = {
590 "uint32_t", "int", "_DWORD", "UINT_PTR", "DWORD",
591 "WPARAM", "LPARAM", "UINT", "__int32",
592 "LONG", "HIMC", "BOOL", "size_t",
595 static const char *word_types[] = {
596 "uint16_t", "int16_t", "_WORD", "WORD",
597 "unsigned __int16", "__int16",
599 static const char *byte_types[] = {
600 "uint8_t", "int8_t", "char",
601 "unsigned __int8", "__int8", "BYTE", "_BYTE",
603 // structures.. deal the same as with _UNKNOWN for now
609 if (c_type->is_ptr) {
614 n = skip_type_mod(c_type->name);
616 for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
617 if (IS(n, dword_types[i])) {
623 for (i = 0; i < ARRAY_SIZE(word_types); i++) {
624 if (IS(n, word_types[i])) {
630 for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
631 if (IS(n, byte_types[i])) {
640 static char *default_cast_to(char *buf, size_t buf_size,
641 struct parsed_opr *opr)
645 if (!opr->is_ptr || strchr(opr->name, '['))
647 if (opr->pp == NULL || opr->pp->type.name == NULL
650 snprintf(buf, buf_size, "%s", "(void *)");
654 snprintf(buf, buf_size, "(%s)", opr->pp->type.name);
658 static enum opr_type lmod_from_directive(const char *d)
662 else if (IS(d, "dw"))
664 else if (IS(d, "db"))
667 aerr("unhandled directive: '%s'\n", d);
671 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
677 *regmask |= 1 << reg;
680 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
683 static int parse_operand(struct parsed_opr *opr,
684 int *regmask, int *regmask_indirect,
685 char words[16][256], int wordc, int w, unsigned int op_flags)
687 const struct parsed_proto *pp = NULL;
688 enum opr_lenmod tmplmod;
689 unsigned long number;
697 aerr("parse_operand w %d, wordc %d\n", w, wordc);
701 for (i = w; i < wordc; i++) {
702 len = strlen(words[i]);
703 if (words[i][len - 1] == ',') {
704 words[i][len - 1] = 0;
710 wordc_in = wordc - w;
712 if ((op_flags & OPF_JMP) && wordc_in > 0
713 && !('0' <= words[w][0] && words[w][0] <= '9'))
715 const char *label = NULL;
717 if (wordc_in == 3 && !strncmp(words[w], "near", 4)
718 && IS(words[w + 1], "ptr"))
719 label = words[w + 2];
720 else if (wordc_in == 2 && IS(words[w], "short"))
721 label = words[w + 1];
722 else if (wordc_in == 1
723 && strchr(words[w], '[') == NULL
724 && parse_reg(&tmplmod, words[w]) < 0)
728 opr->type = OPT_LABEL;
729 ret = check_segment_prefix(label);
732 aerr("fs/gs used\n");
736 strcpy(opr->name, label);
742 if (IS(words[w + 1], "ptr")) {
743 if (IS(words[w], "dword"))
744 opr->lmod = OPLM_DWORD;
745 else if (IS(words[w], "word"))
746 opr->lmod = OPLM_WORD;
747 else if (IS(words[w], "byte"))
748 opr->lmod = OPLM_BYTE;
749 else if (IS(words[w], "qword"))
750 opr->lmod = OPLM_QWORD;
752 aerr("type parsing failed\n");
754 wordc_in = wordc - w;
759 if (IS(words[w], "offset")) {
760 opr->type = OPT_OFFSET;
761 opr->lmod = OPLM_DWORD;
762 strcpy(opr->name, words[w + 1]);
763 pp = proto_parse(g_fhdr, opr->name, 1);
766 if (IS(words[w], "(offset")) {
767 p = strchr(words[w + 1], ')');
769 aerr("parse of bracketed offset failed\n");
771 opr->type = OPT_OFFSET;
772 strcpy(opr->name, words[w + 1]);
778 aerr("parse_operand 1 word expected\n");
780 ret = check_segment_prefix(words[w]);
783 aerr("fs/gs used\n");
785 memmove(words[w], words[w] + 3, strlen(words[w]) - 2);
787 strcpy(opr->name, words[w]);
789 if (words[w][0] == '[') {
790 opr->type = OPT_REGMEM;
791 ret = sscanf(words[w], "[%[^]]]", opr->name);
793 aerr("[] parse failure\n");
795 parse_indmode(opr->name, regmask_indirect, 1);
796 if (opr->lmod == OPLM_UNSPEC && parse_stack_el(opr->name, NULL, 1))
799 struct parsed_equ *eq =
800 equ_find(NULL, parse_stack_el(opr->name, NULL, 1), &i);
802 opr->lmod = eq->lmod;
804 // might be unaligned access
805 g_func_lmods |= 1 << OPLM_BYTE;
809 else if (strchr(words[w], '[')) {
811 p = strchr(words[w], '[');
812 opr->type = OPT_REGMEM;
813 parse_indmode(p, regmask_indirect, 0);
814 strncpy(buf, words[w], p - words[w]);
815 buf[p - words[w]] = 0;
816 pp = proto_parse(g_fhdr, buf, 1);
819 else if (('0' <= words[w][0] && words[w][0] <= '9')
820 || words[w][0] == '-')
822 number = parse_number(words[w]);
823 opr->type = OPT_CONST;
825 printf_number(opr->name, sizeof(opr->name), number);
829 ret = parse_reg(&tmplmod, opr->name);
831 setup_reg_opr(opr, ret, tmplmod, regmask);
835 // most likely var in data segment
836 opr->type = OPT_LABEL;
837 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
841 if (pp->is_fptr || pp->is_func) {
842 opr->lmod = OPLM_DWORD;
846 tmplmod = OPLM_UNSPEC;
847 if (!guess_lmod_from_c_type(&tmplmod, &pp->type))
848 anote("unhandled C type '%s' for '%s'\n",
849 pp->type.name, opr->name);
851 if (opr->lmod == OPLM_UNSPEC) {
853 opr->type_from_var = 1;
855 else if (opr->lmod != tmplmod) {
856 opr->size_mismatch = 1;
857 if (tmplmod < opr->lmod)
860 opr->is_ptr = pp->type.is_ptr;
862 opr->is_array = pp->type.is_array;
866 if (opr->lmod == OPLM_UNSPEC)
867 guess_lmod_from_name(opr);
871 static const struct {
876 { "repe", OPF_REP|OPF_REPZ },
877 { "repz", OPF_REP|OPF_REPZ },
878 { "repne", OPF_REP|OPF_REPNZ },
879 { "repnz", OPF_REP|OPF_REPNZ },
880 { "lock", OPF_LOCK }, // ignored for now..
883 #define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
885 static const struct {
888 unsigned short minopr;
889 unsigned short maxopr;
892 unsigned char pfo_inv;
894 { "nop", OP_NOP, 0, 0, 0 },
895 { "push", OP_PUSH, 1, 1, 0 },
896 { "pop", OP_POP, 1, 1, OPF_DATA },
897 { "leave",OP_LEAVE, 0, 0, OPF_DATA },
898 { "mov" , OP_MOV, 2, 2, OPF_DATA },
899 { "lea", OP_LEA, 2, 2, OPF_DATA },
900 { "movzx",OP_MOVZX, 2, 2, OPF_DATA },
901 { "movsx",OP_MOVSX, 2, 2, OPF_DATA },
902 { "xchg", OP_XCHG, 2, 2, OPF_DATA },
903 { "not", OP_NOT, 1, 1, OPF_DATA },
904 { "xlat", OP_XLAT, 0, 0, OPF_DATA },
905 { "cdq", OP_CDQ, 0, 0, OPF_DATA },
906 { "lodsb",OP_LODS, 0, 0, OPF_DATA },
907 { "lodsw",OP_LODS, 0, 0, OPF_DATA },
908 { "lodsd",OP_LODS, 0, 0, OPF_DATA },
909 { "stosb",OP_STOS, 0, 0, OPF_DATA },
910 { "stosw",OP_STOS, 0, 0, OPF_DATA },
911 { "stosd",OP_STOS, 0, 0, OPF_DATA },
912 { "movsb",OP_MOVS, 0, 0, OPF_DATA },
913 { "movsw",OP_MOVS, 0, 0, OPF_DATA },
914 { "movsd",OP_MOVS, 0, 0, OPF_DATA },
915 { "cmpsb",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
916 { "cmpsw",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
917 { "cmpsd",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
918 { "scasb",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
919 { "scasw",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
920 { "scasd",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
921 { "std", OP_STD, 0, 0, OPF_DATA }, // special flag
922 { "cld", OP_CLD, 0, 0, OPF_DATA },
923 { "add", OP_ADD, 2, 2, OPF_DATA|OPF_FLAGS },
924 { "sub", OP_SUB, 2, 2, OPF_DATA|OPF_FLAGS },
925 { "and", OP_AND, 2, 2, OPF_DATA|OPF_FLAGS },
926 { "or", OP_OR, 2, 2, OPF_DATA|OPF_FLAGS },
927 { "xor", OP_XOR, 2, 2, OPF_DATA|OPF_FLAGS },
928 { "shl", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
929 { "shr", OP_SHR, 2, 2, OPF_DATA|OPF_FLAGS },
930 { "sal", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
931 { "sar", OP_SAR, 2, 2, OPF_DATA|OPF_FLAGS },
932 { "shld", OP_SHLD, 3, 3, OPF_DATA|OPF_FLAGS },
933 { "shrd", OP_SHRD, 3, 3, OPF_DATA|OPF_FLAGS },
934 { "rol", OP_ROL, 2, 2, OPF_DATA|OPF_FLAGS },
935 { "ror", OP_ROR, 2, 2, OPF_DATA|OPF_FLAGS },
936 { "rcl", OP_RCL, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
937 { "rcr", OP_RCR, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
938 { "adc", OP_ADC, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
939 { "sbb", OP_SBB, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
940 { "bsf", OP_BSF, 2, 2, OPF_DATA|OPF_FLAGS },
941 { "inc", OP_INC, 1, 1, OPF_DATA|OPF_FLAGS },
942 { "dec", OP_DEC, 1, 1, OPF_DATA|OPF_FLAGS },
943 { "neg", OP_NEG, 1, 1, OPF_DATA|OPF_FLAGS },
944 { "mul", OP_MUL, 1, 1, OPF_DATA|OPF_FLAGS },
945 { "imul", OP_IMUL, 1, 3, OPF_DATA|OPF_FLAGS },
946 { "div", OP_DIV, 1, 1, OPF_DATA|OPF_FLAGS },
947 { "idiv", OP_IDIV, 1, 1, OPF_DATA|OPF_FLAGS },
948 { "test", OP_TEST, 2, 2, OPF_FLAGS },
949 { "cmp", OP_CMP, 2, 2, OPF_FLAGS },
950 { "retn", OP_RET, 0, 1, OPF_TAIL },
951 { "call", OP_CALL, 1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
952 { "jmp", OP_JMP, 1, 1, OPF_JMP },
953 { "jecxz",OP_JECXZ, 1, 1, OPF_JMP|OPF_CJMP },
954 { "loop", OP_LOOP, 1, 1, OPF_JMP|OPF_CJMP|OPF_DATA },
955 { "jo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 0 }, // 70 OF=1
956 { "jno", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 1 }, // 71 OF=0
957 { "jc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72 CF=1
958 { "jb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72
959 { "jnc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73 CF=0
960 { "jnb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
961 { "jae", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
962 { "jz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74 ZF=1
963 { "je", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74
964 { "jnz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75 ZF=0
965 { "jne", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75
966 { "jbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76 CF=1||ZF=1
967 { "jna", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76
968 { "ja", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77 CF=0&&ZF=0
969 { "jnbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77
970 { "js", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 0 }, // 78 SF=1
971 { "jns", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 1 }, // 79 SF=0
972 { "jp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a PF=1
973 { "jpe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a
974 { "jnp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b PF=0
975 { "jpo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b
976 { "jl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c SF!=OF
977 { "jnge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c
978 { "jge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d SF=OF
979 { "jnl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d
980 { "jle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e ZF=1||SF!=OF
981 { "jng", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e
982 { "jg", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f ZF=0&&SF=OF
983 { "jnle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f
984 { "seto", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 0 },
985 { "setno", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 1 },
986 { "setc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
987 { "setb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
988 { "setnc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
989 { "setae", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
990 { "setnb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
991 { "setz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
992 { "sete", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
993 { "setnz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
994 { "setne", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
995 { "setbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
996 { "setna", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
997 { "seta", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
998 { "setnbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
999 { "sets", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 0 },
1000 { "setns", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 1 },
1001 { "setp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1002 { "setpe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1003 { "setnp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1004 { "setpo", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1005 { "setl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1006 { "setnge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1007 { "setge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1008 { "setnl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1009 { "setle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1010 { "setng", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1011 { "setg", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1012 { "setnle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1014 { "fld", OP_FLD, 1, 1, OPF_FPUSH },
1015 { "fild", OP_FILD, 1, 1, OPF_FPUSH },
1016 { "fld1", OP_FLDc, 0, 0, OPF_FPUSH },
1017 { "fldz", OP_FLDc, 0, 0, OPF_FPUSH },
1018 { "fstp", OP_FST, 1, 1, OPF_FPOP },
1019 { "fst", OP_FST, 1, 1, 0 },
1020 { "fadd", OP_FADD, 0, 2, 0 },
1021 { "faddp", OP_FADD, 0, 2, OPF_FPOP },
1022 { "fdiv", OP_FDIV, 0, 2, 0 },
1023 { "fdivp", OP_FDIV, 0, 2, OPF_FPOP },
1024 { "fmul", OP_FMUL, 0, 2, 0 },
1025 { "fmulp", OP_FMUL, 0, 2, OPF_FPOP },
1026 { "fsub", OP_FSUB, 0, 2, 0 },
1027 { "fsubp", OP_FSUB, 0, 2, OPF_FPOP },
1028 { "fdivr", OP_FDIVR, 0, 2, 0 },
1029 { "fdivrp", OP_FDIVR, 0, 2, OPF_FPOP },
1030 { "fsubr", OP_FSUBR, 0, 2, 0 },
1031 { "fsubrp", OP_FSUBR, 0, 2, OPF_FPOP },
1032 { "fiadd", OP_FIADD, 1, 1, 0 },
1033 { "fidiv", OP_FIDIV, 1, 1, 0 },
1034 { "fimul", OP_FIMUL, 1, 1, 0 },
1035 { "fisub", OP_FISUB, 1, 1, 0 },
1036 { "fidivr", OP_FIDIVR, 1, 1, 0 },
1037 { "fisubr", OP_FISUBR, 1, 1, 0 },
1039 { "emms", OP_EMMS, 0, 0, OPF_DATA },
1040 { "movq", OP_MOV, 2, 2, OPF_DATA },
1041 // pseudo-ops for lib calls
1042 { "_ftol", OPP_FTOL },
1047 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
1049 enum opr_lenmod lmod = OPLM_UNSPEC;
1050 int prefix_flags = 0;
1058 for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
1059 if (IS(words[w], pref_table[i].name)) {
1060 prefix_flags = pref_table[i].flags;
1067 aerr("lone prefix: '%s'\n", words[0]);
1072 for (i = 0; i < ARRAY_SIZE(op_table); i++) {
1073 if (IS(words[w], op_table[i].name))
1077 if (i == ARRAY_SIZE(op_table)) {
1079 aerr("unhandled op: '%s'\n", words[0]);
1084 op->op = op_table[i].op;
1085 op->flags = op_table[i].flags | prefix_flags;
1086 op->pfo = op_table[i].pfo;
1087 op->pfo_inv = op_table[i].pfo_inv;
1088 op->regmask_src = op->regmask_dst = 0;
1091 if (op->op == OP_UD2)
1094 for (opr = 0; opr < op_table[i].maxopr; opr++) {
1095 if (opr >= op_table[i].minopr && w >= wordc)
1098 regmask = regmask_ind = 0;
1099 w = parse_operand(&op->operand[opr], ®mask, ®mask_ind,
1100 words, wordc, w, op->flags);
1102 if (opr == 0 && (op->flags & OPF_DATA))
1103 op->regmask_dst = regmask;
1105 op->regmask_src |= regmask;
1106 op->regmask_src |= regmask_ind;
1108 if (op->operand[opr].lmod != OPLM_UNSPEC)
1109 g_func_lmods |= 1 << op->operand[opr].lmod;
1113 aerr("parse_op %s incomplete: %d/%d\n",
1114 words[0], w, wordc);
1117 op->operand_cnt = opr;
1118 if (!strncmp(op_table[i].name, "set", 3))
1119 op->operand[0].lmod = OPLM_BYTE;
1122 // first operand is not dst
1125 op->regmask_src |= op->regmask_dst;
1126 op->regmask_dst = 0;
1129 // first operand is src too
1141 op->regmask_src |= op->regmask_dst;
1146 op->regmask_src |= op->regmask_dst;
1147 op->regmask_dst |= op->regmask_src;
1153 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1154 && op->operand[0].lmod == op->operand[1].lmod
1155 && op->operand[0].reg == op->operand[1].reg
1156 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1158 op->regmask_src = 0;
1161 op->regmask_src |= op->regmask_dst;
1164 // ops with implicit argumets
1166 op->operand_cnt = 2;
1167 setup_reg_opr(&op->operand[0], xAX, OPLM_BYTE, &op->regmask_src);
1168 op->regmask_dst = op->regmask_src;
1169 setup_reg_opr(&op->operand[1], xBX, OPLM_DWORD, &op->regmask_src);
1173 op->operand_cnt = 2;
1174 setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
1175 setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
1181 if (words[op_w][4] == 'b')
1183 else if (words[op_w][4] == 'w')
1185 else if (words[op_w][4] == 'd')
1188 op->regmask_src = 0;
1189 setup_reg_opr(&op->operand[j++], op->op == OP_LODS ? xSI : xDI,
1190 OPLM_DWORD, &op->regmask_src);
1191 op->regmask_dst = op->regmask_src;
1192 setup_reg_opr(&op->operand[j++], xAX, lmod,
1193 op->op == OP_LODS ? &op->regmask_dst : &op->regmask_src);
1194 if (op->flags & OPF_REP) {
1195 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1196 op->regmask_dst |= 1 << xCX;
1198 op->operand_cnt = j;
1203 if (words[op_w][4] == 'b')
1205 else if (words[op_w][4] == 'w')
1207 else if (words[op_w][4] == 'd')
1210 op->regmask_src = 0;
1211 // note: lmod is not correct, don't have where to place it
1212 setup_reg_opr(&op->operand[j++], xDI, lmod, &op->regmask_src);
1213 setup_reg_opr(&op->operand[j++], xSI, OPLM_DWORD, &op->regmask_src);
1214 if (op->flags & OPF_REP)
1215 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1216 op->operand_cnt = j;
1217 op->regmask_dst = op->regmask_src;
1221 op->regmask_dst = 1 << xCX;
1224 op->operand_cnt = 2;
1225 op->regmask_src = 1 << xCX;
1226 op->operand[1].type = OPT_REG;
1227 op->operand[1].reg = xCX;
1228 op->operand[1].lmod = OPLM_DWORD;
1232 if (op->operand_cnt == 2) {
1233 if (op->operand[0].type != OPT_REG)
1234 aerr("reg expected\n");
1235 op->regmask_src |= 1 << op->operand[0].reg;
1237 if (op->operand_cnt != 1)
1242 op->regmask_src |= op->regmask_dst;
1243 op->regmask_dst = (1 << xDX) | (1 << xAX);
1244 if (op->operand[0].lmod == OPLM_UNSPEC)
1245 op->operand[0].lmod = OPLM_DWORD;
1250 // we could set up operands for edx:eax, but there is no real need to
1251 // (see is_opr_modified())
1252 op->regmask_src |= op->regmask_dst;
1253 op->regmask_dst = (1 << xDX) | (1 << xAX);
1254 if (op->operand[0].lmod == OPLM_UNSPEC)
1255 op->operand[0].lmod = OPLM_DWORD;
1263 op->regmask_src |= op->regmask_dst;
1264 if (op->operand[1].lmod == OPLM_UNSPEC)
1265 op->operand[1].lmod = OPLM_BYTE;
1270 op->regmask_src |= op->regmask_dst;
1271 if (op->operand[2].lmod == OPLM_UNSPEC)
1272 op->operand[2].lmod = OPLM_BYTE;
1276 op->regmask_src |= op->regmask_dst;
1277 op->regmask_dst = 0;
1278 if (op->operand[0].lmod == OPLM_UNSPEC
1279 && (op->operand[0].type == OPT_CONST
1280 || op->operand[0].type == OPT_OFFSET
1281 || op->operand[0].type == OPT_LABEL))
1282 op->operand[0].lmod = OPLM_DWORD;
1288 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1289 && op->operand[0].lmod == op->operand[1].lmod
1290 && op->operand[0].reg == op->operand[1].reg
1291 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1293 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1294 op->regmask_src = op->regmask_dst = 0;
1299 if (op->operand[0].type == OPT_REG
1300 && op->operand[1].type == OPT_REGMEM)
1303 snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1304 if (IS(buf, op->operand[1].name))
1305 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1310 // trashed regs must be explicitly detected later
1311 op->regmask_dst = 0;
1315 op->regmask_dst = (1 << xBP) | (1 << xSP);
1316 op->regmask_src = 1 << xBP;
1321 op->regmask_dst |= mxST0;
1325 op->regmask_dst |= mxST0;
1326 if (IS(words[op_w] + 3, "1"))
1327 op->operand[0].val = X87_CONST_1;
1328 else if (IS(words[op_w] + 3, "z"))
1329 op->operand[0].val = X87_CONST_Z;
1335 op->regmask_src |= mxST0;
1344 op->regmask_src |= mxST0;
1345 if (op->operand_cnt == 2)
1346 op->regmask_src |= op->regmask_dst;
1347 else if (op->operand_cnt == 1) {
1348 memcpy(&op->operand[1], &op->operand[0], sizeof(op->operand[1]));
1349 op->operand[0].type = OPT_REG;
1350 op->operand[0].lmod = OPLM_QWORD;
1351 op->operand[0].reg = xST0;
1352 op->regmask_dst |= mxST0;
1355 // IDA doesn't use this
1356 aerr("no operands?\n");
1365 op->regmask_src |= mxST0;
1366 op->regmask_dst |= mxST0;
1373 if (op->operand[0].type == OPT_REG
1374 && op->operand[1].type == OPT_CONST)
1376 struct parsed_opr *op1 = &op->operand[1];
1377 if ((op->op == OP_AND && op1->val == 0)
1380 || (op->operand[0].lmod == OPLM_WORD && op1->val == 0xffff)
1381 || (op->operand[0].lmod == OPLM_BYTE && op1->val == 0xff))))
1383 op->regmask_src = 0;
1388 static const char *op_name(struct parsed_op *po)
1390 static char buf[16];
1394 if (po->op == OP_JCC || po->op == OP_SCC) {
1396 *p++ = (po->op == OP_JCC) ? 'j' : 's';
1399 strcpy(p, parsed_flag_op_names[po->pfo]);
1403 for (i = 0; i < ARRAY_SIZE(op_table); i++)
1404 if (op_table[i].op == po->op)
1405 return op_table[i].name;
1411 static const char *dump_op(struct parsed_op *po)
1413 static char out[128];
1420 snprintf(out, sizeof(out), "%s", op_name(po));
1421 for (i = 0; i < po->operand_cnt; i++) {
1425 snprintf(p, sizeof(out) - (p - out),
1426 po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1427 po->operand[i].name);
1433 static const char *lmod_type_u(struct parsed_op *po,
1434 enum opr_lenmod lmod)
1446 ferr(po, "invalid lmod: %d\n", lmod);
1447 return "(_invalid_)";
1451 static const char *lmod_cast_u(struct parsed_op *po,
1452 enum opr_lenmod lmod)
1464 ferr(po, "invalid lmod: %d\n", lmod);
1465 return "(_invalid_)";
1469 static const char *lmod_cast_u_ptr(struct parsed_op *po,
1470 enum opr_lenmod lmod)
1482 ferr(po, "invalid lmod: %d\n", lmod);
1483 return "(_invalid_)";
1487 static const char *lmod_cast_s(struct parsed_op *po,
1488 enum opr_lenmod lmod)
1500 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1501 return "(_invalid_)";
1505 static const char *lmod_cast(struct parsed_op *po,
1506 enum opr_lenmod lmod, int is_signed)
1509 lmod_cast_s(po, lmod) :
1510 lmod_cast_u(po, lmod);
1513 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1525 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1530 static const char *opr_name(struct parsed_op *po, int opr_num)
1532 if (opr_num >= po->operand_cnt)
1533 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1534 return po->operand[opr_num].name;
1537 static unsigned int opr_const(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 if (po->operand[opr_num].type != OPT_CONST)
1542 ferr(po, "opr %d: const expected\n", opr_num);
1543 return po->operand[opr_num].val;
1546 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1548 if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
1549 ferr(po, "invalid reg: %d\n", popr->reg);
1550 return regs_r32[popr->reg];
1553 static int check_simple_cast(const char *cast, int *bits, int *is_signed)
1555 if (IS_START(cast, "(s8)") || IS_START(cast, "(u8)"))
1557 else if (IS_START(cast, "(s16)") || IS_START(cast, "(u16)"))
1559 else if (IS_START(cast, "(s32)") || IS_START(cast, "(u32)"))
1561 else if (IS_START(cast, "(s64)") || IS_START(cast, "(u64)"))
1566 *is_signed = cast[1] == 's' ? 1 : 0;
1570 static int check_deref_cast(const char *cast, int *bits)
1572 if (IS_START(cast, "*(u8 *)"))
1574 else if (IS_START(cast, "*(u16 *)"))
1576 else if (IS_START(cast, "*(u32 *)"))
1578 else if (IS_START(cast, "*(u64 *)"))
1586 // cast1 is the "final" cast
1587 static const char *simplify_cast(const char *cast1, const char *cast2)
1589 static char buf[256];
1597 if (IS(cast1, cast2))
1600 if (check_simple_cast(cast1, &bits1, &s1) == 0
1601 && check_simple_cast(cast2, &bits2, &s2) == 0)
1606 if (check_simple_cast(cast1, &bits1, &s1) == 0
1607 && check_deref_cast(cast2, &bits2) == 0)
1609 if (bits1 == bits2) {
1610 snprintf(buf, sizeof(buf), "*(%c%d *)", s1 ? 's' : 'u', bits1);
1615 if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1618 snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1622 static const char *simplify_cast_num(const char *cast, unsigned int val)
1624 if (IS(cast, "(u8)") && val < 0x100)
1626 if (IS(cast, "(s8)") && val < 0x80)
1628 if (IS(cast, "(u16)") && val < 0x10000)
1630 if (IS(cast, "(s16)") && val < 0x8000)
1632 if (IS(cast, "(s32)") && val < 0x80000000)
1638 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1647 namelen = strlen(name);
1649 p = strchr(name, '+');
1653 ferr(po, "equ parse failed for '%s'\n", name);
1655 if (IS_START(p, "0x"))
1657 *extra_offs = strtol(p, &endp, 16);
1659 ferr(po, "equ parse failed for '%s'\n", name);
1662 for (i = 0; i < g_eqcnt; i++)
1663 if (strncmp(g_eqs[i].name, name, namelen) == 0
1664 && g_eqs[i].name[namelen] == 0)
1668 ferr(po, "unresolved equ name: '%s'\n", name);
1675 static int is_stack_access(struct parsed_op *po,
1676 const struct parsed_opr *popr)
1678 return (parse_stack_el(popr->name, NULL, 0)
1679 || (g_bp_frame && !(po->flags & OPF_EBP_S)
1680 && IS_START(popr->name, "ebp")));
1683 static void parse_stack_access(struct parsed_op *po,
1684 const char *name, char *ofs_reg, int *offset_out,
1685 int *stack_ra_out, const char **bp_arg_out, int is_lea)
1687 const char *bp_arg = "";
1688 const char *p = NULL;
1689 struct parsed_equ *eq;
1696 if (IS_START(name, "ebp-")
1697 || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1700 if (IS_START(p, "0x"))
1702 offset = strtoul(p, &endp, 16);
1706 ferr(po, "ebp- parse of '%s' failed\n", name);
1709 bp_arg = parse_stack_el(name, ofs_reg, 0);
1710 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1711 eq = equ_find(po, bp_arg, &offset);
1713 ferr(po, "detected but missing eq\n");
1714 offset += eq->offset;
1717 if (!strncmp(name, "ebp", 3))
1720 // yes it sometimes LEAs ra for compares..
1721 if (!is_lea && ofs_reg[0] == 0
1722 && stack_ra <= offset && offset < stack_ra + 4)
1724 ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1727 *offset_out = offset;
1728 *stack_ra_out = stack_ra;
1730 *bp_arg_out = bp_arg;
1733 static int stack_frame_access(struct parsed_op *po,
1734 struct parsed_opr *popr, char *buf, size_t buf_size,
1735 const char *name, const char *cast, int is_src, int is_lea)
1737 enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1738 const char *prefix = "";
1739 const char *bp_arg = NULL;
1740 char ofs_reg[16] = { 0, };
1741 int i, arg_i, arg_s;
1749 if (po->flags & OPF_EBP_S)
1750 ferr(po, "stack_frame_access while ebp is scratch\n");
1752 parse_stack_access(po, name, ofs_reg, &offset,
1753 &stack_ra, &bp_arg, is_lea);
1755 if (offset > stack_ra)
1757 arg_i = (offset - stack_ra - 4) / 4;
1758 if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1760 if (g_func_pp->is_vararg
1761 && arg_i == g_func_pp->argc_stack && is_lea)
1763 // should be va_list
1766 snprintf(buf, buf_size, "%sap", cast);
1769 ferr(po, "offset %d (%s,%d) doesn't map to any arg\n",
1770 offset, bp_arg, arg_i);
1772 if (ofs_reg[0] != 0)
1773 ferr(po, "offset reg on arg access?\n");
1775 for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1776 if (g_func_pp->arg[i].reg != NULL)
1782 if (i == g_func_pp->argc)
1783 ferr(po, "arg %d not in prototype?\n", arg_i);
1785 popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
1792 ferr(po, "lea/byte to arg?\n");
1793 if (is_src && (offset & 3) == 0)
1794 snprintf(buf, buf_size, "%sa%d",
1795 simplify_cast(cast, "(u8)"), i + 1);
1797 snprintf(buf, buf_size, "%sBYTE%d(a%d)",
1798 cast, offset & 3, i + 1);
1803 ferr(po, "lea/word to arg?\n");
1808 ferr(po, "problematic arg store\n");
1809 snprintf(buf, buf_size, "%s((char *)&a%d + 1)",
1810 simplify_cast(cast, "*(u16 *)"), i + 1);
1813 ferr(po, "unaligned arg word load\n");
1815 else if (is_src && (offset & 2) == 0)
1816 snprintf(buf, buf_size, "%sa%d",
1817 simplify_cast(cast, "(u16)"), i + 1);
1819 snprintf(buf, buf_size, "%s%sWORD(a%d)",
1820 cast, (offset & 2) ? "HI" : "LO", i + 1);
1832 snprintf(buf, buf_size, "(u32)&a%d + %d",
1835 ferr(po, "unaligned arg store\n");
1837 // mov edx, [ebp+arg_4+2]; movsx ecx, dx
1838 snprintf(buf, buf_size, "%s(a%d >> %d)",
1839 prefix, i + 1, (offset & 3) * 8);
1843 snprintf(buf, buf_size, "%s%sa%d",
1844 prefix, is_lea ? "&" : "", i + 1);
1849 ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
1853 snprintf(g_comment, sizeof(g_comment), "%s unaligned", bp_arg);
1856 guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
1857 if (tmp_lmod != OPLM_DWORD
1858 && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
1859 < lmod_bytes(po, popr->lmod) + (offset & 3))))
1861 ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
1862 i + 1, offset, g_func_pp->arg[i].type.name);
1864 // can't check this because msvc likes to reuse
1865 // arg space for scratch..
1866 //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
1867 // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
1871 if (g_stack_fsz == 0)
1872 ferr(po, "stack var access without stackframe\n");
1873 g_stack_frame_used = 1;
1875 sf_ofs = g_stack_fsz + offset;
1876 lim = (ofs_reg[0] != 0) ? -4 : 0;
1877 if (offset > 0 || sf_ofs < lim)
1878 ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
1888 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1889 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1893 if ((sf_ofs & 1) || ofs_reg[0] != 0) {
1894 // known unaligned or possibly unaligned
1895 strcat(g_comment, " unaligned");
1897 prefix = "*(u16 *)&";
1898 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1899 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1902 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
1906 if ((sf_ofs & 3) || ofs_reg[0] != 0) {
1907 // known unaligned or possibly unaligned
1908 strcat(g_comment, " unaligned");
1910 prefix = "*(u32 *)&";
1911 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1912 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1915 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
1919 ferr_assert(po, !(sf_ofs & 7));
1920 ferr_assert(po, ofs_reg[0] == 0);
1921 // float callers set is_lea
1922 ferr_assert(po, is_lea);
1923 snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
1927 ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
1934 static void check_func_pp(struct parsed_op *po,
1935 const struct parsed_proto *pp, const char *pfx)
1937 enum opr_lenmod tmp_lmod;
1941 if (pp->argc_reg != 0) {
1942 if (/*!g_allow_regfunc &&*/ !pp->is_fastcall) {
1943 pp_print(buf, sizeof(buf), pp);
1944 ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
1946 if (pp->argc_stack > 0 && pp->argc_reg != 2)
1947 ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
1948 pfx, pp->argc_reg, pp->argc_stack);
1951 // fptrs must use 32bit args, callsite might have no information and
1952 // lack a cast to smaller types, which results in incorrectly masked
1953 // args passed (callee may assume masked args, it does on ARM)
1954 if (!pp->is_osinc) {
1955 for (i = 0; i < pp->argc; i++) {
1956 ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
1957 if (ret && tmp_lmod != OPLM_DWORD)
1958 ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
1959 i + 1, pp->arg[i].type.name);
1964 static const char *check_label_read_ref(struct parsed_op *po,
1967 const struct parsed_proto *pp;
1969 pp = proto_parse(g_fhdr, name, 0);
1971 ferr(po, "proto_parse failed for ref '%s'\n", name);
1974 check_func_pp(po, pp, "ref");
1979 static char *out_src_opr(char *buf, size_t buf_size,
1980 struct parsed_op *po, struct parsed_opr *popr, const char *cast,
1983 char tmp1[256], tmp2[256];
1992 switch (popr->type) {
1995 ferr(po, "lea from reg?\n");
1997 switch (popr->lmod) {
1999 snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2002 snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2005 snprintf(buf, buf_size, "%s%s",
2006 simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2009 if (popr->name[1] == 'h') // XXX..
2010 snprintf(buf, buf_size, "%s(%s >> 8)",
2011 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2013 snprintf(buf, buf_size, "%s%s",
2014 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2017 ferr(po, "invalid src lmod: %d\n", popr->lmod);
2022 if (is_stack_access(po, popr)) {
2023 stack_frame_access(po, popr, buf, buf_size,
2024 popr->name, cast, 1, is_lea);
2028 strcpy(expr, popr->name);
2029 if (strchr(expr, '[')) {
2030 // special case: '[' can only be left for label[reg] form
2031 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2033 ferr(po, "parse failure for '%s'\n", expr);
2034 if (tmp1[0] == '(') {
2035 // (off_4FFF50+3)[eax]
2036 p = strchr(tmp1 + 1, ')');
2037 if (p == NULL || p[1] != 0)
2038 ferr(po, "parse failure (2) for '%s'\n", expr);
2040 memmove(tmp1, tmp1 + 1, strlen(tmp1));
2042 snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2045 // XXX: do we need more parsing?
2047 snprintf(buf, buf_size, "%s", expr);
2051 snprintf(buf, buf_size, "%s(%s)",
2052 simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2056 name = check_label_read_ref(po, popr->name);
2057 if (cast[0] == 0 && popr->is_ptr)
2061 snprintf(buf, buf_size, "(u32)&%s", name);
2062 else if (popr->size_lt)
2063 snprintf(buf, buf_size, "%s%s%s%s", cast,
2064 lmod_cast_u_ptr(po, popr->lmod),
2065 popr->is_array ? "" : "&", name);
2067 snprintf(buf, buf_size, "%s%s%s", cast, name,
2068 popr->is_array ? "[0]" : "");
2072 name = check_label_read_ref(po, popr->name);
2076 ferr(po, "lea an offset?\n");
2077 snprintf(buf, buf_size, "%s&%s", cast, name);
2082 ferr(po, "lea from const?\n");
2084 printf_number(tmp1, sizeof(tmp1), popr->val);
2085 if (popr->val == 0 && strchr(cast, '*'))
2086 snprintf(buf, buf_size, "NULL");
2088 snprintf(buf, buf_size, "%s%s",
2089 simplify_cast_num(cast, popr->val), tmp1);
2093 ferr(po, "invalid src type: %d\n", popr->type);
2099 // note: may set is_ptr (we find that out late for ebp frame..)
2100 static char *out_dst_opr(char *buf, size_t buf_size,
2101 struct parsed_op *po, struct parsed_opr *popr)
2103 switch (popr->type) {
2105 switch (popr->lmod) {
2107 snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2110 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2114 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2118 if (popr->name[1] == 'h') // XXX..
2119 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2121 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2124 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2129 if (is_stack_access(po, popr)) {
2130 stack_frame_access(po, popr, buf, buf_size,
2131 popr->name, "", 0, 0);
2135 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2138 if (popr->size_mismatch)
2139 snprintf(buf, buf_size, "%s%s%s",
2140 lmod_cast_u_ptr(po, popr->lmod),
2141 popr->is_array ? "" : "&", popr->name);
2143 snprintf(buf, buf_size, "%s%s", popr->name,
2144 popr->is_array ? "[0]" : "");
2148 ferr(po, "invalid dst type: %d\n", popr->type);
2154 static char *out_src_opr_u32(char *buf, size_t buf_size,
2155 struct parsed_op *po, struct parsed_opr *popr)
2157 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2160 static char *out_src_opr_float(char *buf, size_t buf_size,
2161 struct parsed_op *po, struct parsed_opr *popr)
2163 const char *cast = NULL;
2166 switch (popr->type) {
2168 if (popr->reg < xST0 || popr->reg > xST7)
2169 ferr(po, "bad reg: %d\n", popr->reg);
2171 snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2177 switch (popr->lmod) {
2185 ferr(po, "unhandled lmod: %d\n", popr->lmod);
2188 out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2189 snprintf(buf, buf_size, "*((%s *)%s)", cast, tmp);
2193 ferr(po, "invalid float type: %d\n", popr->type);
2199 static char *out_dst_opr_float(char *buf, size_t buf_size,
2200 struct parsed_op *po, struct parsed_opr *popr)
2203 return out_src_opr_float(buf, buf_size, po, popr);
2206 static void out_test_for_cc(char *buf, size_t buf_size,
2207 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2208 enum opr_lenmod lmod, const char *expr)
2210 const char *cast, *scast;
2212 cast = lmod_cast_u(po, lmod);
2213 scast = lmod_cast_s(po, lmod);
2217 case PFO_BE: // CF=1||ZF=1; CF=0
2218 snprintf(buf, buf_size, "(%s%s %s 0)",
2219 cast, expr, is_inv ? "!=" : "==");
2223 case PFO_L: // SF!=OF; OF=0
2224 snprintf(buf, buf_size, "(%s%s %s 0)",
2225 scast, expr, is_inv ? ">=" : "<");
2228 case PFO_LE: // ZF=1||SF!=OF; OF=0
2229 snprintf(buf, buf_size, "(%s%s %s 0)",
2230 scast, expr, is_inv ? ">" : "<=");
2234 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2238 static void out_cmp_for_cc(char *buf, size_t buf_size,
2239 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2241 const char *cast, *scast, *cast_use;
2242 char buf1[256], buf2[256];
2243 enum opr_lenmod lmod;
2245 if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2246 ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2247 po->operand[0].lmod, po->operand[1].lmod);
2248 lmod = po->operand[0].lmod;
2250 cast = lmod_cast_u(po, lmod);
2251 scast = lmod_cast_s(po, lmod);
2267 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2270 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2271 if (po->op == OP_DEC)
2272 snprintf(buf2, sizeof(buf2), "1");
2274 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_use, 0);
2278 // note: must be unsigned compare
2279 snprintf(buf, buf_size, "(%s %s %s)",
2280 buf1, is_inv ? ">=" : "<", buf2);
2284 snprintf(buf, buf_size, "(%s %s %s)",
2285 buf1, is_inv ? "!=" : "==", buf2);
2289 // note: must be unsigned compare
2290 snprintf(buf, buf_size, "(%s %s %s)",
2291 buf1, is_inv ? ">" : "<=", buf2);
2294 if (is_inv && lmod == OPLM_BYTE
2295 && po->operand[1].type == OPT_CONST
2296 && po->operand[1].val == 0xff)
2298 snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2299 snprintf(buf, buf_size, "(0)");
2303 // note: must be signed compare
2305 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2306 scast, buf1, buf2, is_inv ? ">=" : "<");
2310 snprintf(buf, buf_size, "(%s %s %s)",
2311 buf1, is_inv ? ">=" : "<", buf2);
2315 snprintf(buf, buf_size, "(%s %s %s)",
2316 buf1, is_inv ? ">" : "<=", buf2);
2324 static void out_cmp_test(char *buf, size_t buf_size,
2325 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2327 char buf1[256], buf2[256], buf3[256];
2329 if (po->op == OP_TEST) {
2330 if (IS(opr_name(po, 0), opr_name(po, 1))) {
2331 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2334 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2335 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2336 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2338 out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2339 po->operand[0].lmod, buf3);
2341 else if (po->op == OP_CMP) {
2342 out_cmp_for_cc(buf, buf_size, po, pfo, is_inv);
2345 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2348 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2349 struct parsed_opr *popr2)
2351 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2352 ferr(po, "missing lmod for both operands\n");
2354 if (popr1->lmod == OPLM_UNSPEC)
2355 popr1->lmod = popr2->lmod;
2356 else if (popr2->lmod == OPLM_UNSPEC)
2357 popr2->lmod = popr1->lmod;
2358 else if (popr1->lmod != popr2->lmod) {
2359 if (popr1->type_from_var) {
2360 popr1->size_mismatch = 1;
2361 if (popr1->lmod < popr2->lmod)
2363 popr1->lmod = popr2->lmod;
2365 else if (popr2->type_from_var) {
2366 popr2->size_mismatch = 1;
2367 if (popr2->lmod < popr1->lmod)
2369 popr2->lmod = popr1->lmod;
2372 ferr(po, "conflicting lmods: %d vs %d\n",
2373 popr1->lmod, popr2->lmod);
2377 static const char *op_to_c(struct parsed_op *po)
2401 ferr(po, "op_to_c was supplied with %d\n", po->op);
2405 // last op in stream - unconditional branch or ret
2406 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2407 || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2408 && ops[_i].op != OP_CALL))
2410 #define check_i(po, i) \
2412 ferr(po, "bad " #i ": %d\n", i)
2414 // note: this skips over calls and rm'd stuff assuming they're handled
2415 // so it's intended to use at one of final passes
2416 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2417 int depth, int flags_set)
2419 struct parsed_op *po;
2424 for (; i < opcnt; i++) {
2426 if (po->cc_scratch == magic)
2427 return ret; // already checked
2428 po->cc_scratch = magic;
2430 if (po->flags & OPF_TAIL) {
2431 if (po->op == OP_CALL) {
2432 if (po->pp != NULL && po->pp->is_noreturn)
2433 // assume no stack cleanup for noreturn
2436 return -1; // deadend
2439 if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
2442 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2443 if (po->btj != NULL) {
2445 for (j = 0; j < po->btj->count; j++) {
2446 check_i(po, po->btj->d[j].bt_i);
2447 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2450 return ret; // dead end
2455 check_i(po, po->bt_i);
2456 if (po->flags & OPF_CJMP) {
2457 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2460 return ret; // dead end
2469 if ((po->op == OP_POP || po->op == OP_PUSH)
2470 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2475 if (po->op == OP_PUSH) {
2478 else if (po->op == OP_POP) {
2479 if (relevant && depth == 0) {
2480 po->flags |= flags_set;
2490 // scan for 'reg' pop backwards starting from i
2491 // intended to use for register restore search, so other reg
2492 // references are considered an error
2493 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2495 struct parsed_op *po;
2496 struct label_ref *lr;
2499 ops[i].cc_scratch = magic;
2503 if (g_labels[i] != NULL) {
2504 lr = &g_label_refs[i];
2505 for (; lr != NULL; lr = lr->next) {
2506 check_i(&ops[i], lr->i);
2507 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2511 if (i > 0 && LAST_OP(i - 1))
2519 if (ops[i].cc_scratch == magic)
2521 ops[i].cc_scratch = magic;
2524 if (po->op == OP_POP && po->operand[0].reg == reg) {
2525 if (po->flags & (OPF_RMD|OPF_DONE))
2528 po->flags |= set_flags;
2532 // this also covers the case where we reach corresponding push
2533 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2537 // nothing interesting on this path
2541 static void find_reachable_exits(int i, int opcnt, int magic,
2542 int *exits, int *exit_count)
2544 struct parsed_op *po;
2547 for (; i < opcnt; i++)
2550 if (po->cc_scratch == magic)
2552 po->cc_scratch = magic;
2554 if (po->flags & OPF_TAIL) {
2555 ferr_assert(po, *exit_count < MAX_EXITS);
2556 exits[*exit_count] = i;
2561 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2562 if (po->flags & OPF_RMD)
2565 if (po->btj != NULL) {
2566 for (j = 0; j < po->btj->count; j++) {
2567 check_i(po, po->btj->d[j].bt_i);
2568 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2574 check_i(po, po->bt_i);
2575 if (po->flags & OPF_CJMP)
2576 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2584 // scan for 'reg' pop backwards starting from exits (all paths)
2585 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2587 static int exits[MAX_EXITS];
2588 static int exit_count;
2593 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2595 ferr_assert(&ops[i], exit_count > 0);
2598 for (j = 0; j < exit_count; j++) {
2599 ret = scan_for_rsave_pop_reg(exits[j], i + opcnt * 16 + set_flags,
2608 // scan for one or more pop of push <const>
2609 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2610 int push_i, int is_probe)
2612 struct parsed_op *po;
2613 struct label_ref *lr;
2617 for (; i < opcnt; i++)
2620 if (po->cc_scratch == magic)
2621 return ret; // already checked
2622 po->cc_scratch = magic;
2624 if (po->flags & OPF_JMP) {
2625 if (po->flags & OPF_RMD)
2627 if (po->op == OP_CALL)
2630 if (po->btj != NULL) {
2631 for (j = 0; j < po->btj->count; j++) {
2632 check_i(po, po->btj->d[j].bt_i);
2633 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2641 check_i(po, po->bt_i);
2642 if (po->flags & OPF_CJMP) {
2643 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2654 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2657 if (g_labels[i] != NULL) {
2658 // all refs must be visited
2659 lr = &g_label_refs[i];
2660 for (; lr != NULL; lr = lr->next) {
2662 if (ops[lr->i].cc_scratch != magic)
2665 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2669 if (po->op == OP_POP)
2671 if (po->flags & (OPF_RMD|OPF_DONE))
2675 po->flags |= OPF_DONE;
2676 po->datap = &ops[push_i];
2685 static void scan_for_pop_const(int i, int opcnt, int magic)
2689 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
2691 ops[i].flags |= OPF_RMD | OPF_DONE;
2692 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
2696 // check if all branch targets within a marked path are also marked
2697 // note: the path checked must not be empty or end with a branch
2698 static int check_path_branches(int opcnt, int magic)
2700 struct parsed_op *po;
2703 for (i = 0; i < opcnt; i++) {
2705 if (po->cc_scratch != magic)
2708 if (po->flags & OPF_JMP) {
2709 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
2712 if (po->btj != NULL) {
2713 for (j = 0; j < po->btj->count; j++) {
2714 check_i(po, po->btj->d[j].bt_i);
2715 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
2720 check_i(po, po->bt_i);
2721 if (ops[po->bt_i].cc_scratch != magic)
2723 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
2731 // scan for multiple pushes for given pop
2732 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
2735 int reg = ops[pop_i].operand[0].reg;
2736 struct parsed_op *po;
2737 struct label_ref *lr;
2740 ops[i].cc_scratch = magic;
2744 if (g_labels[i] != NULL) {
2745 lr = &g_label_refs[i];
2746 for (; lr != NULL; lr = lr->next) {
2747 check_i(&ops[i], lr->i);
2748 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
2752 if (i > 0 && LAST_OP(i - 1))
2760 if (ops[i].cc_scratch == magic)
2762 ops[i].cc_scratch = magic;
2765 if (po->op == OP_CALL)
2767 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
2770 if (po->op == OP_PUSH)
2772 if (po->datap != NULL)
2774 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2775 // leave this case for reg save/restore handlers
2779 po->flags |= OPF_PPUSH | OPF_DONE;
2780 po->datap = &ops[pop_i];
2789 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
2791 int magic = i + opcnt * 14;
2794 ret = scan_pushes_for_pop_r(i, magic, i, 1);
2796 ret = check_path_branches(opcnt, magic);
2798 ops[i].flags |= OPF_PPUSH | OPF_DONE;
2799 *regmask_pp |= 1 << ops[i].operand[0].reg;
2800 scan_pushes_for_pop_r(i, magic + 1, i, 0);
2805 static void scan_propagate_df(int i, int opcnt)
2807 struct parsed_op *po = &ops[i];
2810 for (; i < opcnt; i++) {
2812 if (po->flags & OPF_DF)
2813 return; // already resolved
2814 po->flags |= OPF_DF;
2816 if (po->op == OP_CALL)
2817 ferr(po, "call with DF set?\n");
2819 if (po->flags & OPF_JMP) {
2820 if (po->btj != NULL) {
2822 for (j = 0; j < po->btj->count; j++) {
2823 check_i(po, po->btj->d[j].bt_i);
2824 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
2829 if (po->flags & OPF_RMD)
2831 check_i(po, po->bt_i);
2832 if (po->flags & OPF_CJMP)
2833 scan_propagate_df(po->bt_i, opcnt);
2839 if (po->flags & OPF_TAIL)
2842 if (po->op == OP_CLD) {
2843 po->flags |= OPF_RMD | OPF_DONE;
2848 ferr(po, "missing DF clear?\n");
2851 // is operand 'opr' referenced by parsed_op 'po'?
2852 static int is_opr_referenced(const struct parsed_opr *opr,
2853 const struct parsed_op *po)
2857 if (opr->type == OPT_REG) {
2858 mask = po->regmask_dst | po->regmask_src;
2859 if (po->op == OP_CALL)
2860 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
2861 if ((1 << opr->reg) & mask)
2867 for (i = 0; i < po->operand_cnt; i++)
2868 if (IS(po->operand[0].name, opr->name))
2874 // is operand 'opr' read by parsed_op 'po'?
2875 static int is_opr_read(const struct parsed_opr *opr,
2876 const struct parsed_op *po)
2878 if (opr->type == OPT_REG) {
2879 if (po->regmask_src & (1 << opr->reg))
2889 // is operand 'opr' modified by parsed_op 'po'?
2890 static int is_opr_modified(const struct parsed_opr *opr,
2891 const struct parsed_op *po)
2895 if (opr->type == OPT_REG) {
2896 if (po->op == OP_CALL) {
2897 mask = po->regmask_dst;
2898 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
2899 if (mask & (1 << opr->reg))
2905 if (po->regmask_dst & (1 << opr->reg))
2911 return IS(po->operand[0].name, opr->name);
2914 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
2915 static int is_any_opr_modified(const struct parsed_op *po_test,
2916 const struct parsed_op *po, int c_mode)
2921 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
2924 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
2927 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
2930 // in reality, it can wreck any register, but in decompiled C
2931 // version it can only overwrite eax or edx:eax
2932 mask = (1 << xAX) | (1 << xDX);
2936 if (po->op == OP_CALL
2937 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
2940 for (i = 0; i < po_test->operand_cnt; i++)
2941 if (IS(po_test->operand[i].name, po->operand[0].name))
2947 // scan for any po_test operand modification in range given
2948 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
2951 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
2954 for (; i < opcnt; i++) {
2955 if (is_any_opr_modified(po_test, &ops[i], c_mode))
2962 // scan for po_test operand[0] modification in range given
2963 static int scan_for_mod_opr0(struct parsed_op *po_test,
2966 for (; i < opcnt; i++) {
2967 if (is_opr_modified(&po_test->operand[0], &ops[i]))
2974 static int scan_for_flag_set(int i, int magic, int *branched,
2975 int *setters, int *setter_cnt)
2977 struct label_ref *lr;
2981 if (ops[i].cc_scratch == magic) {
2982 // is this a problem?
2983 //ferr(&ops[i], "%s looped\n", __func__);
2986 ops[i].cc_scratch = magic;
2988 if (g_labels[i] != NULL) {
2991 lr = &g_label_refs[i];
2992 for (; lr->next; lr = lr->next) {
2993 check_i(&ops[i], lr->i);
2994 ret = scan_for_flag_set(lr->i, magic,
2995 branched, setters, setter_cnt);
3000 check_i(&ops[i], lr->i);
3001 if (i > 0 && LAST_OP(i - 1)) {
3005 ret = scan_for_flag_set(lr->i, magic,
3006 branched, setters, setter_cnt);
3012 if (ops[i].flags & OPF_FLAGS) {
3013 setters[*setter_cnt] = i;
3018 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3025 // scan back for cdq, if anything modifies edx, fail
3026 static int scan_for_cdq_edx(int i)
3029 if (g_labels[i] != NULL) {
3030 if (g_label_refs[i].next != NULL)
3032 if (i > 0 && LAST_OP(i - 1)) {
3033 i = g_label_refs[i].i;
3040 if (ops[i].op == OP_CDQ)
3043 if (ops[i].regmask_dst & (1 << xDX))
3050 static int scan_for_reg_clear(int i, int reg)
3053 if (g_labels[i] != NULL) {
3054 if (g_label_refs[i].next != NULL)
3056 if (i > 0 && LAST_OP(i - 1)) {
3057 i = g_label_refs[i].i;
3064 if (ops[i].op == OP_XOR
3065 && ops[i].operand[0].lmod == OPLM_DWORD
3066 && ops[i].operand[0].reg == ops[i].operand[1].reg
3067 && ops[i].operand[0].reg == reg)
3070 if (ops[i].regmask_dst & (1 << reg))
3077 static void patch_esp_adjust(struct parsed_op *po, int adj)
3079 ferr_assert(po, po->op == OP_ADD);
3080 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3081 ferr_assert(po, po->operand[1].type == OPT_CONST);
3083 // this is a bit of a hack, but deals with use of
3084 // single adj for multiple calls
3085 po->operand[1].val -= adj;
3086 po->flags |= OPF_RMD;
3087 if (po->operand[1].val == 0)
3088 po->flags |= OPF_DONE;
3089 ferr_assert(po, (int)po->operand[1].val >= 0);
3092 // scan for positive, constant esp adjust
3093 // multipath case is preliminary
3094 static int scan_for_esp_adjust(int i, int opcnt,
3095 int adj_expect, int *adj, int *is_multipath, int do_update)
3097 int adj_expect_unknown = 0;
3098 struct parsed_op *po;
3102 *adj = *is_multipath = 0;
3103 if (adj_expect < 0) {
3104 adj_expect_unknown = 1;
3105 adj_expect = 32 * 4; // enough?
3108 for (; i < opcnt && *adj < adj_expect; i++) {
3109 if (g_labels[i] != NULL)
3113 if (po->flags & OPF_DONE)
3116 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3117 if (po->operand[1].type != OPT_CONST)
3118 ferr(&ops[i], "non-const esp adjust?\n");
3119 *adj += po->operand[1].val;
3121 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3124 patch_esp_adjust(po, adj_expect);
3126 po->flags |= OPF_RMD;
3130 else if (po->op == OP_PUSH) {
3131 //if (first_pop == -1)
3132 // first_pop = -2; // none
3133 *adj -= lmod_bytes(po, po->operand[0].lmod);
3135 else if (po->op == OP_POP) {
3136 if (!(po->flags & OPF_DONE)) {
3137 // seems like msvc only uses 'pop ecx' for stack realignment..
3138 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3140 if (first_pop == -1 && *adj >= 0)
3143 if (do_update && *adj >= 0) {
3144 po->flags |= OPF_RMD;
3146 po->flags |= OPF_DONE | OPF_NOREGS;
3149 *adj += lmod_bytes(po, po->operand[0].lmod);
3150 if (*adj > adj_best)
3153 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3154 if (po->op == OP_JMP && po->btj == NULL) {
3160 if (po->op != OP_CALL)
3162 if (po->operand[0].type != OPT_LABEL)
3164 if (po->pp != NULL && po->pp->is_stdcall)
3166 if (adj_expect_unknown && first_pop >= 0)
3168 // assume it's another cdecl call
3172 if (first_pop >= 0) {
3173 // probably only 'pop ecx' was used
3181 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3183 struct parsed_op *po;
3187 ferr(ops, "%s: followed bad branch?\n", __func__);
3189 for (; i < opcnt; i++) {
3191 if (po->cc_scratch == magic)
3193 po->cc_scratch = magic;
3196 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3197 if (po->btj != NULL) {
3199 for (j = 0; j < po->btj->count; j++)
3200 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3204 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3205 if (!(po->flags & OPF_CJMP))
3208 if (po->flags & OPF_TAIL)
3213 static const struct parsed_proto *try_recover_pp(
3214 struct parsed_op *po, const struct parsed_opr *opr, int *search_instead)
3216 const struct parsed_proto *pp = NULL;
3220 // maybe an arg of g_func?
3221 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3223 char ofs_reg[16] = { 0, };
3224 int arg, arg_s, arg_i;
3231 parse_stack_access(po, opr->name, ofs_reg,
3232 &offset, &stack_ra, NULL, 0);
3233 if (ofs_reg[0] != 0)
3234 ferr(po, "offset reg on arg access?\n");
3235 if (offset <= stack_ra) {
3236 // search who set the stack var instead
3237 if (search_instead != NULL)
3238 *search_instead = 1;
3242 arg_i = (offset - stack_ra - 4) / 4;
3243 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3244 if (g_func_pp->arg[arg].reg != NULL)
3250 if (arg == g_func_pp->argc)
3251 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3253 pp = g_func_pp->arg[arg].fptr;
3255 ferr(po, "icall sa: arg%d is not a fptr?\n", arg + 1);
3256 check_func_pp(po, pp, "icall arg");
3258 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3260 p = strchr(opr->name + 1, '[');
3261 memcpy(buf, opr->name, p - opr->name);
3262 buf[p - opr->name] = 0;
3263 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3265 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3266 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3269 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3272 check_func_pp(po, pp, "reg-fptr ref");
3278 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3279 int magic, const struct parsed_proto **pp_found, int *pp_i,
3282 const struct parsed_proto *pp = NULL;
3283 struct parsed_op *po;
3284 struct label_ref *lr;
3286 ops[i].cc_scratch = magic;
3289 if (g_labels[i] != NULL) {
3290 lr = &g_label_refs[i];
3291 for (; lr != NULL; lr = lr->next) {
3292 check_i(&ops[i], lr->i);
3293 scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3295 if (i > 0 && LAST_OP(i - 1))
3303 if (ops[i].cc_scratch == magic)
3305 ops[i].cc_scratch = magic;
3307 if (!(ops[i].flags & OPF_DATA))
3309 if (!is_opr_modified(opr, &ops[i]))
3311 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3312 // most probably trashed by some processing
3317 opr = &ops[i].operand[1];
3318 if (opr->type != OPT_REG)
3322 po = (i >= 0) ? &ops[i] : ops;
3325 // reached the top - can only be an arg-reg
3326 if (opr->type != OPT_REG || g_func_pp == NULL)
3329 for (i = 0; i < g_func_pp->argc; i++) {
3330 if (g_func_pp->arg[i].reg == NULL)
3332 if (IS(opr->name, g_func_pp->arg[i].reg))
3335 if (i == g_func_pp->argc)
3337 pp = g_func_pp->arg[i].fptr;
3339 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3340 i + 1, g_func_pp->arg[i].reg);
3341 check_func_pp(po, pp, "icall reg-arg");
3344 pp = try_recover_pp(po, opr, NULL);
3346 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3347 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3348 || (*pp_found)->is_stdcall != pp->is_stdcall
3349 || (*pp_found)->is_fptr != pp->is_fptr
3350 || (*pp_found)->argc != pp->argc
3351 || (*pp_found)->argc_reg != pp->argc_reg
3352 || (*pp_found)->argc_stack != pp->argc_stack)
3354 ferr(po, "icall: parsed_proto mismatch\n");
3364 static void add_label_ref(struct label_ref *lr, int op_i)
3366 struct label_ref *lr_new;
3373 lr_new = calloc(1, sizeof(*lr_new));
3375 lr_new->next = lr->next;
3379 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3381 struct parsed_op *po = &ops[i];
3382 struct parsed_data *pd;
3383 char label[NAMELEN], *p;
3386 p = strchr(po->operand[0].name, '[');
3390 len = p - po->operand[0].name;
3391 strncpy(label, po->operand[0].name, len);
3394 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3395 if (IS(g_func_pd[j].label, label)) {
3401 //ferr(po, "label '%s' not parsed?\n", label);
3404 if (pd->type != OPT_OFFSET)
3405 ferr(po, "label '%s' with non-offset data?\n", label);
3407 // find all labels, link
3408 for (j = 0; j < pd->count; j++) {
3409 for (l = 0; l < opcnt; l++) {
3410 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3411 add_label_ref(&g_label_refs[l], i);
3421 static void clear_labels(int count)
3425 for (i = 0; i < count; i++) {
3426 if (g_labels[i] != NULL) {
3433 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3438 for (i = 0; i < pp->argc; i++) {
3439 if (pp->arg[i].reg != NULL) {
3440 reg = char_array_i(regs_r32,
3441 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3443 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3444 pp->arg[i].reg, pp->name);
3445 regmask |= 1 << reg;
3452 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3454 if (strstr(pp->ret_type.name, "int64"))
3455 return (1 << xAX) | (1 << xDX);
3456 if (IS(pp->ret_type.name, "float")
3457 || IS(pp->ret_type.name, "double"))
3461 if (strcasecmp(pp->ret_type.name, "void") == 0)
3467 static void resolve_branches_parse_calls(int opcnt)
3469 static const struct {
3473 unsigned int regmask_src;
3474 unsigned int regmask_dst;
3476 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3478 const struct parsed_proto *pp_c;
3479 struct parsed_proto *pp;
3480 struct parsed_data *pd;
3481 struct parsed_op *po;
3482 const char *tmpname;
3486 for (i = 0; i < opcnt; i++)
3492 if (po->datap != NULL) {
3493 pp = calloc(1, sizeof(*pp));
3494 my_assert_not(pp, NULL);
3496 ret = parse_protostr(po->datap, pp);
3498 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3504 if (po->op == OP_CALL) {
3509 else if (po->operand[0].type == OPT_LABEL)
3511 tmpname = opr_name(po, 0);
3512 if (IS_START(tmpname, "loc_"))
3513 ferr(po, "call to loc_*\n");
3515 // convert some calls to pseudo-ops
3516 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3517 if (!IS(tmpname, pseudo_ops[l].name))
3520 po->op = pseudo_ops[l].op;
3521 po->operand_cnt = 0;
3522 po->regmask_src = pseudo_ops[l].regmask_src;
3523 po->regmask_dst = pseudo_ops[l].regmask_dst;
3524 po->flags = pseudo_ops[l].flags;
3525 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3528 if (l < ARRAY_SIZE(pseudo_ops))
3531 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3532 if (!g_header_mode && pp_c == NULL)
3533 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3536 pp = proto_clone(pp_c);
3537 my_assert_not(pp, NULL);
3543 check_func_pp(po, pp, "fptr var call");
3544 if (pp->is_noreturn)
3545 po->flags |= OPF_TAIL;
3551 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3554 if (po->operand[0].type == OPT_REGMEM) {
3555 pd = try_resolve_jumptab(i, opcnt);
3563 for (l = 0; l < opcnt; l++) {
3564 if (g_labels[l] != NULL
3565 && IS(po->operand[0].name, g_labels[l]))
3567 if (l == i + 1 && po->op == OP_JMP) {
3568 // yet another alignment type..
3569 po->flags |= OPF_RMD|OPF_DONE;
3572 add_label_ref(&g_label_refs[l], i);
3578 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3581 if (po->operand[0].type == OPT_LABEL)
3585 ferr(po, "unhandled branch\n");
3589 po->flags |= OPF_TAIL;
3590 if (i > 0 && ops[i - 1].op == OP_POP)
3591 po->flags |= OPF_ATAIL;
3596 static void scan_prologue_epilogue(int opcnt)
3598 int ecx_push = 0, esp_sub = 0;
3602 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
3603 && ops[1].op == OP_MOV
3604 && IS(opr_name(&ops[1], 0), "ebp")
3605 && IS(opr_name(&ops[1], 1), "esp"))
3608 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3609 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3612 if (ops[2].op == OP_SUB && IS(opr_name(&ops[2], 0), "esp")) {
3613 g_stack_fsz = opr_const(&ops[2], 1);
3614 ops[2].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3618 // another way msvc builds stack frame..
3620 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3622 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3626 // and another way..
3627 if (i == 2 && ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3628 && ops[i].operand[1].type == OPT_CONST
3629 && ops[i + 1].op == OP_CALL
3630 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3632 g_stack_fsz += ops[i].operand[1].val;
3633 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3635 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3642 for (; i < opcnt; i++)
3643 if (ops[i].flags & OPF_TAIL)
3646 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3647 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3653 if ((ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
3654 || ops[j].op == OP_LEAVE)
3656 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3658 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
3659 && ops[i].pp->is_noreturn)
3661 // on noreturn, msvc sometimes cleans stack, sometimes not
3666 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3667 ferr(&ops[j], "'pop ebp' expected\n");
3669 if (g_stack_fsz != 0) {
3670 if (ops[j].op == OP_LEAVE)
3672 else if (ops[j].op == OP_POP
3673 && ops[j - 1].op == OP_MOV
3674 && IS(opr_name(&ops[j - 1], 0), "esp")
3675 && IS(opr_name(&ops[j - 1], 1), "ebp"))
3677 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3680 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3682 ferr(&ops[j], "esp restore expected\n");
3685 if (ecx_push && j >= 0 && ops[j].op == OP_POP
3686 && IS(opr_name(&ops[j], 0), "ecx"))
3688 ferr(&ops[j], "unexpected ecx pop\n");
3694 } while (i < opcnt);
3697 ferr(ops, "missing ebp epilogue\n");
3703 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3704 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3710 for (; i < opcnt; i++) {
3711 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
3713 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
3714 && ops[i].operand[1].type == OPT_CONST)
3716 g_stack_fsz = ops[i].operand[1].val;
3717 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3723 if (ecx_push && !esp_sub) {
3724 // could actually be args for a call..
3725 for (; i < opcnt; i++)
3726 if (ops[i].op != OP_PUSH)
3729 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
3730 const struct parsed_proto *pp;
3731 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
3732 j = pp ? pp->argc_stack : 0;
3733 while (i > 0 && j > 0) {
3735 if (ops[i].op == OP_PUSH) {
3736 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
3741 ferr(&ops[i], "unhandled prologue\n");
3744 i = g_stack_fsz = ecx_push = 0;
3745 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3746 if (!(ops[i].flags & OPF_RMD))
3756 if (ecx_push || esp_sub)
3762 for (; i < opcnt; i++)
3763 if (ops[i].flags & OPF_TAIL)
3766 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3767 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3774 for (l = 0; l < ecx_push; l++) {
3775 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
3777 else if (ops[j].op == OP_ADD
3778 && IS(opr_name(&ops[j], 0), "esp")
3779 && ops[j].operand[1].type == OPT_CONST)
3782 l += ops[j].operand[1].val / 4 - 1;
3785 ferr(&ops[j], "'pop ecx' expected\n");
3787 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3791 ferr(&ops[j], "epilogue scan failed\n");
3797 if (ops[j].op != OP_ADD
3798 || !IS(opr_name(&ops[j], 0), "esp")
3799 || ops[j].operand[1].type != OPT_CONST
3800 || ops[j].operand[1].val != g_stack_fsz)
3801 ferr(&ops[j], "'add esp' expected\n");
3803 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3804 ops[j].operand[1].val = 0; // hack for stack arg scanner
3809 } while (i < opcnt);
3812 ferr(ops, "missing esp epilogue\n");
3816 // find an instruction that changed opr before i op
3817 // *op_i must be set to -1 by the caller
3818 // *is_caller is set to 1 if one source is determined to be g_func arg
3819 // returns 1 if found, *op_i is then set to origin
3820 // returns -1 if multiple origins are found
3821 static int resolve_origin(int i, const struct parsed_opr *opr,
3822 int magic, int *op_i, int *is_caller)
3824 struct label_ref *lr;
3827 if (ops[i].cc_scratch == magic)
3829 ops[i].cc_scratch = magic;
3832 if (g_labels[i] != NULL) {
3833 lr = &g_label_refs[i];
3834 for (; lr != NULL; lr = lr->next) {
3835 check_i(&ops[i], lr->i);
3836 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
3838 if (i > 0 && LAST_OP(i - 1))
3844 if (is_caller != NULL)
3849 if (ops[i].cc_scratch == magic)
3851 ops[i].cc_scratch = magic;
3853 if (!(ops[i].flags & OPF_DATA))
3855 if (!is_opr_modified(opr, &ops[i]))
3862 // XXX: could check if the other op does the same
3871 // find an instruction that previously referenced opr
3872 // if multiple results are found - fail
3873 // *op_i must be set to -1 by the caller
3874 // returns 1 if found, *op_i is then set to referencer insn
3875 static int resolve_last_ref(int i, const struct parsed_opr *opr,
3876 int magic, int *op_i)
3878 struct label_ref *lr;
3881 if (ops[i].cc_scratch == magic)
3883 ops[i].cc_scratch = magic;
3886 if (g_labels[i] != NULL) {
3887 lr = &g_label_refs[i];
3888 for (; lr != NULL; lr = lr->next) {
3889 check_i(&ops[i], lr->i);
3890 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
3892 if (i > 0 && LAST_OP(i - 1))
3900 if (ops[i].cc_scratch == magic)
3902 ops[i].cc_scratch = magic;
3904 if (!is_opr_referenced(opr, &ops[i]))
3915 // find next instruction that reads opr
3916 // *op_i must be set to -1 by the caller
3917 // on return, *op_i is set to first referencer insn
3918 // returns 1 if exactly 1 referencer is found
3919 static int find_next_read(int i, int opcnt,
3920 const struct parsed_opr *opr, int magic, int *op_i)
3922 struct parsed_op *po;
3925 for (; i < opcnt; i++)
3927 if (ops[i].cc_scratch == magic)
3929 ops[i].cc_scratch = magic;
3932 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3933 if (po->btj != NULL) {
3935 for (j = 0; j < po->btj->count; j++) {
3936 check_i(po, po->btj->d[j].bt_i);
3937 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
3943 if (po->flags & OPF_RMD)
3945 check_i(po, po->bt_i);
3946 if (po->flags & OPF_CJMP) {
3947 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
3956 if (!is_opr_read(opr, po)) {
3957 if (is_opr_modified(opr, po)
3958 && (po->op == OP_CALL
3959 || ((po->flags & OPF_DATA)
3960 && po->operand[0].lmod == OPLM_DWORD)))
3965 if (po->flags & OPF_TAIL)
3980 static int try_resolve_const(int i, const struct parsed_opr *opr,
3981 int magic, unsigned int *val)
3986 ret = resolve_origin(i, opr, magic, &s_i, NULL);
3989 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
3992 *val = ops[i].operand[1].val;
3999 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4000 int *pp_i, int *multi_src)
4002 const struct parsed_proto *pp = NULL;
4003 int search_advice = 0;
4013 switch (ops[i].operand[0].type) {
4015 // try to resolve struct member calls
4016 ret = sscanf(ops[i].operand[0].name, "%3s+%x%n",
4017 s_reg, &offset, &len);
4018 if (ret == 2 && len == strlen(ops[i].operand[0].name))
4020 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4022 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, reg);
4024 ret = resolve_origin(i, &opr, i + opcnt * 19, &j, NULL);
4027 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4028 && ops[j].operand[0].lmod == OPLM_DWORD
4029 && ops[j].pp == NULL) // no hint
4031 // allow one simple dereference (directx)
4032 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4033 ops[j].operand[1].name);
4036 struct parsed_opr opr2 = OPR_INIT(OPT_REG, OPLM_DWORD, reg);
4038 ret = resolve_origin(j, &opr2, j + opcnt * 19, &k, NULL);
4043 if (ops[j].op != OP_MOV)
4045 if (ops[j].operand[0].lmod != OPLM_DWORD)
4047 if (ops[j].pp != NULL) {
4051 else if (ops[j].operand[1].type == OPT_REGMEM) {
4052 // allow 'hello[ecx]' - assume array of same type items
4053 ret = sscanf(ops[j].operand[1].name, "%[^[][e%2s]",
4057 pp = proto_parse(g_fhdr, name, g_quiet_pp);
4059 else if (ops[j].operand[1].type == OPT_LABEL)
4060 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4065 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4069 pp = proto_lookup_struct(g_fhdr, pp->type.name, offset);
4076 pp = try_recover_pp(&ops[i], &ops[i].operand[0], &search_advice);
4081 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4089 static struct parsed_proto *process_call_early(int i, int opcnt,
4092 struct parsed_op *po = &ops[i];
4093 struct parsed_proto *pp;
4099 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4103 // look for and make use of esp adjust
4105 if (!pp->is_stdcall && pp->argc_stack > 0)
4106 ret = scan_for_esp_adjust(i + 1, opcnt,
4107 pp->argc_stack * 4, &adj, &multipath, 0);
4109 if (pp->argc_stack > adj / 4)
4113 if (ops[ret].op == OP_POP) {
4114 for (j = 1; j < adj / 4; j++) {
4115 if (ops[ret + j].op != OP_POP
4116 || ops[ret + j].operand[0].reg != xCX)
4128 static struct parsed_proto *process_call(int i, int opcnt)
4130 struct parsed_op *po = &ops[i];
4131 const struct parsed_proto *pp_c;
4132 struct parsed_proto *pp;
4133 const char *tmpname;
4134 int call_i = -1, ref_i = -1;
4135 int adj = 0, multipath = 0;
4138 tmpname = opr_name(po, 0);
4143 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4145 if (!pp_c->is_func && !pp_c->is_fptr)
4146 ferr(po, "call to non-func: %s\n", pp_c->name);
4147 pp = proto_clone(pp_c);
4148 my_assert_not(pp, NULL);
4150 // not resolved just to single func
4153 switch (po->operand[0].type) {
4155 // we resolved this call and no longer need the register
4156 po->regmask_src &= ~(1 << po->operand[0].reg);
4158 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4159 && ops[call_i].operand[1].type == OPT_LABEL)
4161 // no other source users?
4162 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4164 if (ret == 1 && call_i == ref_i) {
4165 // and nothing uses it after us?
4167 find_next_read(i + 1, opcnt, &po->operand[0],
4168 i + opcnt * 11, &ref_i);
4170 // then also don't need the source mov
4171 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4183 pp = calloc(1, sizeof(*pp));
4184 my_assert_not(pp, NULL);
4187 ret = scan_for_esp_adjust(i + 1, opcnt,
4188 -1, &adj, &multipath, 0);
4189 if (ret < 0 || adj < 0) {
4190 if (!g_allow_regfunc)
4191 ferr(po, "non-__cdecl indirect call unhandled yet\n");
4192 pp->is_unresolved = 1;
4196 if (adj > ARRAY_SIZE(pp->arg))
4197 ferr(po, "esp adjust too large: %d\n", adj);
4198 pp->ret_type.name = strdup("int");
4199 pp->argc = pp->argc_stack = adj;
4200 for (arg = 0; arg < pp->argc; arg++)
4201 pp->arg[arg].type.name = strdup("int");
4206 // look for and make use of esp adjust
4209 if (!pp->is_stdcall && pp->argc_stack > 0) {
4210 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
4211 ret = scan_for_esp_adjust(i + 1, opcnt,
4212 adj_expect, &adj, &multipath, 0);
4215 if (pp->is_vararg) {
4216 if (adj / 4 < pp->argc_stack) {
4217 fnote(po, "(this call)\n");
4218 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
4219 adj, pp->argc_stack * 4);
4221 // modify pp to make it have varargs as normal args
4223 pp->argc += adj / 4 - pp->argc_stack;
4224 for (; arg < pp->argc; arg++) {
4225 pp->arg[arg].type.name = strdup("int");
4228 if (pp->argc > ARRAY_SIZE(pp->arg))
4229 ferr(po, "too many args for '%s'\n", tmpname);
4231 if (pp->argc_stack > adj / 4) {
4232 fnote(po, "(this call)\n");
4233 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
4234 tmpname, pp->argc_stack * 4, adj);
4237 scan_for_esp_adjust(i + 1, opcnt,
4238 pp->argc_stack * 4, &adj, &multipath, 1);
4240 else if (pp->is_vararg)
4241 ferr(po, "missing esp_adjust for vararg func '%s'\n",
4247 static int collect_call_args_early(struct parsed_op *po, int i,
4248 struct parsed_proto *pp, int *regmask)
4253 for (arg = 0; arg < pp->argc; arg++)
4254 if (pp->arg[arg].reg == NULL)
4257 // first see if it can be easily done
4258 for (j = i; j > 0 && arg < pp->argc; )
4260 if (g_labels[j] != NULL)
4264 if (ops[j].op == OP_CALL)
4266 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP)
4268 else if (ops[j].op == OP_POP)
4270 else if (ops[j].flags & OPF_CJMP)
4272 else if (ops[j].op == OP_PUSH) {
4273 if (ops[j].flags & (OPF_FARG|OPF_FARGNR))
4275 ret = scan_for_mod(&ops[j], j + 1, i, 1);
4279 if (pp->arg[arg].type.is_va_list)
4283 for (arg++; arg < pp->argc; arg++)
4284 if (pp->arg[arg].reg == NULL)
4293 for (arg = 0; arg < pp->argc; arg++)
4294 if (pp->arg[arg].reg == NULL)
4297 for (j = i; j > 0 && arg < pp->argc; )
4301 if (ops[j].op == OP_PUSH)
4303 ops[j].p_argnext = -1;
4304 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
4305 pp->arg[arg].datap = &ops[j];
4307 if (ops[j].operand[0].type == OPT_REG)
4308 *regmask |= 1 << ops[j].operand[0].reg;
4310 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4311 ops[j].flags &= ~OPF_RSAVE;
4314 for (arg++; arg < pp->argc; arg++)
4315 if (pp->arg[arg].reg == NULL)
4323 static int collect_call_args_r(struct parsed_op *po, int i,
4324 struct parsed_proto *pp, int *regmask, int *save_arg_vars,
4325 int *arg_grp, int arg, int magic, int need_op_saving, int may_reuse)
4327 struct parsed_proto *pp_tmp;
4328 struct parsed_op *po_tmp;
4329 struct label_ref *lr;
4330 int need_to_save_current;
4331 int arg_grp_current = 0;
4332 int save_args_seen = 0;
4340 ferr(po, "dead label encountered\n");
4344 for (; arg < pp->argc; arg++)
4345 if (pp->arg[arg].reg == NULL)
4347 magic = (magic & 0xffffff) | (arg << 24);
4349 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
4351 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
4352 if (ops[j].cc_scratch != magic) {
4353 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
4357 // ok: have already been here
4360 ops[j].cc_scratch = magic;
4362 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
4363 lr = &g_label_refs[j];
4364 if (lr->next != NULL)
4366 for (; lr->next; lr = lr->next) {
4367 check_i(&ops[j], lr->i);
4368 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4370 ret = collect_call_args_r(po, lr->i, pp, regmask, save_arg_vars,
4371 arg_grp, arg, magic, need_op_saving, may_reuse);
4376 check_i(&ops[j], lr->i);
4377 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4379 if (j > 0 && LAST_OP(j - 1)) {
4380 // follow last branch in reverse
4385 ret = collect_call_args_r(po, lr->i, pp, regmask, save_arg_vars,
4386 arg_grp, arg, magic, need_op_saving, may_reuse);
4392 if (ops[j].op == OP_CALL)
4394 if (pp->is_unresolved)
4399 ferr(po, "arg collect hit unparsed call '%s'\n",
4400 ops[j].operand[0].name);
4401 if (may_reuse && pp_tmp->argc_stack > 0)
4402 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
4403 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
4405 // esp adjust of 0 means we collected it before
4406 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
4407 && (ops[j].operand[1].type != OPT_CONST
4408 || ops[j].operand[1].val != 0))
4410 if (pp->is_unresolved)
4413 fnote(po, "(this call)\n");
4414 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
4415 arg, pp->argc, ops[j].operand[1].val);
4417 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
4419 if (pp->is_unresolved)
4422 fnote(po, "(this call)\n");
4423 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
4425 else if (ops[j].flags & OPF_CJMP)
4427 if (pp->is_unresolved)
4432 else if (ops[j].op == OP_PUSH
4433 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
4435 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
4438 ops[j].p_argnext = -1;
4439 po_tmp = pp->arg[arg].datap;
4441 ops[j].p_argnext = po_tmp - ops;
4442 pp->arg[arg].datap = &ops[j];
4444 need_to_save_current = 0;
4447 if (ops[j].operand[0].type == OPT_REG)
4448 reg = ops[j].operand[0].reg;
4450 if (!need_op_saving) {
4451 ret = scan_for_mod(&ops[j], j + 1, i, 1);
4452 need_to_save_current = (ret >= 0);
4454 if (need_op_saving || need_to_save_current) {
4455 // mark this push as one that needs operand saving
4456 ops[j].flags &= ~OPF_RMD;
4457 if (ops[j].p_argnum == 0) {
4458 ops[j].p_argnum = arg + 1;
4459 save_args |= 1 << arg;
4461 else if (ops[j].p_argnum < arg + 1) {
4462 // XXX: might kill valid var..
4463 //*save_arg_vars &= ~(1 << (ops[j].p_argnum - 1));
4464 ops[j].p_argnum = arg + 1;
4465 save_args |= 1 << arg;
4468 if (save_args_seen & (1 << (ops[j].p_argnum - 1))) {
4471 if (arg_grp_current >= MAX_ARG_GRP)
4472 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
4473 ops[j].p_argnum, pp->name);
4476 else if (ops[j].p_argnum == 0)
4477 ops[j].flags |= OPF_RMD;
4479 // some PUSHes are reused by different calls on other branches,
4480 // but that can't happen if we didn't branch, so they
4481 // can be removed from future searches (handles nested calls)
4483 ops[j].flags |= OPF_FARGNR;
4485 ops[j].flags |= OPF_FARG;
4486 ops[j].flags &= ~OPF_RSAVE;
4488 // check for __VALIST
4489 if (!pp->is_unresolved && g_func_pp != NULL
4490 && pp->arg[arg].type.is_va_list)
4493 ret = resolve_origin(j, &ops[j].operand[0],
4494 magic + 1, &k, NULL);
4495 if (ret == 1 && k >= 0)
4497 if (ops[k].op == OP_LEA) {
4498 if (!g_func_pp->is_vararg)
4499 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
4502 snprintf(buf, sizeof(buf), "arg_%X",
4503 g_func_pp->argc_stack * 4);
4504 if (strstr(ops[k].operand[1].name, buf)
4505 || strstr(ops[k].operand[1].name, "arglist"))
4507 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
4508 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
4509 save_args &= ~(1 << arg);
4513 ferr(&ops[k], "va_list arg detection failed\n");
4515 // check for va_list from g_func_pp arg too
4516 else if (ops[k].op == OP_MOV
4517 && is_stack_access(&ops[k], &ops[k].operand[1]))
4519 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
4520 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
4522 ops[k].flags |= OPF_RMD | OPF_DONE;
4523 ops[j].flags |= OPF_RMD;
4524 ops[j].p_argpass = ret + 1;
4525 save_args &= ~(1 << arg);
4532 *save_arg_vars |= save_args;
4534 // tracking reg usage
4536 *regmask |= 1 << reg;
4539 if (!pp->is_unresolved) {
4541 for (; arg < pp->argc; arg++)
4542 if (pp->arg[arg].reg == NULL)
4545 magic = (magic & 0xffffff) | (arg << 24);
4548 if (ops[j].p_arggrp > arg_grp_current) {
4550 arg_grp_current = ops[j].p_arggrp;
4552 if (ops[j].p_argnum > 0)
4553 save_args_seen |= 1 << (ops[j].p_argnum - 1);
4556 if (arg < pp->argc) {
4557 ferr(po, "arg collect failed for '%s': %d/%d\n",
4558 pp->name, arg, pp->argc);
4562 if (arg_grp_current > *arg_grp)
4563 *arg_grp = arg_grp_current;
4568 static int collect_call_args(struct parsed_op *po, int i,
4569 struct parsed_proto *pp, int *regmask, int *save_arg_vars,
4572 // arg group is for cases when pushes for
4573 // multiple funcs are going on
4574 struct parsed_op *po_tmp;
4575 int save_arg_vars_current = 0;
4580 ret = collect_call_args_r(po, i, pp, regmask,
4581 &save_arg_vars_current, &arg_grp, 0, magic, 0, 0);
4586 // propagate arg_grp
4587 for (a = 0; a < pp->argc; a++) {
4588 if (pp->arg[a].reg != NULL)
4591 po_tmp = pp->arg[a].datap;
4592 while (po_tmp != NULL) {
4593 po_tmp->p_arggrp = arg_grp;
4594 if (po_tmp->p_argnext > 0)
4595 po_tmp = &ops[po_tmp->p_argnext];
4601 save_arg_vars[arg_grp] |= save_arg_vars_current;
4603 if (pp->is_unresolved) {
4605 pp->argc_stack += ret;
4606 for (a = 0; a < pp->argc; a++)
4607 if (pp->arg[a].type.name == NULL)
4608 pp->arg[a].type.name = strdup("int");
4614 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
4615 int regmask_now, int *regmask,
4616 int regmask_save_now, int *regmask_save,
4617 int *regmask_init, int regmask_arg)
4619 struct parsed_op *po;
4628 for (; i < opcnt; i++)
4631 if (cbits[i >> 3] & (1 << (i & 7)))
4633 cbits[i >> 3] |= (1 << (i & 7));
4635 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4636 if (po->flags & (OPF_RMD|OPF_DONE))
4638 if (po->btj != NULL) {
4639 for (j = 0; j < po->btj->count; j++) {
4640 check_i(po, po->btj->d[j].bt_i);
4641 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
4642 regmask_now, regmask, regmask_save_now, regmask_save,
4643 regmask_init, regmask_arg);
4648 check_i(po, po->bt_i);
4649 if (po->flags & OPF_CJMP)
4650 reg_use_pass(po->bt_i, opcnt, cbits,
4651 regmask_now, regmask, regmask_save_now, regmask_save,
4652 regmask_init, regmask_arg);
4658 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
4659 && !g_func_pp->is_userstack
4660 && po->operand[0].type == OPT_REG)
4662 reg = po->operand[0].reg;
4663 ferr_assert(po, reg >= 0);
4666 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
4667 if (regmask_now & (1 << reg)) {
4668 already_saved = regmask_save_now & (1 << reg);
4669 flags_set = OPF_RSAVE | OPF_DONE;
4672 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0);
4674 scan_for_pop(i + 1, opcnt, i + opcnt * 4, reg, 0, flags_set);
4677 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
4679 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
4684 ferr_assert(po, !already_saved);
4685 po->flags |= flags_set;
4687 if (regmask_now & (1 << reg)) {
4688 regmask_save_now |= (1 << reg);
4689 *regmask_save |= regmask_save_now;
4694 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
4695 reg = po->operand[0].reg;
4696 ferr_assert(po, reg >= 0);
4698 if (regmask_save_now & (1 << reg))
4699 regmask_save_now &= ~(1 << reg);
4701 regmask_now &= ~(1 << reg);
4704 else if (po->op == OP_CALL) {
4705 if ((po->regmask_dst & (1 << xAX))
4706 && !(po->regmask_dst & (1 << xDX)))
4708 if (po->flags & OPF_TAIL)
4709 // don't need eax, will do "return f();" or "f(); return;"
4710 po->regmask_dst &= ~(1 << xAX);
4712 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
4714 find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
4717 po->regmask_dst &= ~(1 << xAX);
4722 if (po->flags & OPF_NOREGS)
4725 if (po->flags & OPF_FPUSH) {
4726 if (regmask_now & mxST1)
4727 ferr(po, "TODO: FPUSH on active ST1\n");
4728 if (regmask_now & mxST0)
4729 po->flags |= OPF_FSHIFT;
4730 mask = mxST0 | mxST1;
4731 regmask_now = (regmask_now & ~mask) | ((regmask_now & mxST0) << 1);
4734 // if incomplete register is used, clear it on init to avoid
4735 // later use of uninitialized upper part in some situations
4736 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
4737 && po->operand[0].lmod != OPLM_DWORD)
4739 reg = po->operand[0].reg;
4740 ferr_assert(po, reg >= 0);
4742 if (!(regmask_now & (1 << reg)))
4743 *regmask_init |= 1 << reg;
4746 regmask_op = po->regmask_src | po->regmask_dst;
4748 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
4749 regmask_new &= ~(1 << xSP);
4750 if (g_bp_frame && !(po->flags & OPF_EBP_S))
4751 regmask_new &= ~(1 << xBP);
4753 if (po->op == OP_CALL) {
4754 // allow fastcall calls from anywhere, calee may be also sitting
4755 // in some fastcall table even when it's not using reg args
4756 if (regmask_new & po->regmask_src & (1 << xCX)) {
4757 *regmask_init |= (1 << xCX);
4758 regmask_now |= (1 << xCX);
4759 regmask_new &= ~(1 << xCX);
4761 if (regmask_new & po->regmask_src & (1 << xDX)) {
4762 *regmask_init |= (1 << xDX);
4763 regmask_now |= (1 << xDX);
4764 regmask_new &= ~(1 << xDX);
4768 if (regmask_new != 0)
4769 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
4771 if (regmask_op & (1 << xBP)) {
4772 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
4773 if (po->regmask_dst & (1 << xBP))
4774 // compiler decided to drop bp frame and use ebp as scratch
4775 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
4777 regmask_op &= ~(1 << xBP);
4781 regmask_now |= regmask_op;
4782 *regmask |= regmask_now;
4785 if (po->flags & OPF_FPOP) {
4786 mask = mxST0 | mxST1;
4787 if (!(regmask_now & mask))
4788 ferr(po, "float pop on empty stack?\n");
4789 if (regmask_now & mxST1)
4790 po->flags |= OPF_FSHIFT;
4791 regmask_now = (regmask_now & ~mask) | ((regmask_now & mxST1) >> 1);
4794 if (po->flags & OPF_TAIL) {
4795 if (regmask_now & (mxST0 | mxST1))
4796 ferr(po, "float regs on tail: %x\n", regmask_now);
4802 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
4806 for (i = 0; i < pp->argc; i++)
4807 if (pp->arg[i].reg == NULL)
4811 memmove(&pp->arg[i + 1], &pp->arg[i],
4812 sizeof(pp->arg[0]) * pp->argc_stack);
4813 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
4814 pp->arg[i].reg = strdup(reg);
4815 pp->arg[i].type.name = strdup("int");
4820 static void output_std_flags(FILE *fout, struct parsed_op *po,
4821 int *pfomask, const char *dst_opr_text)
4823 if (*pfomask & (1 << PFO_Z)) {
4824 fprintf(fout, "\n cond_z = (%s%s == 0);",
4825 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
4826 *pfomask &= ~(1 << PFO_Z);
4828 if (*pfomask & (1 << PFO_S)) {
4829 fprintf(fout, "\n cond_s = (%s%s < 0);",
4830 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
4831 *pfomask &= ~(1 << PFO_S);
4836 OPP_FORCE_NORETURN = (1 << 0),
4837 OPP_SIMPLE_ARGS = (1 << 1),
4838 OPP_ALIGN = (1 << 2),
4841 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
4844 const char *cconv = "";
4846 if (pp->is_fastcall)
4847 cconv = "__fastcall ";
4848 else if (pp->is_stdcall && pp->argc_reg == 0)
4849 cconv = "__stdcall ";
4851 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
4853 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
4854 fprintf(fout, "noreturn ");
4857 static void output_pp(FILE *fout, const struct parsed_proto *pp,
4862 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
4866 output_pp_attrs(fout, pp, flags);
4869 fprintf(fout, "%s", pp->name);
4874 for (i = 0; i < pp->argc; i++) {
4876 fprintf(fout, ", ");
4877 if (pp->arg[i].fptr != NULL && !(flags & OPP_SIMPLE_ARGS)) {
4879 output_pp(fout, pp->arg[i].fptr, 0);
4881 else if (pp->arg[i].type.is_retreg) {
4882 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
4885 fprintf(fout, "%s", pp->arg[i].type.name);
4887 fprintf(fout, " a%d", i + 1);
4890 if (pp->is_vararg) {
4892 fprintf(fout, ", ");
4893 fprintf(fout, "...");
4898 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
4904 snprintf(buf1, sizeof(buf1), "%d", grp);
4905 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
4910 static void gen_x_cleanup(int opcnt);
4912 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
4914 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
4915 struct parsed_opr *last_arith_dst = NULL;
4916 char buf1[256], buf2[256], buf3[256], cast[64];
4917 struct parsed_proto *pp, *pp_tmp;
4918 struct parsed_data *pd;
4920 int save_arg_vars[MAX_ARG_GRP] = { 0, };
4921 unsigned char cbits[MAX_OPS / 8];
4923 int need_tmp_var = 0;
4926 int label_pending = 0;
4927 int regmask_save = 0; // regs saved/restored in this func
4928 int regmask_arg; // regs from this function args (fastcall, etc)
4929 int regmask_ret; // regs needed on ret
4930 int regmask_now; // temp
4931 int regmask_init = 0; // regs that need zero initialization
4932 int regmask_pp = 0; // regs used in complex push-pop graph
4933 int regmask = 0; // used regs
4942 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
4943 g_stack_frame_used = 0;
4945 g_func_pp = proto_parse(fhdr, funcn, 0);
4946 if (g_func_pp == NULL)
4947 ferr(ops, "proto_parse failed for '%s'\n", funcn);
4949 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
4950 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
4952 if (g_func_pp->has_retreg) {
4953 for (arg = 0; arg < g_func_pp->argc; arg++) {
4954 if (g_func_pp->arg[arg].type.is_retreg) {
4955 reg = char_array_i(regs_r32,
4956 ARRAY_SIZE(regs_r32), g_func_pp->arg[arg].reg);
4957 ferr_assert(ops, reg >= 0);
4958 regmask_ret |= 1 << reg;
4964 // - resolve all branches
4965 // - parse calls with labels
4966 resolve_branches_parse_calls(opcnt);
4969 // - handle ebp/esp frame, remove ops related to it
4970 scan_prologue_epilogue(opcnt);
4973 // - remove dead labels
4974 // - set regs needed at ret
4975 for (i = 0; i < opcnt; i++)
4977 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
4982 if (ops[i].op == OP_RET)
4983 ops[i].regmask_src |= regmask_ret;
4987 // - process trivial calls
4988 for (i = 0; i < opcnt; i++)
4991 if (po->flags & (OPF_RMD|OPF_DONE))
4994 if (po->op == OP_CALL)
4996 pp = process_call_early(i, opcnt, &j);
4998 if (!(po->flags & OPF_ATAIL))
4999 // since we know the args, try to collect them
5000 if (collect_call_args_early(po, i, pp, ®mask) != 0)
5006 // commit esp adjust
5007 if (ops[j].op != OP_POP)
5008 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5010 for (l = 0; l < pp->argc_stack; l++)
5011 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
5015 if (strstr(pp->ret_type.name, "int64"))
5018 po->flags |= OPF_DONE;
5024 // - process calls, stage 2
5025 // - handle some push/pop pairs
5026 // - scan for STD/CLD, propagate DF
5027 for (i = 0; i < opcnt; i++)
5030 if (po->flags & OPF_RMD)
5033 if (po->op == OP_CALL)
5035 if (!(po->flags & OPF_DONE)) {
5036 pp = process_call(i, opcnt);
5038 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
5039 // since we know the args, collect them
5040 collect_call_args(po, i, pp, ®mask, save_arg_vars,
5043 // for unresolved, collect after other passes
5047 ferr_assert(po, pp != NULL);
5049 po->regmask_src |= get_pp_arg_regmask_src(pp);
5050 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
5052 if (po->regmask_dst & mxST0)
5053 po->flags |= OPF_FPUSH;
5055 if (strstr(pp->ret_type.name, "int64"))
5061 if (po->flags & OPF_DONE)
5064 if (po->op == OP_PUSH && !(po->flags & OPF_FARG)
5065 && !(po->flags & OPF_RSAVE) && po->operand[0].type == OPT_CONST)
5067 scan_for_pop_const(i, opcnt, i + opcnt * 12);
5069 else if (po->op == OP_POP)
5070 scan_pushes_for_pop(i, opcnt, ®mask_pp);
5071 else if (po->op == OP_STD) {
5072 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
5073 scan_propagate_df(i + 1, opcnt);
5078 // - find POPs for PUSHes, rm both
5079 // - scan for all used registers
5080 memset(cbits, 0, sizeof(cbits));
5081 reg_use_pass(0, opcnt, cbits, 0, ®mask,
5082 0, ®mask_save, ®mask_init, regmask_arg);
5085 // - find flag set ops for their users
5086 // - do unresolved calls
5087 // - declare indirect functions
5088 for (i = 0; i < opcnt; i++)
5091 if (po->flags & (OPF_RMD|OPF_DONE))
5094 if (po->flags & OPF_CC)
5096 int setters[16], cnt = 0, branched = 0;
5098 ret = scan_for_flag_set(i, i + opcnt * 6,
5099 &branched, setters, &cnt);
5100 if (ret < 0 || cnt <= 0)
5101 ferr(po, "unable to trace flag setter(s)\n");
5102 if (cnt > ARRAY_SIZE(setters))
5103 ferr(po, "too many flag setters\n");
5105 for (j = 0; j < cnt; j++)
5107 tmp_op = &ops[setters[j]]; // flag setter
5110 // to get nicer code, we try to delay test and cmp;
5111 // if we can't because of operand modification, or if we
5112 // have arith op, or branch, make it calculate flags explicitly
5113 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
5115 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
5116 pfomask = 1 << po->pfo;
5118 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
5119 pfomask = 1 << po->pfo;
5122 // see if we'll be able to handle based on op result
5123 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
5124 && po->pfo != PFO_Z && po->pfo != PFO_S
5125 && po->pfo != PFO_P)
5127 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
5129 pfomask = 1 << po->pfo;
5132 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
5133 propagate_lmod(tmp_op, &tmp_op->operand[0],
5134 &tmp_op->operand[1]);
5135 if (tmp_op->operand[0].lmod == OPLM_DWORD)
5140 tmp_op->pfomask |= pfomask;
5141 cond_vars |= pfomask;
5143 // note: may overwrite, currently not a problem
5147 if (po->op == OP_RCL || po->op == OP_RCR
5148 || po->op == OP_ADC || po->op == OP_SBB)
5149 cond_vars |= 1 << PFO_C;
5152 if (po->op == OP_CMPS || po->op == OP_SCAS) {
5153 cond_vars |= 1 << PFO_Z;
5155 else if (po->op == OP_MUL
5156 || (po->op == OP_IMUL && po->operand_cnt == 1))
5158 if (po->operand[0].lmod == OPLM_DWORD)
5161 else if (po->op == OP_CALL) {
5162 // note: resolved non-reg calls are OPF_DONE already
5164 ferr_assert(po, pp != NULL);
5166 if (pp->is_unresolved) {
5167 int regmask_stack = 0;
5168 collect_call_args(po, i, pp, ®mask, save_arg_vars,
5171 // this is pretty rough guess:
5172 // see ecx and edx were pushed (and not their saved versions)
5173 for (arg = 0; arg < pp->argc; arg++) {
5174 if (pp->arg[arg].reg != NULL)
5177 tmp_op = pp->arg[arg].datap;
5179 ferr(po, "parsed_op missing for arg%d\n", arg);
5180 if (tmp_op->p_argnum == 0 && tmp_op->operand[0].type == OPT_REG)
5181 regmask_stack |= 1 << tmp_op->operand[0].reg;
5184 if (!((regmask_stack & (1 << xCX))
5185 && (regmask_stack & (1 << xDX))))
5187 if (pp->argc_stack != 0
5188 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
5190 pp_insert_reg_arg(pp, "ecx");
5191 pp->is_fastcall = 1;
5192 regmask_init |= 1 << xCX;
5193 regmask |= 1 << xCX;
5195 if (pp->argc_stack != 0
5196 || ((regmask | regmask_arg) & (1 << xDX)))
5198 pp_insert_reg_arg(pp, "edx");
5199 regmask_init |= 1 << xDX;
5200 regmask |= 1 << xDX;
5204 // note: __cdecl doesn't fall into is_unresolved category
5205 if (pp->argc_stack > 0)
5209 else if (po->op == OP_MOV && po->operand[0].pp != NULL
5210 && po->operand[1].pp != NULL)
5212 // <var> = offset <something>
5213 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
5214 && !IS_START(po->operand[1].name, "off_"))
5216 if (!po->operand[0].pp->is_fptr)
5217 ferr(po, "%s not declared as fptr when it should be\n",
5218 po->operand[0].name);
5219 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
5220 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
5221 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
5222 fnote(po, "var: %s\n", buf1);
5223 fnote(po, "func: %s\n", buf2);
5224 ferr(po, "^ mismatch\n");
5228 else if (po->op == OP_DIV || po->op == OP_IDIV) {
5229 if (po->operand[0].lmod == OPLM_DWORD) {
5230 // 32bit division is common, look for it
5231 if (po->op == OP_DIV)
5232 ret = scan_for_reg_clear(i, xDX);
5234 ret = scan_for_cdq_edx(i);
5236 po->flags |= OPF_32BIT;
5243 else if (po->op == OP_CLD)
5244 po->flags |= OPF_RMD | OPF_DONE;
5245 else if (po->op == OPP_FTOL) {
5246 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
5248 find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
5250 po->flags |= OPF_32BIT;
5253 if (po->op == OP_RCL || po->op == OP_RCR || po->op == OP_XCHG)
5257 // output starts here
5259 // define userstack size
5260 if (g_func_pp->is_userstack) {
5261 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
5262 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
5263 fprintf(fout, "#endif\n");
5266 // the function itself
5267 ferr_assert(ops, !g_func_pp->is_fptr);
5268 output_pp(fout, g_func_pp,
5269 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
5270 fprintf(fout, "\n{\n");
5272 // declare indirect functions
5273 for (i = 0; i < opcnt; i++) {
5275 if (po->flags & OPF_RMD)
5278 if (po->op == OP_CALL) {
5281 ferr(po, "NULL pp\n");
5283 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
5284 if (pp->name[0] != 0) {
5285 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
5286 memcpy(pp->name, "i_", 2);
5288 // might be declared already
5290 for (j = 0; j < i; j++) {
5291 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
5292 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
5302 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
5305 output_pp(fout, pp, OPP_SIMPLE_ARGS);
5306 fprintf(fout, ";\n");
5311 // output LUTs/jumptables
5312 for (i = 0; i < g_func_pd_cnt; i++) {
5314 fprintf(fout, " static const ");
5315 if (pd->type == OPT_OFFSET) {
5316 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
5318 for (j = 0; j < pd->count; j++) {
5320 fprintf(fout, ", ");
5321 fprintf(fout, "&&%s", pd->d[j].u.label);
5325 fprintf(fout, "%s %s[] =\n { ",
5326 lmod_type_u(ops, pd->lmod), pd->label);
5328 for (j = 0; j < pd->count; j++) {
5330 fprintf(fout, ", ");
5331 fprintf(fout, "%u", pd->d[j].u.val);
5334 fprintf(fout, " };\n");
5338 // declare stack frame, va_arg
5340 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
5341 if (g_func_lmods & (1 << OPLM_WORD))
5342 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
5343 if (g_func_lmods & (1 << OPLM_BYTE))
5344 fprintf(fout, " u8 b[%d];", g_stack_fsz);
5345 if (g_func_lmods & (1 << OPLM_QWORD))
5346 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
5347 fprintf(fout, " } sf;\n");
5351 if (g_func_pp->is_userstack) {
5352 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
5353 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
5357 if (g_func_pp->is_vararg) {
5358 fprintf(fout, " va_list ap;\n");
5362 // declare arg-registers
5363 for (i = 0; i < g_func_pp->argc; i++) {
5364 if (g_func_pp->arg[i].reg != NULL) {
5365 reg = char_array_i(regs_r32,
5366 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
5367 if (regmask & (1 << reg)) {
5368 if (g_func_pp->arg[i].type.is_retreg)
5369 fprintf(fout, " u32 %s = *r_%s;\n",
5370 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
5372 fprintf(fout, " u32 %s = (u32)a%d;\n",
5373 g_func_pp->arg[i].reg, i + 1);
5376 if (g_func_pp->arg[i].type.is_retreg)
5377 ferr(ops, "retreg '%s' is unused?\n",
5378 g_func_pp->arg[i].reg);
5379 fprintf(fout, " // %s = a%d; // unused\n",
5380 g_func_pp->arg[i].reg, i + 1);
5386 // declare normal registers
5387 regmask_now = regmask & ~regmask_arg;
5388 regmask_now &= ~(1 << xSP);
5389 if (regmask_now & 0x00ff) {
5390 for (reg = 0; reg < 8; reg++) {
5391 if (regmask_now & (1 << reg)) {
5392 fprintf(fout, " u32 %s", regs_r32[reg]);
5393 if (regmask_init & (1 << reg))
5394 fprintf(fout, " = 0");
5395 fprintf(fout, ";\n");
5401 if (regmask_now & 0xff00) {
5402 for (reg = 8; reg < 16; reg++) {
5403 if (regmask_now & (1 << reg)) {
5404 fprintf(fout, " mmxr %s", regs_r32[reg]);
5405 if (regmask_init & (1 << reg))
5406 fprintf(fout, " = { 0, }");
5407 fprintf(fout, ";\n");
5413 if (regmask_now & 0xff0000) {
5414 for (reg = 16; reg < 24; reg++) {
5415 if (regmask_now & (1 << reg)) {
5416 fprintf(fout, " double f_st%d", reg - 16);
5417 if (regmask_init & (1 << reg))
5418 fprintf(fout, " = 0");
5419 fprintf(fout, ";\n");
5426 for (reg = 0; reg < 8; reg++) {
5427 if (regmask_save & (1 << reg)) {
5428 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
5434 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
5435 if (save_arg_vars[i] == 0)
5437 for (reg = 0; reg < 32; reg++) {
5438 if (save_arg_vars[i] & (1 << reg)) {
5439 fprintf(fout, " u32 %s;\n",
5440 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
5446 // declare push-pop temporaries
5448 for (reg = 0; reg < 8; reg++) {
5449 if (regmask_pp & (1 << reg)) {
5450 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
5457 for (i = 0; i < 8; i++) {
5458 if (cond_vars & (1 << i)) {
5459 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
5466 fprintf(fout, " u32 tmp;\n");
5471 fprintf(fout, " u64 tmp64;\n");
5476 fprintf(fout, "\n");
5478 if (g_func_pp->is_vararg) {
5479 if (g_func_pp->argc_stack == 0)
5480 ferr(ops, "vararg func without stack args?\n");
5481 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
5485 for (i = 0; i < opcnt; i++)
5487 if (g_labels[i] != NULL) {
5488 fprintf(fout, "\n%s:\n", g_labels[i]);
5491 delayed_flag_op = NULL;
5492 last_arith_dst = NULL;
5496 if (po->flags & OPF_RMD)
5501 #define assert_operand_cnt(n_) \
5502 if (po->operand_cnt != n_) \
5503 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
5505 // conditional/flag using op?
5506 if (po->flags & OPF_CC)
5512 // we go through all this trouble to avoid using parsed_flag_op,
5513 // which makes generated code much nicer
5514 if (delayed_flag_op != NULL)
5516 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
5517 po->pfo, po->pfo_inv);
5520 else if (last_arith_dst != NULL
5521 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
5522 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
5525 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
5526 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
5527 last_arith_dst->lmod, buf3);
5530 else if (tmp_op != NULL) {
5531 // use preprocessed flag calc results
5532 if (!(tmp_op->pfomask & (1 << po->pfo)))
5533 ferr(po, "not prepared for pfo %d\n", po->pfo);
5535 // note: pfo_inv was not yet applied
5536 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
5537 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
5540 ferr(po, "all methods of finding comparison failed\n");
5543 if (po->flags & OPF_JMP) {
5544 fprintf(fout, " if %s", buf1);
5546 else if (po->op == OP_RCL || po->op == OP_RCR
5547 || po->op == OP_ADC || po->op == OP_SBB)
5550 fprintf(fout, " cond_%s = %s;\n",
5551 parsed_flag_op_names[po->pfo], buf1);
5553 else if (po->flags & OPF_DATA) { // SETcc
5554 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
5555 fprintf(fout, " %s = %s;", buf2, buf1);
5558 ferr(po, "unhandled conditional op\n");
5562 pfomask = po->pfomask;
5564 if (po->flags & (OPF_REPZ|OPF_REPNZ)) {
5565 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
5566 ret = try_resolve_const(i, &opr, opcnt * 7 + i, &uval);
5568 if (ret != 1 || uval == 0) {
5569 // we need initial flags for ecx=0 case..
5570 if (i > 0 && ops[i - 1].op == OP_XOR
5571 && IS(ops[i - 1].operand[0].name,
5572 ops[i - 1].operand[1].name))
5574 fprintf(fout, " cond_z = ");
5575 if (pfomask & (1 << PFO_C))
5576 fprintf(fout, "cond_c = ");
5577 fprintf(fout, "0;\n");
5579 else if (last_arith_dst != NULL) {
5580 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
5581 out_test_for_cc(buf1, sizeof(buf1), po, PFO_Z, 0,
5582 last_arith_dst->lmod, buf3);
5583 fprintf(fout, " cond_z = %s;\n", buf1);
5586 ferr(po, "missing initial ZF\n");
5593 assert_operand_cnt(2);
5594 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5595 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5596 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
5597 fprintf(fout, " %s = %s;", buf1,
5598 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5603 assert_operand_cnt(2);
5604 po->operand[1].lmod = OPLM_DWORD; // always
5605 fprintf(fout, " %s = %s;",
5606 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5607 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5612 assert_operand_cnt(2);
5613 fprintf(fout, " %s = %s;",
5614 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5615 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5619 assert_operand_cnt(2);
5620 switch (po->operand[1].lmod) {
5622 strcpy(buf3, "(s8)");
5625 strcpy(buf3, "(s16)");
5628 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
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 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5639 fprintf(fout, " tmp = %s;",
5640 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
5641 fprintf(fout, " %s = %s;",
5642 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5643 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5644 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
5645 fprintf(fout, " %s = %stmp;",
5646 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
5647 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
5648 snprintf(g_comment, sizeof(g_comment), "xchg");
5652 assert_operand_cnt(1);
5653 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5654 fprintf(fout, " %s = ~%s;", buf1, buf1);
5658 assert_operand_cnt(2);
5659 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5660 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
5661 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
5662 strcpy(g_comment, "xlat");
5666 assert_operand_cnt(2);
5667 fprintf(fout, " %s = (s32)%s >> 31;",
5668 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5669 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5670 strcpy(g_comment, "cdq");
5674 if (po->flags & OPF_REP) {
5675 assert_operand_cnt(3);
5680 assert_operand_cnt(2);
5681 fprintf(fout, " %s = %sesi; esi %c= %d;",
5682 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
5683 lmod_cast_u_ptr(po, po->operand[1].lmod),
5684 (po->flags & OPF_DF) ? '-' : '+',
5685 lmod_bytes(po, po->operand[1].lmod));
5686 strcpy(g_comment, "lods");
5691 if (po->flags & OPF_REP) {
5692 assert_operand_cnt(3);
5693 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
5694 (po->flags & OPF_DF) ? '-' : '+',
5695 lmod_bytes(po, po->operand[1].lmod));
5696 fprintf(fout, " %sedi = eax;",
5697 lmod_cast_u_ptr(po, po->operand[1].lmod));
5698 strcpy(g_comment, "rep stos");
5701 assert_operand_cnt(2);
5702 fprintf(fout, " %sedi = eax; edi %c= %d;",
5703 lmod_cast_u_ptr(po, po->operand[1].lmod),
5704 (po->flags & OPF_DF) ? '-' : '+',
5705 lmod_bytes(po, po->operand[1].lmod));
5706 strcpy(g_comment, "stos");
5711 j = lmod_bytes(po, po->operand[0].lmod);
5712 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
5713 l = (po->flags & OPF_DF) ? '-' : '+';
5714 if (po->flags & OPF_REP) {
5715 assert_operand_cnt(3);
5717 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
5720 " %sedi = %sesi;", buf1, buf1);
5721 strcpy(g_comment, "rep movs");
5724 assert_operand_cnt(2);
5725 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
5726 buf1, buf1, l, j, l, j);
5727 strcpy(g_comment, "movs");
5732 // repe ~ repeat while ZF=1
5733 j = lmod_bytes(po, po->operand[0].lmod);
5734 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
5735 l = (po->flags & OPF_DF) ? '-' : '+';
5736 if (po->flags & OPF_REP) {
5737 assert_operand_cnt(3);
5739 " for (; ecx != 0; ecx--) {\n");
5740 if (pfomask & (1 << PFO_C)) {
5743 " cond_c = %sesi < %sedi;\n", buf1, buf1);
5744 pfomask &= ~(1 << PFO_C);
5747 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
5748 buf1, buf1, l, j, l, j);
5750 " if (cond_z %s 0) break;\n",
5751 (po->flags & OPF_REPZ) ? "==" : "!=");
5754 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
5755 (po->flags & OPF_REPZ) ? "e" : "ne");
5758 assert_operand_cnt(2);
5760 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
5761 buf1, buf1, l, j, l, j);
5762 strcpy(g_comment, "cmps");
5764 pfomask &= ~(1 << PFO_Z);
5765 last_arith_dst = NULL;
5766 delayed_flag_op = NULL;
5770 // only does ZF (for now)
5771 // repe ~ repeat while ZF=1
5772 j = lmod_bytes(po, po->operand[1].lmod);
5773 l = (po->flags & OPF_DF) ? '-' : '+';
5774 if (po->flags & OPF_REP) {
5775 assert_operand_cnt(3);
5777 " for (; ecx != 0; ecx--) {\n");
5779 " cond_z = (%seax == %sedi); edi %c= %d;\n",
5780 lmod_cast_u(po, po->operand[1].lmod),
5781 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
5783 " if (cond_z %s 0) break;\n",
5784 (po->flags & OPF_REPZ) ? "==" : "!=");
5787 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
5788 (po->flags & OPF_REPZ) ? "e" : "ne");
5791 assert_operand_cnt(2);
5792 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
5793 lmod_cast_u(po, po->operand[1].lmod),
5794 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
5795 strcpy(g_comment, "scas");
5797 pfomask &= ~(1 << PFO_Z);
5798 last_arith_dst = NULL;
5799 delayed_flag_op = NULL;
5802 // arithmetic w/flags
5804 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
5805 goto dualop_arith_const;
5806 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5810 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5811 if (po->operand[1].type == OPT_CONST) {
5812 j = lmod_bytes(po, po->operand[0].lmod);
5813 if (((1ull << j * 8) - 1) == po->operand[1].val)
5814 goto dualop_arith_const;
5819 assert_operand_cnt(2);
5820 fprintf(fout, " %s %s= %s;",
5821 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5823 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5824 output_std_flags(fout, po, &pfomask, buf1);
5825 last_arith_dst = &po->operand[0];
5826 delayed_flag_op = NULL;
5830 // and 0, or ~0 used instead mov
5831 assert_operand_cnt(2);
5832 fprintf(fout, " %s = %s;",
5833 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5834 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5835 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
5836 output_std_flags(fout, po, &pfomask, buf1);
5837 last_arith_dst = &po->operand[0];
5838 delayed_flag_op = NULL;
5843 assert_operand_cnt(2);
5844 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5845 if (pfomask & (1 << PFO_C)) {
5846 if (po->operand[1].type == OPT_CONST) {
5847 l = lmod_bytes(po, po->operand[0].lmod) * 8;
5848 j = po->operand[1].val;
5851 if (po->op == OP_SHL)
5855 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
5859 ferr(po, "zero shift?\n");
5863 pfomask &= ~(1 << PFO_C);
5865 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
5866 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5867 if (po->operand[1].type != OPT_CONST)
5868 fprintf(fout, " & 0x1f");
5870 output_std_flags(fout, po, &pfomask, buf1);
5871 last_arith_dst = &po->operand[0];
5872 delayed_flag_op = NULL;
5876 assert_operand_cnt(2);
5877 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5878 fprintf(fout, " %s = %s%s >> %s;", buf1,
5879 lmod_cast_s(po, po->operand[0].lmod), buf1,
5880 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5881 output_std_flags(fout, po, &pfomask, buf1);
5882 last_arith_dst = &po->operand[0];
5883 delayed_flag_op = NULL;
5888 assert_operand_cnt(3);
5889 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5890 l = lmod_bytes(po, po->operand[0].lmod) * 8;
5891 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
5892 if (po->operand[2].type != OPT_CONST) {
5893 // no handling for "undefined" case, hopefully not needed
5894 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
5897 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
5898 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5899 if (po->op == OP_SHLD) {
5900 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
5901 buf1, buf3, buf1, buf2, l, buf3);
5902 strcpy(g_comment, "shld");
5905 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
5906 buf1, buf3, buf1, buf2, l, buf3);
5907 strcpy(g_comment, "shrd");
5909 output_std_flags(fout, po, &pfomask, buf1);
5910 last_arith_dst = &po->operand[0];
5911 delayed_flag_op = NULL;
5916 assert_operand_cnt(2);
5917 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5918 if (po->operand[1].type == OPT_CONST) {
5919 j = po->operand[1].val;
5920 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
5921 fprintf(fout, po->op == OP_ROL ?
5922 " %s = (%s << %d) | (%s >> %d);" :
5923 " %s = (%s >> %d) | (%s << %d);",
5924 buf1, buf1, j, buf1,
5925 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
5929 output_std_flags(fout, po, &pfomask, buf1);
5930 last_arith_dst = &po->operand[0];
5931 delayed_flag_op = NULL;
5936 assert_operand_cnt(2);
5937 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5938 l = lmod_bytes(po, po->operand[0].lmod) * 8;
5939 if (po->operand[1].type == OPT_CONST) {
5940 j = po->operand[1].val % l;
5942 ferr(po, "zero rotate\n");
5943 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
5944 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
5945 if (po->op == OP_RCL) {
5947 " %s = (%s << %d) | (cond_c << %d)",
5948 buf1, buf1, j, j - 1);
5950 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
5954 " %s = (%s >> %d) | (cond_c << %d)",
5955 buf1, buf1, j, l - j);
5957 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
5959 fprintf(fout, ";\n");
5960 fprintf(fout, " cond_c = tmp;");
5964 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
5965 output_std_flags(fout, po, &pfomask, buf1);
5966 last_arith_dst = &po->operand[0];
5967 delayed_flag_op = NULL;
5971 assert_operand_cnt(2);
5972 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5973 if (IS(opr_name(po, 0), opr_name(po, 1))) {
5974 // special case for XOR
5975 if (pfomask & (1 << PFO_BE)) { // weird, but it happens..
5976 fprintf(fout, " cond_be = 1;\n");
5977 pfomask &= ~(1 << PFO_BE);
5979 fprintf(fout, " %s = 0;",
5980 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
5981 last_arith_dst = &po->operand[0];
5982 delayed_flag_op = NULL;
5988 assert_operand_cnt(2);
5989 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5990 if (pfomask & (1 << PFO_C)) {
5991 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
5992 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
5993 if (po->operand[0].lmod == OPLM_DWORD) {
5994 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
5995 fprintf(fout, " cond_c = tmp64 >> 32;\n");
5996 fprintf(fout, " %s = (u32)tmp64;",
5997 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
5998 strcat(g_comment, " add64");
6001 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
6002 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
6003 fprintf(fout, " %s += %s;",
6004 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6007 pfomask &= ~(1 << PFO_C);
6008 output_std_flags(fout, po, &pfomask, buf1);
6009 last_arith_dst = &po->operand[0];
6010 delayed_flag_op = NULL;
6016 assert_operand_cnt(2);
6017 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6018 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
6019 for (j = 0; j <= PFO_LE; j++) {
6020 if (!(pfomask & (1 << j)))
6022 if (j == PFO_Z || j == PFO_S)
6025 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0);
6026 fprintf(fout, " cond_%s = %s;\n",
6027 parsed_flag_op_names[j], buf1);
6028 pfomask &= ~(1 << j);
6035 assert_operand_cnt(2);
6036 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6037 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6038 if (po->op == OP_SBB
6039 && IS(po->operand[0].name, po->operand[1].name))
6041 // avoid use of unitialized var
6042 fprintf(fout, " %s = -cond_c;", buf1);
6043 // carry remains what it was
6044 pfomask &= ~(1 << PFO_C);
6047 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
6048 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6050 output_std_flags(fout, po, &pfomask, buf1);
6051 last_arith_dst = &po->operand[0];
6052 delayed_flag_op = NULL;
6056 assert_operand_cnt(2);
6057 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6058 fprintf(fout, " %s = %s ? __builtin_ffs(%s) - 1 : 0;",
6059 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6061 output_std_flags(fout, po, &pfomask, buf1);
6062 last_arith_dst = &po->operand[0];
6063 delayed_flag_op = NULL;
6064 strcat(g_comment, " bsf");
6068 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
6069 for (j = 0; j <= PFO_LE; j++) {
6070 if (!(pfomask & (1 << j)))
6072 if (j == PFO_Z || j == PFO_S || j == PFO_C)
6075 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0);
6076 fprintf(fout, " cond_%s = %s;\n",
6077 parsed_flag_op_names[j], buf1);
6078 pfomask &= ~(1 << j);
6084 if (pfomask & (1 << PFO_C))
6085 // carry is unaffected by inc/dec.. wtf?
6086 ferr(po, "carry propagation needed\n");
6088 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6089 if (po->operand[0].type == OPT_REG) {
6090 strcpy(buf2, po->op == OP_INC ? "++" : "--");
6091 fprintf(fout, " %s%s;", buf1, buf2);
6094 strcpy(buf2, po->op == OP_INC ? "+" : "-");
6095 fprintf(fout, " %s %s= 1;", buf1, buf2);
6097 output_std_flags(fout, po, &pfomask, buf1);
6098 last_arith_dst = &po->operand[0];
6099 delayed_flag_op = NULL;
6103 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6104 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
6105 fprintf(fout, " %s = -%s%s;", buf1,
6106 lmod_cast_s(po, po->operand[0].lmod), buf2);
6107 last_arith_dst = &po->operand[0];
6108 delayed_flag_op = NULL;
6109 if (pfomask & (1 << PFO_C)) {
6110 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
6111 pfomask &= ~(1 << PFO_C);
6116 if (po->operand_cnt == 2) {
6117 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6120 if (po->operand_cnt == 3)
6121 ferr(po, "TODO imul3\n");
6124 assert_operand_cnt(1);
6125 switch (po->operand[0].lmod) {
6127 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
6128 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
6129 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
6130 fprintf(fout, " edx = tmp64 >> 32;\n");
6131 fprintf(fout, " eax = tmp64;");
6134 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
6135 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
6136 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
6140 ferr(po, "TODO: unhandled mul type\n");
6143 last_arith_dst = NULL;
6144 delayed_flag_op = NULL;
6149 assert_operand_cnt(1);
6150 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6151 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
6152 po->op == OP_IDIV));
6153 switch (po->operand[0].lmod) {
6155 if (po->flags & OPF_32BIT)
6156 snprintf(buf2, sizeof(buf2), "%seax", cast);
6158 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
6159 snprintf(buf2, sizeof(buf2), "%stmp64",
6160 (po->op == OP_IDIV) ? "(s64)" : "");
6162 if (po->operand[0].type == OPT_REG
6163 && po->operand[0].reg == xDX)
6165 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
6166 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
6169 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
6170 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
6174 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
6175 snprintf(buf2, sizeof(buf2), "%stmp",
6176 (po->op == OP_IDIV) ? "(s32)" : "");
6177 if (po->operand[0].type == OPT_REG
6178 && po->operand[0].reg == xDX)
6180 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
6182 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
6186 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
6188 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
6191 strcat(g_comment, " div16");
6194 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
6196 last_arith_dst = NULL;
6197 delayed_flag_op = NULL;
6202 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6204 for (j = 0; j < 8; j++) {
6205 if (pfomask & (1 << j)) {
6206 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
6207 fprintf(fout, " cond_%s = %s;",
6208 parsed_flag_op_names[j], buf1);
6215 last_arith_dst = NULL;
6216 delayed_flag_op = po;
6220 // SETcc - should already be handled
6223 // note: we reuse OP_Jcc for SETcc, only flags differ
6225 fprintf(fout, "\n goto %s;", po->operand[0].name);
6229 fprintf(fout, " if (ecx == 0)\n");
6230 fprintf(fout, " goto %s;", po->operand[0].name);
6231 strcat(g_comment, " jecxz");
6235 fprintf(fout, " if (--ecx != 0)\n");
6236 fprintf(fout, " goto %s;", po->operand[0].name);
6237 strcat(g_comment, " loop");
6241 assert_operand_cnt(1);
6242 last_arith_dst = NULL;
6243 delayed_flag_op = NULL;
6245 if (po->operand[0].type == OPT_REGMEM) {
6246 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
6249 ferr(po, "parse failure for jmp '%s'\n",
6250 po->operand[0].name);
6251 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
6254 else if (po->operand[0].type != OPT_LABEL)
6255 ferr(po, "unhandled jmp type\n");
6257 fprintf(fout, " goto %s;", po->operand[0].name);
6261 assert_operand_cnt(1);
6263 my_assert_not(pp, NULL);
6266 if (po->flags & OPF_CC) {
6267 // we treat conditional branch to another func
6268 // (yes such code exists..) as conditional tailcall
6270 fprintf(fout, " {\n");
6273 if (pp->is_fptr && !pp->is_arg) {
6274 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
6275 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6277 if (pp->is_unresolved)
6278 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
6279 buf3, asmfn, po->asmln, pp->name);
6282 fprintf(fout, "%s", buf3);
6283 if (strstr(pp->ret_type.name, "int64")) {
6284 if (po->flags & OPF_TAIL)
6285 ferr(po, "int64 and tail?\n");
6286 fprintf(fout, "tmp64 = ");
6288 else if (!IS(pp->ret_type.name, "void")) {
6289 if (po->flags & OPF_TAIL) {
6290 if (regmask_ret & mxAX) {
6291 fprintf(fout, "return ");
6292 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
6293 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
6295 else if (regmask_ret & mxST0)
6296 ferr(po, "float tailcall\n");
6298 else if (po->regmask_dst & mxAX) {
6299 fprintf(fout, "eax = ");
6300 if (pp->ret_type.is_ptr)
6301 fprintf(fout, "(u32)");
6303 else if (po->regmask_dst & mxST0) {
6304 fprintf(fout, "f_st0 = ");
6308 if (pp->name[0] == 0)
6309 ferr(po, "missing pp->name\n");
6310 fprintf(fout, "%s%s(", pp->name,
6311 pp->has_structarg ? "_sa" : "");
6313 if (po->flags & OPF_ATAIL) {
6314 if (pp->argc_stack != g_func_pp->argc_stack
6315 || (pp->argc_stack > 0
6316 && pp->is_stdcall != g_func_pp->is_stdcall))
6317 ferr(po, "incompatible tailcall\n");
6318 if (g_func_pp->has_retreg)
6319 ferr(po, "TODO: retreg+tailcall\n");
6321 for (arg = j = 0; arg < pp->argc; arg++) {
6323 fprintf(fout, ", ");
6326 if (pp->arg[arg].type.is_ptr)
6327 snprintf(cast, sizeof(cast), "(%s)",
6328 pp->arg[arg].type.name);
6330 if (pp->arg[arg].reg != NULL) {
6331 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6335 for (; j < g_func_pp->argc; j++)
6336 if (g_func_pp->arg[j].reg == NULL)
6338 fprintf(fout, "%sa%d", cast, j + 1);
6343 for (arg = 0; arg < pp->argc; arg++) {
6345 fprintf(fout, ", ");
6348 if (pp->arg[arg].type.is_ptr)
6349 snprintf(cast, sizeof(cast), "(%s)",
6350 pp->arg[arg].type.name);
6352 if (pp->arg[arg].reg != NULL) {
6353 if (pp->arg[arg].type.is_retreg)
6354 fprintf(fout, "&%s", pp->arg[arg].reg);
6356 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6361 tmp_op = pp->arg[arg].datap;
6363 ferr(po, "parsed_op missing for arg%d\n", arg);
6365 if (tmp_op->flags & OPF_VAPUSH) {
6366 fprintf(fout, "ap");
6368 else if (tmp_op->p_argpass != 0) {
6369 fprintf(fout, "a%d", tmp_op->p_argpass);
6371 else if (tmp_op->p_argnum != 0) {
6372 fprintf(fout, "%s%s", cast,
6373 saved_arg_name(buf1, sizeof(buf1),
6374 tmp_op->p_arggrp, tmp_op->p_argnum));
6378 out_src_opr(buf1, sizeof(buf1),
6379 tmp_op, &tmp_op->operand[0], cast, 0));
6383 fprintf(fout, ");");
6385 if (strstr(pp->ret_type.name, "int64")) {
6386 fprintf(fout, "\n");
6387 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
6388 fprintf(fout, "%seax = tmp64;", buf3);
6391 if (pp->is_unresolved) {
6392 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
6394 strcat(g_comment, buf2);
6397 if (po->flags & OPF_TAIL) {
6399 if (i == opcnt - 1 || pp->is_noreturn)
6401 else if (IS(pp->ret_type.name, "void"))
6403 else if (!(regmask_ret & (1 << xAX)))
6405 // else already handled as 'return f()'
6408 fprintf(fout, "\n%sreturn;", buf3);
6409 strcat(g_comment, " ^ tailcall");
6412 strcat(g_comment, " tailcall");
6414 if ((regmask_ret & (1 << xAX))
6415 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
6417 ferr(po, "int func -> void func tailcall?\n");
6420 if (pp->is_noreturn)
6421 strcat(g_comment, " noreturn");
6422 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
6423 strcat(g_comment, " argframe");
6424 if (po->flags & OPF_CC)
6425 strcat(g_comment, " cond");
6427 if (po->flags & OPF_CC)
6428 fprintf(fout, "\n }");
6430 delayed_flag_op = NULL;
6431 last_arith_dst = NULL;
6435 if (g_func_pp->is_vararg)
6436 fprintf(fout, " va_end(ap);\n");
6437 if (g_func_pp->has_retreg) {
6438 for (arg = 0; arg < g_func_pp->argc; arg++)
6439 if (g_func_pp->arg[arg].type.is_retreg)
6440 fprintf(fout, " *r_%s = %s;\n",
6441 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
6444 if (!(regmask_ret & (1 << xAX))) {
6445 if (i != opcnt - 1 || label_pending)
6446 fprintf(fout, " return;");
6448 else if (g_func_pp->ret_type.is_ptr) {
6449 fprintf(fout, " return (%s)eax;",
6450 g_func_pp->ret_type.name);
6452 else if (IS(g_func_pp->ret_type.name, "__int64"))
6453 fprintf(fout, " return ((u64)edx << 32) | eax;");
6455 fprintf(fout, " return eax;");
6457 last_arith_dst = NULL;
6458 delayed_flag_op = NULL;
6462 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6463 if (po->p_argnum != 0) {
6464 // special case - saved func arg
6465 fprintf(fout, " %s = %s;",
6466 saved_arg_name(buf2, sizeof(buf2),
6467 po->p_arggrp, po->p_argnum), buf1);
6470 else if (po->flags & OPF_RSAVE) {
6471 fprintf(fout, " s_%s = %s;", buf1, buf1);
6474 else if (po->flags & OPF_PPUSH) {
6476 ferr_assert(po, tmp_op != NULL);
6477 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
6478 fprintf(fout, " pp_%s = %s;", buf2, buf1);
6481 else if (g_func_pp->is_userstack) {
6482 fprintf(fout, " *(--esp) = %s;", buf1);
6485 if (!(g_ida_func_attr & IDAFA_NORETURN))
6486 ferr(po, "stray push encountered\n");
6491 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6492 if (po->flags & OPF_RSAVE) {
6493 fprintf(fout, " %s = s_%s;", buf1, buf1);
6496 else if (po->flags & OPF_PPUSH) {
6497 // push/pop graph / non-const
6498 ferr_assert(po, po->datap == NULL);
6499 fprintf(fout, " %s = pp_%s;", buf1, buf1);
6502 else if (po->datap != NULL) {
6505 fprintf(fout, " %s = %s;", buf1,
6506 out_src_opr(buf2, sizeof(buf2),
6507 tmp_op, &tmp_op->operand[0],
6508 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6511 else if (g_func_pp->is_userstack) {
6512 fprintf(fout, " %s = *esp++;", buf1);
6516 ferr(po, "stray pop encountered\n");
6525 if (po->flags & OPF_FSHIFT)
6526 fprintf(fout, " f_st1 = f_st0;\n");
6527 if (po->operand[0].type == OPT_REG
6528 && po->operand[0].reg == xST0)
6530 strcat(g_comment, " fld st");
6533 fprintf(fout, " f_st0 = %s;",
6534 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0]));
6535 strcat(g_comment, " fld");
6539 if (po->flags & OPF_FSHIFT)
6540 fprintf(fout, " f_st1 = f_st0;\n");
6541 fprintf(fout, " f_st0 = (double)%s;",
6542 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6543 lmod_cast(po, po->operand[0].lmod, 1), 0));
6544 strcat(g_comment, " fild");
6548 if (po->flags & OPF_FSHIFT)
6549 fprintf(fout, " f_st1 = f_st0;\n");
6550 fprintf(fout, " f_st0 = ");
6551 switch (po->operand[0].val) {
6552 case X87_CONST_1: fprintf(fout, "1.0;"); break;
6553 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
6554 default: ferr(po, "TODO\n"); break;
6559 if ((po->flags & OPF_FPOP) && po->operand[0].type == OPT_REG
6560 && po->operand[0].reg == xST0)
6565 fprintf(fout, " %s = f_st0;",
6566 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0]));
6567 if (po->flags & OPF_FSHIFT)
6568 fprintf(fout, "\n f_st0 = f_st1;");
6569 strcat(g_comment, " fst");
6577 case OP_FADD: j = '+'; break;
6578 case OP_FDIV: j = '/'; break;
6579 case OP_FMUL: j = '*'; break;
6580 case OP_FSUB: j = '-'; break;
6581 default: j = 'x'; break;
6583 if (po->flags & OPF_FSHIFT) {
6584 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
6587 fprintf(fout, " %s %c= %s;",
6588 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0]),
6590 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1]));
6596 if (po->flags & OPF_FSHIFT)
6597 snprintf(buf1, sizeof(buf1), "f_st0");
6599 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0]);
6600 fprintf(fout, " %s = %s %c %s;", buf1,
6601 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1]),
6602 po->op == OP_FDIVR ? '/' : '-',
6603 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0]));
6611 case OP_FIADD: j = '+'; break;
6612 case OP_FIDIV: j = '/'; break;
6613 case OP_FIMUL: j = '*'; break;
6614 case OP_FISUB: j = '-'; break;
6615 default: j = 'x'; break;
6617 fprintf(fout, " f_st0 %c= (double)%s;", j,
6618 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6619 lmod_cast(po, po->operand[0].lmod, 1), 0));
6624 fprintf(fout, " f_st0 = %s %c f_st0;",
6625 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1]),
6626 po->op == OP_FIDIVR ? '/' : '-');
6630 ferr_assert(po, po->flags & OPF_32BIT);
6631 fprintf(fout, " eax = (s32)f_st0;");
6632 if (po->flags & OPF_FSHIFT)
6633 fprintf(fout, "\n f_st0 = f_st1;");
6634 strcat(g_comment, " ftol");
6639 strcpy(g_comment, " (emms)");
6644 ferr(po, "unhandled op type %d, flags %x\n",
6649 if (g_comment[0] != 0) {
6650 char *p = g_comment;
6651 while (my_isblank(*p))
6653 fprintf(fout, " // %s", p);
6658 fprintf(fout, "\n");
6660 // some sanity checking
6661 if (po->flags & OPF_REP) {
6662 if (po->op != OP_STOS && po->op != OP_MOVS
6663 && po->op != OP_CMPS && po->op != OP_SCAS)
6664 ferr(po, "unexpected rep\n");
6665 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
6666 && (po->op == OP_CMPS || po->op == OP_SCAS))
6667 ferr(po, "cmps/scas with plain rep\n");
6669 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
6670 && po->op != OP_CMPS && po->op != OP_SCAS)
6671 ferr(po, "unexpected repz/repnz\n");
6674 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
6676 // see is delayed flag stuff is still valid
6677 if (delayed_flag_op != NULL && delayed_flag_op != po) {
6678 if (is_any_opr_modified(delayed_flag_op, po, 0))
6679 delayed_flag_op = NULL;
6682 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
6683 if (is_opr_modified(last_arith_dst, po))
6684 last_arith_dst = NULL;
6690 if (g_stack_fsz && !g_stack_frame_used)
6691 fprintf(fout, " (void)sf;\n");
6693 fprintf(fout, "}\n\n");
6695 gen_x_cleanup(opcnt);
6698 static void gen_x_cleanup(int opcnt)
6702 for (i = 0; i < opcnt; i++) {
6703 struct label_ref *lr, *lr_del;
6705 lr = g_label_refs[i].next;
6706 while (lr != NULL) {
6711 g_label_refs[i].i = -1;
6712 g_label_refs[i].next = NULL;
6714 if (ops[i].op == OP_CALL) {
6716 proto_release(ops[i].pp);
6722 struct func_proto_dep;
6724 struct func_prototype {
6729 int has_ret:3; // -1, 0, 1: unresolved, no, yes
6730 unsigned int dep_resolved:1;
6731 unsigned int is_stdcall:1;
6732 struct func_proto_dep *dep_func;
6734 const struct parsed_proto *pp; // seed pp, if any
6737 struct func_proto_dep {
6739 struct func_prototype *proto;
6740 int regmask_live; // .. at the time of call
6741 unsigned int ret_dep:1; // return from this is caller's return
6744 static struct func_prototype *hg_fp;
6745 static int hg_fp_cnt;
6747 static struct scanned_var {
6749 enum opr_lenmod lmod;
6750 unsigned int is_seeded:1;
6751 unsigned int is_c_str:1;
6752 const struct parsed_proto *pp; // seed pp, if any
6754 static int hg_var_cnt;
6756 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
6759 struct func_prototype *hg_fp_add(const char *funcn)
6761 struct func_prototype *fp;
6763 if ((hg_fp_cnt & 0xff) == 0) {
6764 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
6765 my_assert_not(hg_fp, NULL);
6766 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
6769 fp = &hg_fp[hg_fp_cnt];
6770 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
6772 fp->argc_stack = -1;
6778 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
6783 for (i = 0; i < fp->dep_func_cnt; i++)
6784 if (IS(fp->dep_func[i].name, name))
6785 return &fp->dep_func[i];
6790 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
6793 if (hg_fp_find_dep(fp, name))
6796 if ((fp->dep_func_cnt & 0xff) == 0) {
6797 fp->dep_func = realloc(fp->dep_func,
6798 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
6799 my_assert_not(fp->dep_func, NULL);
6800 memset(&fp->dep_func[fp->dep_func_cnt], 0,
6801 sizeof(fp->dep_func[0]) * 0x100);
6803 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
6807 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
6809 const struct func_prototype *p1 = p1_, *p2 = p2_;
6810 return strcmp(p1->name, p2->name);
6814 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
6816 const struct func_prototype *p1 = p1_, *p2 = p2_;
6817 return p1->id - p2->id;
6821 // recursive register dep pass
6822 // - track saved regs (part 2)
6823 // - try to figure out arg-regs
6824 // - calculate reg deps
6825 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
6826 struct func_prototype *fp, int regmask_save, int regmask_dst,
6827 int *regmask_dep, int *has_ret)
6829 struct func_proto_dep *dep;
6830 struct parsed_op *po;
6831 int from_caller = 0;
6836 for (; i < opcnt; i++)
6838 if (cbits[i >> 3] & (1 << (i & 7)))
6840 cbits[i >> 3] |= (1 << (i & 7));
6844 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
6845 if (po->flags & OPF_RMD)
6848 if (po->btj != NULL) {
6850 for (j = 0; j < po->btj->count; j++) {
6851 check_i(po, po->btj->d[j].bt_i);
6852 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
6853 regmask_save, regmask_dst, regmask_dep, has_ret);
6858 check_i(po, po->bt_i);
6859 if (po->flags & OPF_CJMP) {
6860 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
6861 regmask_save, regmask_dst, regmask_dep, has_ret);
6869 if (po->flags & OPF_FARG)
6870 /* (just calculate register deps) */;
6871 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
6873 reg = po->operand[0].reg;
6874 ferr_assert(po, reg >= 0);
6876 if (po->flags & OPF_RSAVE) {
6877 regmask_save |= 1 << reg;
6880 if (po->flags & OPF_DONE)
6883 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0);
6885 regmask_save |= 1 << reg;
6886 po->flags |= OPF_RMD;
6887 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, OPF_RMD);
6891 else if (po->flags & OPF_RMD)
6893 else if (po->op == OP_CALL) {
6894 po->regmask_dst |= 1 << xAX;
6896 dep = hg_fp_find_dep(fp, po->operand[0].name);
6898 dep->regmask_live = regmask_save | regmask_dst;
6900 else if (po->op == OP_RET) {
6901 if (po->operand_cnt > 0) {
6903 if (fp->argc_stack >= 0
6904 && fp->argc_stack != po->operand[0].val / 4)
6905 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
6906 fp->argc_stack = po->operand[0].val / 4;
6910 // if has_ret is 0, there is uninitialized eax path,
6911 // which means it's most likely void func
6912 if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
6913 if (po->op == OP_CALL) {
6918 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
6921 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
6924 if (ret != 1 && from_caller) {
6925 // unresolved eax - probably void func
6929 if (j >= 0 && ops[j].op == OP_CALL) {
6930 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
6941 l = regmask_save | regmask_dst;
6942 if (g_bp_frame && !(po->flags & OPF_EBP_S))
6945 l = po->regmask_src & ~l;
6948 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
6949 l, regmask_dst, regmask_save, po->flags);
6952 regmask_dst |= po->regmask_dst;
6954 if (po->flags & OPF_TAIL)
6959 static void gen_hdr(const char *funcn, int opcnt)
6961 int save_arg_vars[MAX_ARG_GRP] = { 0, };
6962 unsigned char cbits[MAX_OPS / 8];
6963 const struct parsed_proto *pp_c;
6964 struct parsed_proto *pp;
6965 struct func_prototype *fp;
6966 struct parsed_op *po;
6967 int regmask_dummy = 0;
6969 int max_bp_offset = 0;
6974 pp_c = proto_parse(g_fhdr, funcn, 1);
6976 // already in seed, will add to hg_fp later
6979 fp = hg_fp_add(funcn);
6981 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
6982 g_stack_frame_used = 0;
6985 // - resolve all branches
6986 // - parse calls with labels
6987 resolve_branches_parse_calls(opcnt);
6990 // - handle ebp/esp frame, remove ops related to it
6991 scan_prologue_epilogue(opcnt);
6994 // - remove dead labels
6996 for (i = 0; i < opcnt; i++)
6998 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7004 if (po->flags & (OPF_RMD|OPF_DONE))
7007 if (po->op == OP_CALL) {
7008 if (po->operand[0].type == OPT_LABEL)
7009 hg_fp_add_dep(fp, opr_name(po, 0));
7010 else if (po->pp != NULL)
7011 hg_fp_add_dep(fp, po->pp->name);
7016 // - remove dead labels
7017 // - handle push <const>/pop pairs
7018 for (i = 0; i < opcnt; i++)
7020 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7026 if (po->flags & (OPF_RMD|OPF_DONE))
7029 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
7030 scan_for_pop_const(i, opcnt, i + opcnt * 13);
7034 // - process trivial calls
7035 for (i = 0; i < opcnt; i++)
7038 if (po->flags & (OPF_RMD|OPF_DONE))
7041 if (po->op == OP_CALL)
7043 pp = process_call_early(i, opcnt, &j);
7045 if (!(po->flags & OPF_ATAIL))
7046 // since we know the args, try to collect them
7047 if (collect_call_args_early(po, i, pp, ®mask_dummy) != 0)
7053 // commit esp adjust
7054 if (ops[j].op != OP_POP)
7055 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
7057 for (l = 0; l < pp->argc_stack; l++)
7058 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
7062 po->flags |= OPF_DONE;
7068 // - track saved regs (simple)
7070 for (i = 0; i < opcnt; i++)
7073 if (po->flags & (OPF_RMD|OPF_DONE))
7076 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
7077 && po->operand[0].reg != xCX)
7079 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
7081 // regmask_save |= 1 << po->operand[0].reg; // do it later
7082 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
7083 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
7086 else if (po->op == OP_CALL)
7088 pp = process_call(i, opcnt);
7090 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
7091 // since we know the args, collect them
7092 ret = collect_call_args(po, i, pp, ®mask_dummy, save_arg_vars,
7099 memset(cbits, 0, sizeof(cbits));
7103 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, ®mask_dep, &has_ret);
7105 // find unreachable code - must be fixed in IDA
7106 for (i = 0; i < opcnt; i++)
7108 if (cbits[i >> 3] & (1 << (i & 7)))
7111 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
7112 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
7114 // the compiler sometimes still generates code after
7115 // noreturn OS functions
7118 if (ops[i].op != OP_NOP)
7119 ferr(&ops[i], "unreachable code\n");
7122 for (i = 0; i < g_eqcnt; i++) {
7123 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
7124 max_bp_offset = g_eqs[i].offset;
7127 if (fp->argc_stack < 0) {
7128 max_bp_offset = (max_bp_offset + 3) & ~3;
7129 fp->argc_stack = max_bp_offset / 4;
7130 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
7134 fp->regmask_dep = regmask_dep & ~(1 << xSP);
7135 fp->has_ret = has_ret;
7137 printf("// has_ret %d, regmask_dep %x\n",
7138 fp->has_ret, fp->regmask_dep);
7139 output_hdr_fp(stdout, fp, 1);
7140 if (IS(funcn, "sub_10007F72")) exit(1);
7143 gen_x_cleanup(opcnt);
7146 static void hg_fp_resolve_deps(struct func_prototype *fp)
7148 struct func_prototype fp_s;
7152 // this thing is recursive, so mark first..
7153 fp->dep_resolved = 1;
7155 for (i = 0; i < fp->dep_func_cnt; i++) {
7156 strcpy(fp_s.name, fp->dep_func[i].name);
7157 fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
7158 sizeof(hg_fp[0]), hg_fp_cmp_name);
7159 if (fp->dep_func[i].proto != NULL) {
7160 if (!fp->dep_func[i].proto->dep_resolved)
7161 hg_fp_resolve_deps(fp->dep_func[i].proto);
7163 dep = ~fp->dep_func[i].regmask_live
7164 & fp->dep_func[i].proto->regmask_dep;
7165 fp->regmask_dep |= dep;
7166 // printf("dep %s %s |= %x\n", fp->name,
7167 // fp->dep_func[i].name, dep);
7169 if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
7170 fp->has_ret = fp->dep_func[i].proto->has_ret;
7175 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7178 const struct parsed_proto *pp;
7179 char *p, namebuf[NAMELEN];
7185 for (; count > 0; count--, fp++) {
7186 if (fp->has_ret == -1)
7187 fprintf(fout, "// ret unresolved\n");
7189 fprintf(fout, "// dep:");
7190 for (j = 0; j < fp->dep_func_cnt; j++) {
7191 fprintf(fout, " %s/", fp->dep_func[j].name);
7192 if (fp->dep_func[j].proto != NULL)
7193 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
7194 fp->dep_func[j].proto->has_ret);
7196 fprintf(fout, "\n");
7199 p = strchr(fp->name, '@');
7201 memcpy(namebuf, fp->name, p - fp->name);
7202 namebuf[p - fp->name] = 0;
7210 pp = proto_parse(g_fhdr, name, 1);
7211 if (pp != NULL && pp->is_include)
7214 if (fp->pp != NULL) {
7215 // part of seed, output later
7219 regmask_dep = fp->regmask_dep;
7220 argc_stack = fp->argc_stack;
7222 fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
7223 (fp->has_ret ? "int" : "void"));
7224 if (regmask_dep && (fp->is_stdcall || argc_stack == 0)
7225 && (regmask_dep & ~((1 << xCX) | (1 << xDX))) == 0)
7227 fprintf(fout, " __fastcall ");
7228 if (!(regmask_dep & (1 << xDX)) && argc_stack == 0)
7234 else if (regmask_dep && !fp->is_stdcall) {
7235 fprintf(fout, "/*__usercall*/ ");
7237 else if (regmask_dep) {
7238 fprintf(fout, "/*__userpurge*/ ");
7240 else if (fp->is_stdcall)
7241 fprintf(fout, " __stdcall ");
7243 fprintf(fout, " __cdecl ");
7245 fprintf(fout, "%s(", name);
7248 for (j = 0; j < xSP; j++) {
7249 if (regmask_dep & (1 << j)) {
7252 fprintf(fout, ", ");
7254 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
7256 fprintf(fout, "int");
7257 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
7261 for (j = 0; j < argc_stack; j++) {
7264 fprintf(fout, ", ");
7265 if (fp->pp != NULL) {
7266 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
7267 if (!fp->pp->arg[arg - 1].type.is_ptr)
7271 fprintf(fout, "int ");
7272 fprintf(fout, "a%d", arg);
7275 fprintf(fout, ");\n");
7279 static void output_hdr(FILE *fout)
7281 static const char *lmod_c_names[] = {
7282 [OPLM_UNSPEC] = "???",
7283 [OPLM_BYTE] = "uint8_t",
7284 [OPLM_WORD] = "uint16_t",
7285 [OPLM_DWORD] = "uint32_t",
7286 [OPLM_QWORD] = "uint64_t",
7288 const struct scanned_var *var;
7289 struct func_prototype *fp;
7290 char line[256] = { 0, };
7294 // add stuff from headers
7295 for (i = 0; i < pp_cache_size; i++) {
7296 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
7297 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
7299 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
7300 fp = hg_fp_add(name);
7301 fp->pp = &pp_cache[i];
7302 fp->argc_stack = fp->pp->argc_stack;
7303 fp->is_stdcall = fp->pp->is_stdcall;
7304 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
7305 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
7309 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
7310 for (i = 0; i < hg_fp_cnt; i++)
7311 hg_fp_resolve_deps(&hg_fp[i]);
7313 // note: messes up .proto ptr, don't use
7314 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
7317 for (i = 0; i < hg_var_cnt; i++) {
7320 if (var->pp != NULL)
7323 else if (var->is_c_str)
7324 fprintf(fout, "extern %-8s %s[];", "char", var->name);
7326 fprintf(fout, "extern %-8s %s;",
7327 lmod_c_names[var->lmod], var->name);
7330 fprintf(fout, " // seeded");
7331 fprintf(fout, "\n");
7334 fprintf(fout, "\n");
7336 // output function prototypes
7337 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
7340 fprintf(fout, "\n// - seed -\n");
7343 while (fgets(line, sizeof(line), g_fhdr))
7344 fwrite(line, 1, strlen(line), fout);
7347 // '=' needs special treatment
7349 static char *next_word_s(char *w, size_t wsize, char *s)
7358 for (i = 1; i < wsize - 1; i++) {
7360 printf("warning: missing closing quote: \"%s\"\n", s);
7369 for (; i < wsize - 1; i++) {
7370 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
7376 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
7377 printf("warning: '%s' truncated\n", w);
7382 static void scan_variables(FILE *fasm)
7384 struct scanned_var *var;
7385 char line[256] = { 0, };
7393 // skip to next data section
7394 while (my_fgets(line, sizeof(line), fasm))
7399 if (*p == 0 || *p == ';')
7402 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
7403 if (*p == 0 || *p == ';')
7406 if (*p != 's' || !IS_START(p, "segment para public"))
7412 if (p == NULL || !IS_START(p, "segment para public"))
7416 if (!IS_START(p, "'DATA'"))
7420 while (my_fgets(line, sizeof(line), fasm))
7429 if (*p == 0 || *p == ';')
7432 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
7433 words[wordc][0] = 0;
7434 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
7435 if (*p == 0 || *p == ';') {
7441 if (wordc == 2 && IS(words[1], "ends"))
7446 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
7447 // when this starts, we don't need anything from this section
7451 if ((hg_var_cnt & 0xff) == 0) {
7452 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
7453 * (hg_var_cnt + 0x100));
7454 my_assert_not(hg_vars, NULL);
7455 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
7458 var = &hg_vars[hg_var_cnt++];
7459 snprintf(var->name, sizeof(var->name), "%s", words[0]);
7461 // maybe already in seed header?
7462 var->pp = proto_parse(g_fhdr, var->name, 1);
7463 if (var->pp != NULL) {
7464 if (var->pp->is_fptr) {
7465 var->lmod = OPLM_DWORD;
7468 else if (var->pp->is_func)
7470 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
7471 aerr("unhandled C type '%s' for '%s'\n",
7472 var->pp->type.name, var->name);
7478 if (IS(words[1], "dd"))
7479 var->lmod = OPLM_DWORD;
7480 else if (IS(words[1], "dw"))
7481 var->lmod = OPLM_WORD;
7482 else if (IS(words[1], "db")) {
7483 var->lmod = OPLM_BYTE;
7484 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
7485 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
7489 else if (IS(words[1], "dq"))
7490 var->lmod = OPLM_QWORD;
7491 //else if (IS(words[1], "dt"))
7493 aerr("type '%s' not known\n", words[1]);
7501 static void set_label(int i, const char *name)
7507 p = strchr(name, ':');
7511 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
7512 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
7513 g_labels[i] = realloc(g_labels[i], len + 1);
7514 my_assert_not(g_labels[i], NULL);
7515 memcpy(g_labels[i], name, len);
7516 g_labels[i][len] = 0;
7525 static struct chunk_item *func_chunks;
7526 static int func_chunk_cnt;
7527 static int func_chunk_alloc;
7529 static void add_func_chunk(FILE *fasm, const char *name, int line)
7531 if (func_chunk_cnt >= func_chunk_alloc) {
7532 func_chunk_alloc *= 2;
7533 func_chunks = realloc(func_chunks,
7534 func_chunk_alloc * sizeof(func_chunks[0]));
7535 my_assert_not(func_chunks, NULL);
7537 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
7538 func_chunks[func_chunk_cnt].name = strdup(name);
7539 func_chunks[func_chunk_cnt].asmln = line;
7543 static int cmp_chunks(const void *p1, const void *p2)
7545 const struct chunk_item *c1 = p1, *c2 = p2;
7546 return strcmp(c1->name, c2->name);
7549 static int cmpstringp(const void *p1, const void *p2)
7551 return strcmp(*(char * const *)p1, *(char * const *)p2);
7554 static void scan_ahead(FILE *fasm)
7564 oldpos = ftell(fasm);
7567 while (my_fgets(line, sizeof(line), fasm))
7578 // get rid of random tabs
7579 for (i = 0; line[i] != 0; i++)
7580 if (line[i] == '\t')
7583 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
7586 next_word(words[0], sizeof(words[0]), p);
7587 if (words[0][0] == 0)
7588 aerr("missing name for func chunk?\n");
7590 add_func_chunk(fasm, words[0], asmln);
7592 else if (IS_START(p, "; sctend"))
7598 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
7599 words[wordc][0] = 0;
7600 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
7601 if (*p == 0 || *p == ';') {
7607 if (wordc == 2 && IS(words[1], "ends"))
7611 fseek(fasm, oldpos, SEEK_SET);
7615 int main(int argc, char *argv[])
7617 FILE *fout, *fasm, *frlist;
7618 struct parsed_data *pd = NULL;
7620 char **rlist = NULL;
7622 int rlist_alloc = 0;
7623 int func_chunks_used = 0;
7624 int func_chunks_sorted = 0;
7625 int func_chunk_i = -1;
7626 long func_chunk_ret = 0;
7627 int func_chunk_ret_ln = 0;
7628 int scanned_ahead = 0;
7630 char words[20][256];
7631 enum opr_lenmod lmod;
7632 char *sctproto = NULL;
7634 int pending_endp = 0;
7636 int skip_warned = 0;
7649 for (arg = 1; arg < argc; arg++) {
7650 if (IS(argv[arg], "-v"))
7652 else if (IS(argv[arg], "-rf"))
7653 g_allow_regfunc = 1;
7654 else if (IS(argv[arg], "-m"))
7656 else if (IS(argv[arg], "-hdr"))
7657 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
7662 if (argc < arg + 3) {
7663 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
7664 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
7666 " -hdr - header generation mode\n"
7667 " -rf - allow unannotated indirect calls\n"
7668 " -m - allow multiple .text sections\n"
7669 "[rlist] is a file with function names to skip,"
7677 asmfn = argv[arg++];
7678 fasm = fopen(asmfn, "r");
7679 my_assert_not(fasm, NULL);
7681 hdrfn = argv[arg++];
7682 g_fhdr = fopen(hdrfn, "r");
7683 my_assert_not(g_fhdr, NULL);
7686 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
7687 my_assert_not(rlist, NULL);
7688 // needs special handling..
7689 rlist[rlist_len++] = "__alloca_probe";
7691 func_chunk_alloc = 32;
7692 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
7693 my_assert_not(func_chunks, NULL);
7695 memset(words, 0, sizeof(words));
7697 for (; arg < argc; arg++) {
7698 frlist = fopen(argv[arg], "r");
7699 my_assert_not(frlist, NULL);
7701 while (my_fgets(line, sizeof(line), frlist)) {
7703 if (*p == 0 || *p == ';')
7706 if (IS_START(p, "#if 0")
7707 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
7711 else if (IS_START(p, "#endif"))
7718 p = next_word(words[0], sizeof(words[0]), p);
7719 if (words[0][0] == 0)
7722 if (rlist_len >= rlist_alloc) {
7723 rlist_alloc = rlist_alloc * 2 + 64;
7724 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
7725 my_assert_not(rlist, NULL);
7727 rlist[rlist_len++] = strdup(words[0]);
7736 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
7738 fout = fopen(argv[arg_out], "w");
7739 my_assert_not(fout, NULL);
7742 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
7743 my_assert_not(g_eqs, NULL);
7745 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
7746 g_label_refs[i].i = -1;
7747 g_label_refs[i].next = NULL;
7751 scan_variables(fasm);
7753 while (my_fgets(line, sizeof(line), fasm))
7762 // get rid of random tabs
7763 for (i = 0; line[i] != 0; i++)
7764 if (line[i] == '\t')
7769 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
7770 goto do_pending_endp; // eww..
7772 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
7774 static const char *attrs[] = {
7783 // parse IDA's attribute-list comment
7784 g_ida_func_attr = 0;
7787 for (; *p != 0; p = sskip(p)) {
7788 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
7789 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
7790 g_ida_func_attr |= 1 << i;
7791 p += strlen(attrs[i]);
7795 if (i == ARRAY_SIZE(attrs)) {
7796 anote("unparsed IDA attr: %s\n", p);
7799 if (IS(attrs[i], "fpd=")) {
7800 p = next_word(words[0], sizeof(words[0]), p);
7805 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
7808 next_word(words[0], sizeof(words[0]), p);
7809 if (words[0][0] == 0)
7810 aerr("missing name for func chunk?\n");
7812 if (!scanned_ahead) {
7813 add_func_chunk(fasm, words[0], asmln);
7814 func_chunks_sorted = 0;
7817 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
7819 if (func_chunk_i >= 0) {
7820 if (func_chunk_i < func_chunk_cnt
7821 && IS(func_chunks[func_chunk_i].name, g_func))
7823 // move on to next chunk
7824 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
7826 aerr("seek failed for '%s' chunk #%d\n",
7827 g_func, func_chunk_i);
7828 asmln = func_chunks[func_chunk_i].asmln;
7832 if (func_chunk_ret == 0)
7833 aerr("no return from chunk?\n");
7834 fseek(fasm, func_chunk_ret, SEEK_SET);
7835 asmln = func_chunk_ret_ln;
7841 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
7842 func_chunks_used = 1;
7844 if (IS_START(g_func, "sub_")) {
7845 unsigned long addr = strtoul(p, NULL, 16);
7846 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
7847 if (addr > f_addr && !scanned_ahead) {
7848 //anote("scan_ahead caused by '%s', addr %lx\n",
7852 func_chunks_sorted = 0;
7860 for (i = wordc; i < ARRAY_SIZE(words); i++)
7862 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
7863 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
7864 if (*p == 0 || *p == ';') {
7869 if (*p != 0 && *p != ';')
7870 aerr("too many words\n");
7872 // alow asm patches in comments
7874 if (IS_START(p, "; sctpatch:")) {
7876 if (*p == 0 || *p == ';')
7878 goto parse_words; // lame
7880 if (IS_START(p, "; sctproto:")) {
7881 sctproto = strdup(p + 11);
7883 else if (IS_START(p, "; sctend")) {
7892 awarn("wordc == 0?\n");
7896 // don't care about this:
7897 if (words[0][0] == '.'
7898 || IS(words[0], "include")
7899 || IS(words[0], "assume") || IS(words[1], "segment")
7900 || IS(words[0], "align"))
7906 // do delayed endp processing to collect switch jumptables
7908 if (in_func && !g_skip_func && !end && wordc >= 2
7909 && ((words[0][0] == 'd' && words[0][2] == 0)
7910 || (words[1][0] == 'd' && words[1][2] == 0)))
7913 if (words[1][0] == 'd' && words[1][2] == 0) {
7915 if (g_func_pd_cnt >= pd_alloc) {
7916 pd_alloc = pd_alloc * 2 + 16;
7917 g_func_pd = realloc(g_func_pd,
7918 sizeof(g_func_pd[0]) * pd_alloc);
7919 my_assert_not(g_func_pd, NULL);
7921 pd = &g_func_pd[g_func_pd_cnt];
7923 memset(pd, 0, sizeof(*pd));
7924 strcpy(pd->label, words[0]);
7925 pd->type = OPT_CONST;
7926 pd->lmod = lmod_from_directive(words[1]);
7932 anote("skipping alignment byte?\n");
7935 lmod = lmod_from_directive(words[0]);
7936 if (lmod != pd->lmod)
7937 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
7940 if (pd->count_alloc < pd->count + wordc) {
7941 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
7942 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
7943 my_assert_not(pd->d, NULL);
7945 for (; i < wordc; i++) {
7946 if (IS(words[i], "offset")) {
7947 pd->type = OPT_OFFSET;
7950 p = strchr(words[i], ',');
7953 if (pd->type == OPT_OFFSET)
7954 pd->d[pd->count].u.label = strdup(words[i]);
7956 pd->d[pd->count].u.val = parse_number(words[i]);
7957 pd->d[pd->count].bt_i = -1;
7963 if (in_func && !g_skip_func) {
7965 gen_hdr(g_func, pi);
7967 gen_func(fout, g_fhdr, g_func, pi);
7972 g_ida_func_attr = 0;
7976 func_chunks_used = 0;
7979 memset(&ops, 0, pi * sizeof(ops[0]));
7984 for (i = 0; i < g_func_pd_cnt; i++) {
7986 if (pd->type == OPT_OFFSET) {
7987 for (j = 0; j < pd->count; j++)
7988 free(pd->d[j].u.label);
8003 if (IS(words[1], "proc")) {
8005 aerr("proc '%s' while in_func '%s'?\n",
8008 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8010 strcpy(g_func, words[0]);
8011 set_label(0, words[0]);
8016 if (IS(words[1], "endp"))
8019 aerr("endp '%s' while not in_func?\n", words[0]);
8020 if (!IS(g_func, words[0]))
8021 aerr("endp '%s' while in_func '%s'?\n",
8024 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
8025 && ops[0].op == OP_JMP && ops[0].operand[0].had_ds)
8031 if (!g_skip_func && func_chunks_used) {
8032 // start processing chunks
8033 struct chunk_item *ci, key = { g_func, 0 };
8035 func_chunk_ret = ftell(fasm);
8036 func_chunk_ret_ln = asmln;
8037 if (!func_chunks_sorted) {
8038 qsort(func_chunks, func_chunk_cnt,
8039 sizeof(func_chunks[0]), cmp_chunks);
8040 func_chunks_sorted = 1;
8042 ci = bsearch(&key, func_chunks, func_chunk_cnt,
8043 sizeof(func_chunks[0]), cmp_chunks);
8045 aerr("'%s' needs chunks, but none found\n", g_func);
8046 func_chunk_i = ci - func_chunks;
8047 for (; func_chunk_i > 0; func_chunk_i--)
8048 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
8051 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
8053 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
8054 asmln = func_chunks[func_chunk_i].asmln;
8062 if (wordc == 2 && IS(words[1], "ends")) {
8066 goto do_pending_endp;
8070 // scan for next text segment
8071 while (my_fgets(line, sizeof(line), fasm)) {
8074 if (*p == 0 || *p == ';')
8077 if (strstr(p, "segment para public 'CODE' use32"))
8084 p = strchr(words[0], ':');
8086 set_label(pi, words[0]);
8090 if (!in_func || g_skip_func) {
8091 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
8093 anote("skipping from '%s'\n", g_labels[pi]);
8097 g_labels[pi] = NULL;
8101 if (wordc > 1 && IS(words[1], "="))
8104 aerr("unhandled equ, wc=%d\n", wordc);
8105 if (g_eqcnt >= eq_alloc) {
8107 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
8108 my_assert_not(g_eqs, NULL);
8111 len = strlen(words[0]);
8112 if (len > sizeof(g_eqs[0].name) - 1)
8113 aerr("equ name too long: %d\n", len);
8114 strcpy(g_eqs[g_eqcnt].name, words[0]);
8116 if (!IS(words[3], "ptr"))
8117 aerr("unhandled equ\n");
8118 if (IS(words[2], "dword"))
8119 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
8120 else if (IS(words[2], "word"))
8121 g_eqs[g_eqcnt].lmod = OPLM_WORD;
8122 else if (IS(words[2], "byte"))
8123 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
8124 else if (IS(words[2], "qword"))
8125 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
8127 aerr("bad lmod: '%s'\n", words[2]);
8129 g_eqs[g_eqcnt].offset = parse_number(words[4]);
8134 if (pi >= ARRAY_SIZE(ops))
8135 aerr("too many ops\n");
8137 parse_op(&ops[pi], words, wordc);
8139 ops[pi].datap = sctproto;
8154 // vim:ts=2:shiftwidth=2:expandtab