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 */
155 // pseudo-ops for lib calls
172 // must be sorted (larger len must be further in enum)
181 #define MAX_EXITS 128
183 #define MAX_OPERANDS 3
186 #define OPR_INIT(type_, lmod_, reg_) \
187 { type_, lmod_, reg_, }
191 enum opr_lenmod lmod;
193 unsigned int is_ptr:1; // pointer in C
194 unsigned int is_array:1; // array in C
195 unsigned int type_from_var:1; // .. in header, sometimes wrong
196 unsigned int size_mismatch:1; // type override differs from C
197 unsigned int size_lt:1; // type override is larger than C
198 unsigned int had_ds:1; // had ds: prefix
199 const struct parsed_proto *pp; // for OPT_LABEL
206 struct parsed_opr operand[MAX_OPERANDS];
209 unsigned char pfo_inv;
210 unsigned char operand_cnt;
211 unsigned char p_argnum; // arg push: altered before call arg #
212 unsigned char p_arggrp; // arg push: arg group # for above
213 unsigned char p_argpass;// arg push: arg of host func
214 short p_argnext;// arg push: same arg pushed elsewhere or -1
215 int regmask_src; // all referensed regs
217 int pfomask; // flagop: parsed_flag_op that can't be delayed
218 int cc_scratch; // scratch storage during analysis
219 int bt_i; // branch target for branches
220 struct parsed_data *btj;// branch targets for jumptables
221 struct parsed_proto *pp;// parsed_proto for OP_CALL
227 // on start: function/data type hint (sctproto)
229 // (OPF_CC) - points to one of (OPF_FLAGS) that affects cc op
230 // OP_PUSH - points to OP_POP in complex push/pop graph
231 // OP_POP - points to OP_PUSH in simple push/pop pair
232 // OP_FCOM - needed_status_word_bits | (is_z_check << 16)
236 enum opr_lenmod lmod;
243 enum opr_lenmod lmod;
257 struct label_ref *next;
261 IDAFA_BP_FRAME = (1 << 0),
262 IDAFA_LIB_FUNC = (1 << 1),
263 IDAFA_STATIC = (1 << 2),
264 IDAFA_NORETURN = (1 << 3),
265 IDAFA_THUNK = (1 << 4),
266 IDAFA_FPD = (1 << 5),
270 SCTFA_CLEAR_SF = (1 << 0), // clear stack frame
271 SCTFA_CLEAR_REGS = (1 << 1), // clear registers (mask)
284 // note: limited to 32k due to p_argnext
286 #define MAX_ARG_GRP 2
288 static struct parsed_op ops[MAX_OPS];
289 static struct parsed_equ *g_eqs;
291 static char *g_labels[MAX_OPS];
292 static struct label_ref g_label_refs[MAX_OPS];
293 static const struct parsed_proto *g_func_pp;
294 static struct parsed_data *g_func_pd;
295 static int g_func_pd_cnt;
296 static int g_func_lmods;
297 static char g_func[256];
298 static char g_comment[256];
299 static int g_bp_frame;
300 static int g_sp_frame;
301 static int g_stack_frame_used;
302 static int g_stack_fsz;
303 static int g_ida_func_attr;
304 static int g_sct_func_attr;
305 static int g_stack_clear_start; // in dwords
306 static int g_stack_clear_len;
307 static int g_regmask_init;
308 static int g_skip_func;
309 static int g_allow_regfunc;
310 static int g_quiet_pp;
311 static int g_header_mode;
313 #define ferr(op_, fmt, ...) do { \
314 printf("%s:%d: error %u: [%s] '%s': " fmt, asmfn, (op_)->asmln, \
315 __LINE__, g_func, dump_op(op_), ##__VA_ARGS__); \
319 #define fnote(op_, fmt, ...) \
320 printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
321 dump_op(op_), ##__VA_ARGS__)
323 #define ferr_assert(op_, cond) do { \
324 if (!(cond)) ferr(op_, "assertion '%s' failed\n", #cond); \
327 const char *regs_r32[] = {
328 "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
329 // not r32, but list here for easy parsing and printing
330 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
331 "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"
333 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
334 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
335 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
341 xMM0, xMM1, xMM2, xMM3, // mmx
342 xMM4, xMM5, xMM6, xMM7,
343 xST0, xST1, xST2, xST3, // x87
344 xST4, xST5, xST6, xST7,
347 #define mxAX (1 << xAX)
348 #define mxCX (1 << xCX)
349 #define mxDX (1 << xDX)
350 #define mxST0 (1 << xST0)
351 #define mxST1 (1 << xST1)
352 #define mxST1_0 (mxST1 | mxST0)
353 #define mxST7_2 (0xfc << xST0)
354 #define mxSTa (0xff << xST0)
356 // possible basic comparison types (without inversion)
357 enum parsed_flag_op {
361 PFO_BE, // 6 CF=1||ZF=1
365 PFO_LE, // e ZF=1||SF!=OF
368 #define PFOB_O (1 << PFO_O)
369 #define PFOB_C (1 << PFO_C)
370 #define PFOB_Z (1 << PFO_Z)
371 #define PFOB_S (1 << PFO_S)
373 static const char *parsed_flag_op_names[] = {
374 "o", "c", "z", "be", "s", "p", "l", "le"
377 static int char_array_i(const char *array[], size_t len, const char *s)
381 for (i = 0; i < len; i++)
388 static void printf_number(char *buf, size_t buf_size,
389 unsigned long number)
391 // output in C-friendly form
392 snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
395 static int check_segment_prefix(const char *s)
397 if (s[0] == 0 || s[1] != 's' || s[2] != ':')
411 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
415 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
417 *reg_lmod = OPLM_QWORD;
421 *reg_lmod = OPLM_DWORD;
424 reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
426 *reg_lmod = OPLM_WORD;
429 reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
431 *reg_lmod = OPLM_BYTE;
434 reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
436 *reg_lmod = OPLM_BYTE;
443 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
445 enum opr_lenmod lmod;
458 while (my_isblank(*s))
460 for (; my_issep(*s); d++, s++)
462 while (my_isblank(*s))
466 // skip '?s:' prefixes
467 if (check_segment_prefix(s))
470 s = next_idt(w, sizeof(w), s);
475 reg = parse_reg(&lmod, w);
477 *regmask |= 1 << reg;
481 if ('0' <= w[0] && w[0] <= '9') {
482 number = parse_number(w);
483 printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
487 // probably some label/identifier - pass
490 snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
494 strcpy(name, cvtbuf);
499 static int is_reg_in_str(const char *s)
503 if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
506 for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
507 if (!strncmp(s, regs_r32[i], 3))
513 static const char *parse_stack_el(const char *name, char *extra_reg,
514 int *base_val, int early_try)
516 const char *p, *p2, *s;
522 if (g_bp_frame || early_try)
525 if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
527 if (extra_reg != NULL) {
528 strncpy(extra_reg, name, 3);
533 if (IS_START(p, "ebp+")) {
537 if (p2 != NULL && is_reg_in_str(p)) {
538 if (extra_reg != NULL) {
539 strncpy(extra_reg, p, p2 - p);
540 extra_reg[p2 - p] = 0;
545 if (!('0' <= *p && *p <= '9'))
552 if (!IS_START(name, "esp+"))
558 if (is_reg_in_str(s)) {
559 if (extra_reg != NULL) {
560 strncpy(extra_reg, s, p - s);
561 extra_reg[p - s] = 0;
566 aerr("%s IDA stackvar not set?\n", __func__);
568 if (!('0' <= *s && *s <= '9')) {
569 aerr("%s IDA stackvar offset not set?\n", __func__);
572 if (s[0] == '0' && s[1] == 'x')
575 if (len < sizeof(buf) - 1) {
576 strncpy(buf, s, len);
578 val = strtol(buf, &endp, 16);
579 if (val == 0 || *endp != 0) {
580 aerr("%s num parse fail for '%s'\n", __func__, buf);
589 if ('0' <= *p && *p <= '9')
592 if (base_val != NULL)
597 static int guess_lmod_from_name(struct parsed_opr *opr)
599 if (IS_START(opr->name, "dword_") || IS_START(opr->name, "off_")) {
600 opr->lmod = OPLM_DWORD;
603 if (IS_START(opr->name, "word_")) {
604 opr->lmod = OPLM_WORD;
607 if (IS_START(opr->name, "byte_")) {
608 opr->lmod = OPLM_BYTE;
611 if (IS_START(opr->name, "qword_")) {
612 opr->lmod = OPLM_QWORD;
618 static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
619 const struct parsed_type *c_type)
621 static const char *dword_types[] = {
622 "uint32_t", "int", "_DWORD", "UINT_PTR", "DWORD",
623 "WPARAM", "LPARAM", "UINT", "__int32",
624 "LONG", "HIMC", "BOOL", "size_t",
627 static const char *word_types[] = {
628 "uint16_t", "int16_t", "_WORD", "WORD",
629 "unsigned __int16", "__int16",
631 static const char *byte_types[] = {
632 "uint8_t", "int8_t", "char",
633 "unsigned __int8", "__int8", "BYTE", "_BYTE",
635 // structures.. deal the same as with _UNKNOWN for now
641 if (c_type->is_ptr) {
646 n = skip_type_mod(c_type->name);
648 for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
649 if (IS(n, dword_types[i])) {
655 for (i = 0; i < ARRAY_SIZE(word_types); i++) {
656 if (IS(n, word_types[i])) {
662 for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
663 if (IS(n, byte_types[i])) {
672 static char *default_cast_to(char *buf, size_t buf_size,
673 struct parsed_opr *opr)
677 if (!opr->is_ptr || strchr(opr->name, '['))
679 if (opr->pp == NULL || opr->pp->type.name == NULL
682 snprintf(buf, buf_size, "%s", "(void *)");
686 snprintf(buf, buf_size, "(%s)", opr->pp->type.name);
690 static enum opr_type lmod_from_directive(const char *d)
694 else if (IS(d, "dw"))
696 else if (IS(d, "db"))
699 aerr("unhandled directive: '%s'\n", d);
703 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
709 *regmask |= 1 << reg;
712 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
715 static int parse_operand(struct parsed_opr *opr,
716 int *regmask, int *regmask_indirect,
717 char words[16][256], int wordc, int w, unsigned int op_flags)
719 const struct parsed_proto *pp = NULL;
720 enum opr_lenmod tmplmod;
721 unsigned long number;
729 aerr("parse_operand w %d, wordc %d\n", w, wordc);
733 for (i = w; i < wordc; i++) {
734 len = strlen(words[i]);
735 if (words[i][len - 1] == ',') {
736 words[i][len - 1] = 0;
742 wordc_in = wordc - w;
744 if ((op_flags & OPF_JMP) && wordc_in > 0
745 && !('0' <= words[w][0] && words[w][0] <= '9'))
747 const char *label = NULL;
749 if (wordc_in == 3 && !strncmp(words[w], "near", 4)
750 && IS(words[w + 1], "ptr"))
751 label = words[w + 2];
752 else if (wordc_in == 2 && IS(words[w], "short"))
753 label = words[w + 1];
754 else if (wordc_in == 1
755 && strchr(words[w], '[') == NULL
756 && parse_reg(&tmplmod, words[w]) < 0)
760 opr->type = OPT_LABEL;
761 ret = check_segment_prefix(label);
764 aerr("fs/gs used\n");
768 strcpy(opr->name, label);
774 if (IS(words[w + 1], "ptr")) {
775 if (IS(words[w], "dword"))
776 opr->lmod = OPLM_DWORD;
777 else if (IS(words[w], "word"))
778 opr->lmod = OPLM_WORD;
779 else if (IS(words[w], "byte"))
780 opr->lmod = OPLM_BYTE;
781 else if (IS(words[w], "qword"))
782 opr->lmod = OPLM_QWORD;
784 aerr("type parsing failed\n");
786 wordc_in = wordc - w;
791 if (IS(words[w], "offset")) {
792 opr->type = OPT_OFFSET;
793 opr->lmod = OPLM_DWORD;
794 strcpy(opr->name, words[w + 1]);
795 pp = proto_parse(g_fhdr, opr->name, 1);
798 if (IS(words[w], "(offset")) {
799 p = strchr(words[w + 1], ')');
801 aerr("parse of bracketed offset failed\n");
803 opr->type = OPT_OFFSET;
804 strcpy(opr->name, words[w + 1]);
810 aerr("parse_operand 1 word expected\n");
812 ret = check_segment_prefix(words[w]);
815 aerr("fs/gs used\n");
817 memmove(words[w], words[w] + 3, strlen(words[w]) - 2);
819 strcpy(opr->name, words[w]);
821 if (words[w][0] == '[') {
822 opr->type = OPT_REGMEM;
823 ret = sscanf(words[w], "[%[^]]]", opr->name);
825 aerr("[] parse failure\n");
827 parse_indmode(opr->name, regmask_indirect, 1);
828 if (opr->lmod == OPLM_UNSPEC
829 && parse_stack_el(opr->name, NULL, NULL, 1))
832 struct parsed_equ *eq =
833 equ_find(NULL, parse_stack_el(opr->name, NULL, NULL, 1), &i);
835 opr->lmod = eq->lmod;
837 // might be unaligned access
838 g_func_lmods |= 1 << OPLM_BYTE;
842 else if (strchr(words[w], '[')) {
844 p = strchr(words[w], '[');
845 opr->type = OPT_REGMEM;
846 parse_indmode(p, regmask_indirect, 0);
847 strncpy(buf, words[w], p - words[w]);
848 buf[p - words[w]] = 0;
849 pp = proto_parse(g_fhdr, buf, 1);
852 else if (('0' <= words[w][0] && words[w][0] <= '9')
853 || words[w][0] == '-')
855 number = parse_number(words[w]);
856 opr->type = OPT_CONST;
858 printf_number(opr->name, sizeof(opr->name), number);
862 ret = parse_reg(&tmplmod, opr->name);
864 setup_reg_opr(opr, ret, tmplmod, regmask);
868 // most likely var in data segment
869 opr->type = OPT_LABEL;
870 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
874 if (pp->is_fptr || pp->is_func) {
875 opr->lmod = OPLM_DWORD;
879 tmplmod = OPLM_UNSPEC;
880 if (!guess_lmod_from_c_type(&tmplmod, &pp->type))
881 anote("unhandled C type '%s' for '%s'\n",
882 pp->type.name, opr->name);
884 if (opr->lmod == OPLM_UNSPEC) {
886 opr->type_from_var = 1;
888 else if (opr->lmod != tmplmod) {
889 opr->size_mismatch = 1;
890 if (tmplmod < opr->lmod)
893 opr->is_ptr = pp->type.is_ptr;
895 opr->is_array = pp->type.is_array;
899 if (opr->lmod == OPLM_UNSPEC)
900 guess_lmod_from_name(opr);
904 static const struct {
909 { "repe", OPF_REP|OPF_REPZ },
910 { "repz", OPF_REP|OPF_REPZ },
911 { "repne", OPF_REP|OPF_REPNZ },
912 { "repnz", OPF_REP|OPF_REPNZ },
913 { "lock", OPF_LOCK }, // ignored for now..
916 #define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
918 static const struct {
921 unsigned short minopr;
922 unsigned short maxopr;
925 unsigned char pfo_inv;
927 { "nop", OP_NOP, 0, 0, 0 },
928 { "push", OP_PUSH, 1, 1, 0 },
929 { "pop", OP_POP, 1, 1, OPF_DATA },
930 { "pusha",OP_PUSHA, 0, 0, 0 },
931 { "popa", OP_POPA, 0, 0, OPF_DATA },
932 { "leave",OP_LEAVE, 0, 0, OPF_DATA },
933 { "mov" , OP_MOV, 2, 2, OPF_DATA },
934 { "lea", OP_LEA, 2, 2, OPF_DATA },
935 { "movzx",OP_MOVZX, 2, 2, OPF_DATA },
936 { "movsx",OP_MOVSX, 2, 2, OPF_DATA },
937 { "xchg", OP_XCHG, 2, 2, OPF_DATA },
938 { "not", OP_NOT, 1, 1, OPF_DATA },
939 { "xlat", OP_XLAT, 0, 0, OPF_DATA },
940 { "cdq", OP_CDQ, 0, 0, OPF_DATA },
941 { "bswap",OP_BSWAP, 1, 1, OPF_DATA },
942 { "lodsb",OP_LODS, 0, 0, OPF_DATA },
943 { "lodsw",OP_LODS, 0, 0, OPF_DATA },
944 { "lodsd",OP_LODS, 0, 0, OPF_DATA },
945 { "stosb",OP_STOS, 0, 0, OPF_DATA },
946 { "stosw",OP_STOS, 0, 0, OPF_DATA },
947 { "stosd",OP_STOS, 0, 0, OPF_DATA },
948 { "movsb",OP_MOVS, 0, 0, OPF_DATA },
949 { "movsw",OP_MOVS, 0, 0, OPF_DATA },
950 { "movsd",OP_MOVS, 0, 0, OPF_DATA },
951 { "cmpsb",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
952 { "cmpsw",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
953 { "cmpsd",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
954 { "scasb",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
955 { "scasw",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
956 { "scasd",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
957 { "std", OP_STD, 0, 0, OPF_DATA }, // special flag
958 { "cld", OP_CLD, 0, 0, OPF_DATA },
959 { "add", OP_ADD, 2, 2, OPF_DATA|OPF_FLAGS },
960 { "sub", OP_SUB, 2, 2, OPF_DATA|OPF_FLAGS },
961 { "and", OP_AND, 2, 2, OPF_DATA|OPF_FLAGS },
962 { "or", OP_OR, 2, 2, OPF_DATA|OPF_FLAGS },
963 { "xor", OP_XOR, 2, 2, OPF_DATA|OPF_FLAGS },
964 { "shl", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
965 { "shr", OP_SHR, 2, 2, OPF_DATA|OPF_FLAGS },
966 { "sal", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
967 { "sar", OP_SAR, 2, 2, OPF_DATA|OPF_FLAGS },
968 { "shld", OP_SHLD, 3, 3, OPF_DATA|OPF_FLAGS },
969 { "shrd", OP_SHRD, 3, 3, OPF_DATA|OPF_FLAGS },
970 { "rol", OP_ROL, 2, 2, OPF_DATA|OPF_FLAGS },
971 { "ror", OP_ROR, 2, 2, OPF_DATA|OPF_FLAGS },
972 { "rcl", OP_RCL, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
973 { "rcr", OP_RCR, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
974 { "adc", OP_ADC, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
975 { "sbb", OP_SBB, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
976 { "bsf", OP_BSF, 2, 2, OPF_DATA|OPF_FLAGS },
977 { "inc", OP_INC, 1, 1, OPF_DATA|OPF_FLAGS },
978 { "dec", OP_DEC, 1, 1, OPF_DATA|OPF_FLAGS },
979 { "neg", OP_NEG, 1, 1, OPF_DATA|OPF_FLAGS },
980 { "mul", OP_MUL, 1, 1, OPF_DATA|OPF_FLAGS },
981 { "imul", OP_IMUL, 1, 3, OPF_DATA|OPF_FLAGS },
982 { "div", OP_DIV, 1, 1, OPF_DATA|OPF_FLAGS },
983 { "idiv", OP_IDIV, 1, 1, OPF_DATA|OPF_FLAGS },
984 { "test", OP_TEST, 2, 2, OPF_FLAGS },
985 { "cmp", OP_CMP, 2, 2, OPF_FLAGS },
986 { "retn", OP_RET, 0, 1, OPF_TAIL },
987 { "call", OP_CALL, 1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
988 { "jmp", OP_JMP, 1, 1, OPF_JMP },
989 { "jecxz",OP_JECXZ, 1, 1, OPF_JMP|OPF_CJMP },
990 { "loop", OP_LOOP, 1, 1, OPF_JMP|OPF_CJMP|OPF_DATA },
991 { "jo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 0 }, // 70 OF=1
992 { "jno", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 1 }, // 71 OF=0
993 { "jc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72 CF=1
994 { "jb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72
995 { "jnc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73 CF=0
996 { "jnb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
997 { "jae", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
998 { "jz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74 ZF=1
999 { "je", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74
1000 { "jnz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75 ZF=0
1001 { "jne", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75
1002 { "jbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76 CF=1||ZF=1
1003 { "jna", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76
1004 { "ja", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77 CF=0&&ZF=0
1005 { "jnbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77
1006 { "js", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 0 }, // 78 SF=1
1007 { "jns", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 1 }, // 79 SF=0
1008 { "jp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a PF=1
1009 { "jpe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a
1010 { "jnp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b PF=0
1011 { "jpo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b
1012 { "jl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c SF!=OF
1013 { "jnge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c
1014 { "jge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d SF=OF
1015 { "jnl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d
1016 { "jle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e ZF=1||SF!=OF
1017 { "jng", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e
1018 { "jg", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f ZF=0&&SF=OF
1019 { "jnle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f
1020 { "seto", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 0 },
1021 { "setno", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 1 },
1022 { "setc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1023 { "setb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1024 { "setnc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1025 { "setae", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1026 { "setnb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1027 { "setz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1028 { "sete", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1029 { "setnz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1030 { "setne", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1031 { "setbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1032 { "setna", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1033 { "seta", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1034 { "setnbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1035 { "sets", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 0 },
1036 { "setns", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 1 },
1037 { "setp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1038 { "setpe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1039 { "setnp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1040 { "setpo", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1041 { "setl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1042 { "setnge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1043 { "setge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1044 { "setnl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1045 { "setle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1046 { "setng", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1047 { "setg", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1048 { "setnle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1050 { "fld", OP_FLD, 1, 1, OPF_FPUSH },
1051 { "fild", OP_FILD, 1, 1, OPF_FPUSH },
1052 { "fld1", OP_FLDc, 0, 0, OPF_FPUSH },
1053 { "fldln2", OP_FLDc, 0, 0, OPF_FPUSH },
1054 { "fldz", OP_FLDc, 0, 0, OPF_FPUSH },
1055 { "fst", OP_FST, 1, 1, 0 },
1056 { "fstp", OP_FST, 1, 1, OPF_FPOP },
1057 { "fist", OP_FIST, 1, 1, 0 },
1058 { "fistp", OP_FIST, 1, 1, OPF_FPOP },
1059 { "fadd", OP_FADD, 0, 2, 0 },
1060 { "faddp", OP_FADD, 0, 2, OPF_FPOP },
1061 { "fdiv", OP_FDIV, 0, 2, 0 },
1062 { "fdivp", OP_FDIV, 0, 2, OPF_FPOP },
1063 { "fmul", OP_FMUL, 0, 2, 0 },
1064 { "fmulp", OP_FMUL, 0, 2, OPF_FPOP },
1065 { "fsub", OP_FSUB, 0, 2, 0 },
1066 { "fsubp", OP_FSUB, 0, 2, OPF_FPOP },
1067 { "fdivr", OP_FDIVR, 0, 2, 0 },
1068 { "fdivrp", OP_FDIVR, 0, 2, OPF_FPOP },
1069 { "fsubr", OP_FSUBR, 0, 2, 0 },
1070 { "fsubrp", OP_FSUBR, 0, 2, OPF_FPOP },
1071 { "fiadd", OP_FIADD, 1, 1, 0 },
1072 { "fidiv", OP_FIDIV, 1, 1, 0 },
1073 { "fimul", OP_FIMUL, 1, 1, 0 },
1074 { "fisub", OP_FISUB, 1, 1, 0 },
1075 { "fidivr", OP_FIDIVR, 1, 1, 0 },
1076 { "fisubr", OP_FISUBR, 1, 1, 0 },
1077 { "fcom", OP_FCOM, 0, 1, 0 },
1078 { "fcomp", OP_FCOM, 0, 1, OPF_FPOP },
1079 { "fnstsw", OP_FNSTSW, 1, 1, OPF_DATA },
1080 { "fchs", OP_FCHS, 0, 0, 0 },
1081 { "fcos", OP_FCOS, 0, 0, 0 },
1082 { "fpatan", OP_FPATAN, 0, 0, OPF_FPOP },
1083 { "fptan", OP_FPTAN, 0, 0, OPF_FPUSH },
1084 { "fsin", OP_FSIN, 0, 0, 0 },
1085 { "fsqrt", OP_FSQRT, 0, 0, 0 },
1086 { "fxch", OP_FXCH, 1, 1, 0 },
1087 { "fyl2x", OP_FYL2X, 0, 0, OPF_FPOP },
1089 { "emms", OP_EMMS, 0, 0, OPF_DATA },
1090 { "movq", OP_MOV, 2, 2, OPF_DATA },
1091 // pseudo-ops for lib calls
1092 { "_allshl",OPP_ALLSHL },
1093 { "_allshr",OPP_ALLSHR },
1094 { "_ftol", OPP_FTOL },
1099 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
1101 enum opr_lenmod lmod = OPLM_UNSPEC;
1102 int prefix_flags = 0;
1110 for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
1111 if (IS(words[w], pref_table[i].name)) {
1112 prefix_flags = pref_table[i].flags;
1119 aerr("lone prefix: '%s'\n", words[0]);
1124 for (i = 0; i < ARRAY_SIZE(op_table); i++) {
1125 if (IS(words[w], op_table[i].name))
1129 if (i == ARRAY_SIZE(op_table)) {
1131 aerr("unhandled op: '%s'\n", words[0]);
1136 op->op = op_table[i].op;
1137 op->flags = op_table[i].flags | prefix_flags;
1138 op->pfo = op_table[i].pfo;
1139 op->pfo_inv = op_table[i].pfo_inv;
1140 op->regmask_src = op->regmask_dst = 0;
1143 if (op->op == OP_UD2)
1146 for (opr = 0; opr < op_table[i].maxopr; opr++) {
1147 if (opr >= op_table[i].minopr && w >= wordc)
1150 regmask = regmask_ind = 0;
1151 w = parse_operand(&op->operand[opr], ®mask, ®mask_ind,
1152 words, wordc, w, op->flags);
1154 if (opr == 0 && (op->flags & OPF_DATA))
1155 op->regmask_dst = regmask;
1157 op->regmask_src |= regmask;
1158 op->regmask_src |= regmask_ind;
1160 if (op->operand[opr].lmod != OPLM_UNSPEC)
1161 g_func_lmods |= 1 << op->operand[opr].lmod;
1165 aerr("parse_op %s incomplete: %d/%d\n",
1166 words[0], w, wordc);
1169 op->operand_cnt = opr;
1170 if (!strncmp(op_table[i].name, "set", 3))
1171 op->operand[0].lmod = OPLM_BYTE;
1174 // first operand is not dst
1177 op->regmask_src |= op->regmask_dst;
1178 op->regmask_dst = 0;
1181 // first operand is src too
1194 op->regmask_src |= op->regmask_dst;
1199 op->regmask_src |= op->regmask_dst;
1200 op->regmask_dst |= op->regmask_src;
1206 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1207 && op->operand[0].lmod == op->operand[1].lmod
1208 && op->operand[0].reg == op->operand[1].reg
1209 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1211 op->regmask_src = 0;
1214 op->regmask_src |= op->regmask_dst;
1217 // ops with implicit argumets
1219 op->operand_cnt = 2;
1220 setup_reg_opr(&op->operand[0], xAX, OPLM_BYTE, &op->regmask_src);
1221 op->regmask_dst = op->regmask_src;
1222 setup_reg_opr(&op->operand[1], xBX, OPLM_DWORD, &op->regmask_src);
1226 op->operand_cnt = 2;
1227 setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
1228 setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
1234 if (words[op_w][4] == 'b')
1236 else if (words[op_w][4] == 'w')
1238 else if (words[op_w][4] == 'd')
1241 op->regmask_src = 0;
1242 setup_reg_opr(&op->operand[j++], op->op == OP_LODS ? xSI : xDI,
1243 OPLM_DWORD, &op->regmask_src);
1244 op->regmask_dst = op->regmask_src;
1245 setup_reg_opr(&op->operand[j++], xAX, lmod,
1246 op->op == OP_LODS ? &op->regmask_dst : &op->regmask_src);
1247 if (op->flags & OPF_REP) {
1248 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1249 op->regmask_dst |= 1 << xCX;
1251 op->operand_cnt = j;
1256 if (words[op_w][4] == 'b')
1258 else if (words[op_w][4] == 'w')
1260 else if (words[op_w][4] == 'd')
1263 op->regmask_src = 0;
1264 // note: lmod is not correct, don't have where to place it
1265 setup_reg_opr(&op->operand[j++], xDI, lmod, &op->regmask_src);
1266 setup_reg_opr(&op->operand[j++], xSI, OPLM_DWORD, &op->regmask_src);
1267 if (op->flags & OPF_REP)
1268 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1269 op->operand_cnt = j;
1270 op->regmask_dst = op->regmask_src;
1274 op->regmask_dst = 1 << xCX;
1277 op->operand_cnt = 2;
1278 op->regmask_src = 1 << xCX;
1279 op->operand[1].type = OPT_REG;
1280 op->operand[1].reg = xCX;
1281 op->operand[1].lmod = OPLM_DWORD;
1285 if (op->operand_cnt == 2) {
1286 if (op->operand[0].type != OPT_REG)
1287 aerr("reg expected\n");
1288 op->regmask_src |= 1 << op->operand[0].reg;
1290 if (op->operand_cnt != 1)
1295 op->regmask_src |= op->regmask_dst;
1296 op->regmask_dst = (1 << xDX) | (1 << xAX);
1297 if (op->operand[0].lmod == OPLM_UNSPEC)
1298 op->operand[0].lmod = OPLM_DWORD;
1303 // we could set up operands for edx:eax, but there is no real need to
1304 // (see is_opr_modified())
1305 op->regmask_src |= op->regmask_dst;
1306 op->regmask_dst = (1 << xDX) | (1 << xAX);
1307 if (op->operand[0].lmod == OPLM_UNSPEC)
1308 op->operand[0].lmod = OPLM_DWORD;
1316 op->regmask_src |= op->regmask_dst;
1317 if (op->operand[1].lmod == OPLM_UNSPEC)
1318 op->operand[1].lmod = OPLM_BYTE;
1323 op->regmask_src |= op->regmask_dst;
1324 if (op->operand[2].lmod == OPLM_UNSPEC)
1325 op->operand[2].lmod = OPLM_BYTE;
1329 op->regmask_src |= op->regmask_dst;
1330 op->regmask_dst = 0;
1331 if (op->operand[0].lmod == OPLM_UNSPEC
1332 && (op->operand[0].type == OPT_CONST
1333 || op->operand[0].type == OPT_OFFSET
1334 || op->operand[0].type == OPT_LABEL))
1335 op->operand[0].lmod = OPLM_DWORD;
1341 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1342 && op->operand[0].lmod == op->operand[1].lmod
1343 && op->operand[0].reg == op->operand[1].reg
1344 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1346 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1347 op->regmask_src = op->regmask_dst = 0;
1352 if (op->operand[0].type == OPT_REG
1353 && op->operand[1].type == OPT_REGMEM)
1356 snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1357 if (IS(buf, op->operand[1].name))
1358 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1363 // trashed regs must be explicitly detected later
1364 op->regmask_dst = 0;
1368 op->regmask_dst = (1 << xBP) | (1 << xSP);
1369 op->regmask_src = 1 << xBP;
1374 op->regmask_dst |= mxST0;
1378 op->regmask_dst |= mxST0;
1379 if (IS(words[op_w] + 3, "1"))
1380 op->operand[0].val = X87_CONST_1;
1381 else if (IS(words[op_w] + 3, "ln2"))
1382 op->operand[0].val = X87_CONST_LN2;
1383 else if (IS(words[op_w] + 3, "z"))
1384 op->operand[0].val = X87_CONST_Z;
1391 op->regmask_src |= mxST0;
1400 op->regmask_src |= mxST0;
1401 if (op->operand_cnt == 2)
1402 op->regmask_src |= op->regmask_dst;
1403 else if (op->operand_cnt == 1) {
1404 memcpy(&op->operand[1], &op->operand[0], sizeof(op->operand[1]));
1405 op->operand[0].type = OPT_REG;
1406 op->operand[0].lmod = OPLM_QWORD;
1407 op->operand[0].reg = xST0;
1408 op->regmask_dst |= mxST0;
1411 // IDA doesn't use this
1412 aerr("no operands?\n");
1426 op->regmask_src |= mxST0;
1427 op->regmask_dst |= mxST0;
1432 op->regmask_src |= mxST0 | mxST1;
1433 op->regmask_dst |= mxST0;
1441 op->regmask_src |= mxST0;
1448 if (op->operand[0].type == OPT_REG
1449 && op->operand[1].type == OPT_CONST)
1451 struct parsed_opr *op1 = &op->operand[1];
1452 if ((op->op == OP_AND && op1->val == 0)
1455 || (op->operand[0].lmod == OPLM_WORD && op1->val == 0xffff)
1456 || (op->operand[0].lmod == OPLM_BYTE && op1->val == 0xff))))
1458 op->regmask_src = 0;
1463 static const char *op_name(struct parsed_op *po)
1465 static char buf[16];
1469 if (po->op == OP_JCC || po->op == OP_SCC) {
1471 *p++ = (po->op == OP_JCC) ? 'j' : 's';
1474 strcpy(p, parsed_flag_op_names[po->pfo]);
1478 for (i = 0; i < ARRAY_SIZE(op_table); i++)
1479 if (op_table[i].op == po->op)
1480 return op_table[i].name;
1486 static const char *dump_op(struct parsed_op *po)
1488 static char out[128];
1495 snprintf(out, sizeof(out), "%s", op_name(po));
1496 for (i = 0; i < po->operand_cnt; i++) {
1500 snprintf(p, sizeof(out) - (p - out),
1501 po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1502 po->operand[i].name);
1508 static const char *lmod_type_u(struct parsed_op *po,
1509 enum opr_lenmod lmod)
1521 ferr(po, "invalid lmod: %d\n", lmod);
1522 return "(_invalid_)";
1526 static const char *lmod_cast_u(struct parsed_op *po,
1527 enum opr_lenmod lmod)
1539 ferr(po, "invalid lmod: %d\n", lmod);
1540 return "(_invalid_)";
1544 static const char *lmod_cast_u_ptr(struct parsed_op *po,
1545 enum opr_lenmod lmod)
1557 ferr(po, "invalid lmod: %d\n", lmod);
1558 return "(_invalid_)";
1562 static const char *lmod_cast_s(struct parsed_op *po,
1563 enum opr_lenmod lmod)
1575 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1576 return "(_invalid_)";
1580 static const char *lmod_cast(struct parsed_op *po,
1581 enum opr_lenmod lmod, int is_signed)
1584 lmod_cast_s(po, lmod) :
1585 lmod_cast_u(po, lmod);
1588 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1600 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1605 static const char *opr_name(struct parsed_op *po, int opr_num)
1607 if (opr_num >= po->operand_cnt)
1608 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1609 return po->operand[opr_num].name;
1612 static unsigned int opr_const(struct parsed_op *po, int opr_num)
1614 if (opr_num >= po->operand_cnt)
1615 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1616 if (po->operand[opr_num].type != OPT_CONST)
1617 ferr(po, "opr %d: const expected\n", opr_num);
1618 return po->operand[opr_num].val;
1621 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1623 if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
1624 ferr(po, "invalid reg: %d\n", popr->reg);
1625 return regs_r32[popr->reg];
1628 static int check_simple_cast(const char *cast, int *bits, int *is_signed)
1630 if (IS_START(cast, "(s8)") || IS_START(cast, "(u8)"))
1632 else if (IS_START(cast, "(s16)") || IS_START(cast, "(u16)"))
1634 else if (IS_START(cast, "(s32)") || IS_START(cast, "(u32)"))
1636 else if (IS_START(cast, "(s64)") || IS_START(cast, "(u64)"))
1641 *is_signed = cast[1] == 's' ? 1 : 0;
1645 static int check_deref_cast(const char *cast, int *bits)
1647 if (IS_START(cast, "*(u8 *)"))
1649 else if (IS_START(cast, "*(u16 *)"))
1651 else if (IS_START(cast, "*(u32 *)"))
1653 else if (IS_START(cast, "*(u64 *)"))
1661 // cast1 is the "final" cast
1662 static const char *simplify_cast(const char *cast1, const char *cast2)
1664 static char buf[256];
1672 if (IS(cast1, cast2))
1675 if (check_simple_cast(cast1, &bits1, &s1) == 0
1676 && check_simple_cast(cast2, &bits2, &s2) == 0)
1681 if (check_simple_cast(cast1, &bits1, &s1) == 0
1682 && check_deref_cast(cast2, &bits2) == 0)
1684 if (bits1 == bits2) {
1685 snprintf(buf, sizeof(buf), "*(%c%d *)", s1 ? 's' : 'u', bits1);
1690 if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1693 snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1697 static const char *simplify_cast_num(const char *cast, unsigned int val)
1699 if (IS(cast, "(u8)") && val < 0x100)
1701 if (IS(cast, "(s8)") && val < 0x80)
1703 if (IS(cast, "(u16)") && val < 0x10000)
1705 if (IS(cast, "(s16)") && val < 0x8000)
1707 if (IS(cast, "(s32)") && val < 0x80000000)
1713 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1722 namelen = strlen(name);
1724 p = strchr(name, '+');
1728 ferr(po, "equ parse failed for '%s'\n", name);
1730 if (IS_START(p, "0x"))
1732 *extra_offs = strtol(p, &endp, 16);
1734 ferr(po, "equ parse failed for '%s'\n", name);
1737 for (i = 0; i < g_eqcnt; i++)
1738 if (strncmp(g_eqs[i].name, name, namelen) == 0
1739 && g_eqs[i].name[namelen] == 0)
1743 ferr(po, "unresolved equ name: '%s'\n", name);
1750 static int is_stack_access(struct parsed_op *po,
1751 const struct parsed_opr *popr)
1753 return (parse_stack_el(popr->name, NULL, NULL, 0)
1754 || (g_bp_frame && !(po->flags & OPF_EBP_S)
1755 && IS_START(popr->name, "ebp")));
1758 static void parse_stack_access(struct parsed_op *po,
1759 const char *name, char *ofs_reg, int *offset_out,
1760 int *stack_ra_out, const char **bp_arg_out, int is_lea)
1762 const char *bp_arg = "";
1763 const char *p = NULL;
1764 struct parsed_equ *eq;
1771 if (IS_START(name, "ebp-")
1772 || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1775 if (IS_START(p, "0x"))
1777 offset = strtoul(p, &endp, 16);
1781 ferr(po, "ebp- parse of '%s' failed\n", name);
1784 bp_arg = parse_stack_el(name, ofs_reg, NULL, 0);
1785 eq = equ_find(po, bp_arg, &offset);
1787 ferr(po, "detected but missing eq\n");
1788 offset += eq->offset;
1791 if (!strncmp(name, "ebp", 3))
1794 // yes it sometimes LEAs ra for compares..
1795 if (!is_lea && ofs_reg[0] == 0
1796 && stack_ra <= offset && offset < stack_ra + 4)
1798 ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1801 *offset_out = offset;
1803 *stack_ra_out = stack_ra;
1805 *bp_arg_out = bp_arg;
1808 static int parse_stack_esp_offset(struct parsed_op *po,
1809 const char *name, int *offset_out)
1811 char ofs_reg[16] = { 0, };
1812 struct parsed_equ *eq;
1818 if (strstr(name, "esp") == NULL)
1820 bp_arg = parse_stack_el(name, ofs_reg, &base_val, 0);
1821 if (bp_arg == NULL) {
1822 // just plain offset?
1823 if (!IS_START(name, "esp+"))
1825 offset = strtol(name + 4, &endp, 0);
1826 if (endp == NULL || *endp != 0)
1828 *offset_out = offset;
1832 if (ofs_reg[0] != 0)
1834 eq = equ_find(po, bp_arg, &offset);
1836 ferr(po, "detected but missing eq\n");
1837 offset += eq->offset;
1838 *offset_out = base_val + offset;
1842 static int stack_frame_access(struct parsed_op *po,
1843 struct parsed_opr *popr, char *buf, size_t buf_size,
1844 const char *name, const char *cast, int is_src, int is_lea)
1846 enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1847 const char *prefix = "";
1848 const char *bp_arg = NULL;
1849 char ofs_reg[16] = { 0, };
1850 int i, arg_i, arg_s;
1858 if (po->flags & OPF_EBP_S)
1859 ferr(po, "stack_frame_access while ebp is scratch\n");
1861 parse_stack_access(po, name, ofs_reg, &offset,
1862 &stack_ra, &bp_arg, is_lea);
1864 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1866 if (offset > stack_ra)
1868 arg_i = (offset - stack_ra - 4) / 4;
1869 if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1871 if (g_func_pp->is_vararg
1872 && arg_i == g_func_pp->argc_stack && is_lea)
1874 // should be va_list
1877 snprintf(buf, buf_size, "%sap", cast);
1880 ferr(po, "offset %d (%s,%d) doesn't map to any arg\n",
1881 offset, bp_arg, arg_i);
1883 if (ofs_reg[0] != 0)
1884 ferr(po, "offset reg on arg access?\n");
1886 for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1887 if (g_func_pp->arg[i].reg != NULL)
1893 if (i == g_func_pp->argc)
1894 ferr(po, "arg %d not in prototype?\n", arg_i);
1896 popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
1903 ferr(po, "lea/byte to arg?\n");
1904 if (is_src && (offset & 3) == 0)
1905 snprintf(buf, buf_size, "%sa%d",
1906 simplify_cast(cast, "(u8)"), i + 1);
1908 snprintf(buf, buf_size, "%sBYTE%d(a%d)",
1909 cast, offset & 3, i + 1);
1914 ferr(po, "lea/word to arg?\n");
1919 ferr(po, "problematic arg store\n");
1920 snprintf(buf, buf_size, "%s((char *)&a%d + 1)",
1921 simplify_cast(cast, "*(u16 *)"), i + 1);
1924 ferr(po, "unaligned arg word load\n");
1926 else if (is_src && (offset & 2) == 0)
1927 snprintf(buf, buf_size, "%sa%d",
1928 simplify_cast(cast, "(u16)"), i + 1);
1930 snprintf(buf, buf_size, "%s%sWORD(a%d)",
1931 cast, (offset & 2) ? "HI" : "LO", i + 1);
1943 snprintf(buf, buf_size, "(u32)&a%d + %d",
1946 ferr(po, "unaligned arg store\n");
1948 // mov edx, [ebp+arg_4+2]; movsx ecx, dx
1949 snprintf(buf, buf_size, "%s(a%d >> %d)",
1950 prefix, i + 1, (offset & 3) * 8);
1954 snprintf(buf, buf_size, "%s%sa%d",
1955 prefix, is_lea ? "&" : "", i + 1);
1960 ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
1964 strcat(g_comment, " unaligned");
1967 guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
1968 if (tmp_lmod != OPLM_DWORD
1969 && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
1970 < lmod_bytes(po, popr->lmod) + (offset & 3))))
1972 ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
1973 i + 1, offset, g_func_pp->arg[i].type.name);
1975 // can't check this because msvc likes to reuse
1976 // arg space for scratch..
1977 //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
1978 // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
1982 if (g_stack_fsz == 0)
1983 ferr(po, "stack var access without stackframe\n");
1984 g_stack_frame_used = 1;
1986 sf_ofs = g_stack_fsz + offset;
1987 lim = (ofs_reg[0] != 0) ? -4 : 0;
1988 if (offset > 0 || sf_ofs < lim)
1989 ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
1999 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2000 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2004 if ((sf_ofs & 1) || ofs_reg[0] != 0) {
2005 // known unaligned or possibly unaligned
2006 strcat(g_comment, " unaligned");
2008 prefix = "*(u16 *)&";
2009 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2010 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2013 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
2017 if ((sf_ofs & 3) || ofs_reg[0] != 0) {
2018 // known unaligned or possibly unaligned
2019 strcat(g_comment, " unaligned");
2021 prefix = "*(u32 *)&";
2022 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2023 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2026 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
2030 ferr_assert(po, !(sf_ofs & 7));
2031 ferr_assert(po, ofs_reg[0] == 0);
2032 // float callers set is_lea
2033 ferr_assert(po, is_lea);
2034 snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
2038 ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
2045 static void check_func_pp(struct parsed_op *po,
2046 const struct parsed_proto *pp, const char *pfx)
2048 enum opr_lenmod tmp_lmod;
2052 if (pp->argc_reg != 0) {
2053 if (/*!g_allow_regfunc &&*/ !pp->is_fastcall) {
2054 pp_print(buf, sizeof(buf), pp);
2055 ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
2057 if (pp->argc_stack > 0 && pp->argc_reg != 2)
2058 ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
2059 pfx, pp->argc_reg, pp->argc_stack);
2062 // fptrs must use 32bit args, callsite might have no information and
2063 // lack a cast to smaller types, which results in incorrectly masked
2064 // args passed (callee may assume masked args, it does on ARM)
2065 if (!pp->is_osinc) {
2066 for (i = 0; i < pp->argc; i++) {
2067 ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
2068 if (ret && tmp_lmod != OPLM_DWORD)
2069 ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
2070 i + 1, pp->arg[i].type.name);
2075 static const char *check_label_read_ref(struct parsed_op *po,
2078 const struct parsed_proto *pp;
2080 pp = proto_parse(g_fhdr, name, 0);
2082 ferr(po, "proto_parse failed for ref '%s'\n", name);
2085 check_func_pp(po, pp, "ref");
2090 static char *out_src_opr(char *buf, size_t buf_size,
2091 struct parsed_op *po, struct parsed_opr *popr, const char *cast,
2094 char tmp1[256], tmp2[256];
2103 switch (popr->type) {
2106 ferr(po, "lea from reg?\n");
2108 switch (popr->lmod) {
2110 snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2113 snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2116 snprintf(buf, buf_size, "%s%s",
2117 simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2120 if (popr->name[1] == 'h') // XXX..
2121 snprintf(buf, buf_size, "%s(%s >> 8)",
2122 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2124 snprintf(buf, buf_size, "%s%s",
2125 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2128 ferr(po, "invalid src lmod: %d\n", popr->lmod);
2133 if (is_stack_access(po, popr)) {
2134 stack_frame_access(po, popr, buf, buf_size,
2135 popr->name, cast, 1, is_lea);
2139 strcpy(expr, popr->name);
2140 if (strchr(expr, '[')) {
2141 // special case: '[' can only be left for label[reg] form
2142 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2144 ferr(po, "parse failure for '%s'\n", expr);
2145 if (tmp1[0] == '(') {
2146 // (off_4FFF50+3)[eax]
2147 p = strchr(tmp1 + 1, ')');
2148 if (p == NULL || p[1] != 0)
2149 ferr(po, "parse failure (2) for '%s'\n", expr);
2151 memmove(tmp1, tmp1 + 1, strlen(tmp1));
2153 snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2156 // XXX: do we need more parsing?
2158 snprintf(buf, buf_size, "%s", expr);
2162 snprintf(buf, buf_size, "%s(%s)",
2163 simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2167 name = check_label_read_ref(po, popr->name);
2168 if (cast[0] == 0 && popr->is_ptr)
2172 snprintf(buf, buf_size, "(u32)&%s", name);
2173 else if (popr->size_lt)
2174 snprintf(buf, buf_size, "%s%s%s%s", cast,
2175 lmod_cast_u_ptr(po, popr->lmod),
2176 popr->is_array ? "" : "&", name);
2178 snprintf(buf, buf_size, "%s%s%s", cast, name,
2179 popr->is_array ? "[0]" : "");
2183 name = check_label_read_ref(po, popr->name);
2187 ferr(po, "lea an offset?\n");
2188 snprintf(buf, buf_size, "%s&%s", cast, name);
2193 ferr(po, "lea from const?\n");
2195 printf_number(tmp1, sizeof(tmp1), popr->val);
2196 if (popr->val == 0 && strchr(cast, '*'))
2197 snprintf(buf, buf_size, "NULL");
2199 snprintf(buf, buf_size, "%s%s",
2200 simplify_cast_num(cast, popr->val), tmp1);
2204 ferr(po, "invalid src type: %d\n", popr->type);
2210 // note: may set is_ptr (we find that out late for ebp frame..)
2211 static char *out_dst_opr(char *buf, size_t buf_size,
2212 struct parsed_op *po, struct parsed_opr *popr)
2214 switch (popr->type) {
2216 switch (popr->lmod) {
2218 snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2221 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2225 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2229 if (popr->name[1] == 'h') // XXX..
2230 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2232 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2235 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2240 if (is_stack_access(po, popr)) {
2241 stack_frame_access(po, popr, buf, buf_size,
2242 popr->name, "", 0, 0);
2246 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2249 if (popr->size_mismatch)
2250 snprintf(buf, buf_size, "%s%s%s",
2251 lmod_cast_u_ptr(po, popr->lmod),
2252 popr->is_array ? "" : "&", popr->name);
2254 snprintf(buf, buf_size, "%s%s", popr->name,
2255 popr->is_array ? "[0]" : "");
2259 ferr(po, "invalid dst type: %d\n", popr->type);
2265 static char *out_src_opr_u32(char *buf, size_t buf_size,
2266 struct parsed_op *po, struct parsed_opr *popr)
2268 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2271 static char *out_src_opr_float(char *buf, size_t buf_size,
2272 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2274 const char *cast = NULL;
2277 switch (popr->type) {
2279 if (popr->reg < xST0 || popr->reg > xST7)
2280 ferr(po, "bad reg: %d\n", popr->reg);
2282 if (need_float_stack) {
2283 if (popr->reg == xST0)
2284 snprintf(buf, buf_size, "f_st[f_stp & 7]");
2286 snprintf(buf, buf_size, "f_st[(f_stp + %d) & 7]",
2290 snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2296 switch (popr->lmod) {
2304 ferr(po, "unhandled lmod: %d\n", popr->lmod);
2307 out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2308 snprintf(buf, buf_size, "*((%s *)%s)", cast, tmp);
2312 ferr(po, "invalid float type: %d\n", popr->type);
2318 static char *out_dst_opr_float(char *buf, size_t buf_size,
2319 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2322 return out_src_opr_float(buf, buf_size, po, popr, need_float_stack);
2325 static void out_test_for_cc(char *buf, size_t buf_size,
2326 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2327 enum opr_lenmod lmod, const char *expr)
2329 const char *cast, *scast;
2331 cast = lmod_cast_u(po, lmod);
2332 scast = lmod_cast_s(po, lmod);
2336 case PFO_BE: // CF=1||ZF=1; CF=0
2337 snprintf(buf, buf_size, "(%s%s %s 0)",
2338 cast, expr, is_inv ? "!=" : "==");
2342 case PFO_L: // SF!=OF; OF=0
2343 snprintf(buf, buf_size, "(%s%s %s 0)",
2344 scast, expr, is_inv ? ">=" : "<");
2347 case PFO_LE: // ZF=1||SF!=OF; OF=0
2348 snprintf(buf, buf_size, "(%s%s %s 0)",
2349 scast, expr, is_inv ? ">" : "<=");
2353 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2357 static void out_cmp_for_cc(char *buf, size_t buf_size,
2358 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2361 const char *cast, *scast, *cast_use;
2362 char buf1[256], buf2[256];
2363 enum opr_lenmod lmod;
2365 if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2366 ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2367 po->operand[0].lmod, po->operand[1].lmod);
2368 lmod = po->operand[0].lmod;
2370 cast = lmod_cast_u(po, lmod);
2371 scast = lmod_cast_s(po, lmod);
2387 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2390 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2391 if (po->op == OP_DEC)
2392 snprintf(buf2, sizeof(buf2), "1");
2395 snprintf(cast_op2, sizeof(cast_op2) - 1, "%s", cast_use);
2397 strcat(cast_op2, "-");
2398 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_op2, 0);
2403 // note: must be unsigned compare
2404 snprintf(buf, buf_size, "(%s %s %s)",
2405 buf1, is_inv ? ">=" : "<", buf2);
2409 snprintf(buf, buf_size, "(%s %s %s)",
2410 buf1, is_inv ? "!=" : "==", buf2);
2414 // note: must be unsigned compare
2415 snprintf(buf, buf_size, "(%s %s %s)",
2416 buf1, is_inv ? ">" : "<=", buf2);
2419 if (is_inv && lmod == OPLM_BYTE
2420 && po->operand[1].type == OPT_CONST
2421 && po->operand[1].val == 0xff)
2423 snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2424 snprintf(buf, buf_size, "(0)");
2428 // note: must be signed compare
2430 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2431 scast, buf1, buf2, is_inv ? ">=" : "<");
2435 snprintf(buf, buf_size, "(%s %s %s)",
2436 buf1, is_inv ? ">=" : "<", buf2);
2440 snprintf(buf, buf_size, "(%s %s %s)",
2441 buf1, is_inv ? ">" : "<=", buf2);
2449 static void out_cmp_test(char *buf, size_t buf_size,
2450 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2452 char buf1[256], buf2[256], buf3[256];
2454 if (po->op == OP_TEST) {
2455 if (IS(opr_name(po, 0), opr_name(po, 1))) {
2456 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2459 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2460 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2461 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2463 out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2464 po->operand[0].lmod, buf3);
2466 else if (po->op == OP_CMP) {
2467 out_cmp_for_cc(buf, buf_size, po, pfo, is_inv, 0);
2470 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2473 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2474 struct parsed_opr *popr2)
2476 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2477 ferr(po, "missing lmod for both operands\n");
2479 if (popr1->lmod == OPLM_UNSPEC)
2480 popr1->lmod = popr2->lmod;
2481 else if (popr2->lmod == OPLM_UNSPEC)
2482 popr2->lmod = popr1->lmod;
2483 else if (popr1->lmod != popr2->lmod) {
2484 if (popr1->type_from_var) {
2485 popr1->size_mismatch = 1;
2486 if (popr1->lmod < popr2->lmod)
2488 popr1->lmod = popr2->lmod;
2490 else if (popr2->type_from_var) {
2491 popr2->size_mismatch = 1;
2492 if (popr2->lmod < popr1->lmod)
2494 popr2->lmod = popr1->lmod;
2497 ferr(po, "conflicting lmods: %d vs %d\n",
2498 popr1->lmod, popr2->lmod);
2502 static const char *op_to_c(struct parsed_op *po)
2526 ferr(po, "op_to_c was supplied with %d\n", po->op);
2530 // last op in stream - unconditional branch or ret
2531 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2532 || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2533 && ops[_i].op != OP_CALL))
2535 #define check_i(po, i) \
2537 ferr(po, "bad " #i ": %d\n", i)
2539 // note: this skips over calls and rm'd stuff assuming they're handled
2540 // so it's intended to use at one of final passes
2541 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2542 int depth, int seen_noreturn, int flags_set)
2544 struct parsed_op *po;
2549 for (; i < opcnt; i++) {
2551 if (po->cc_scratch == magic)
2552 return ret; // already checked
2553 po->cc_scratch = magic;
2555 if (po->flags & OPF_TAIL) {
2556 if (po->op == OP_CALL) {
2557 if (po->pp != NULL && po->pp->is_noreturn)
2563 return -1; // deadend
2566 if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
2569 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2570 if (po->btj != NULL) {
2572 for (j = 0; j < po->btj->count; j++) {
2573 check_i(po, po->btj->d[j].bt_i);
2574 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2575 depth, seen_noreturn, flags_set);
2577 return ret; // dead end
2582 check_i(po, po->bt_i);
2583 if (po->flags & OPF_CJMP) {
2584 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2585 depth, seen_noreturn, flags_set);
2587 return ret; // dead end
2596 if ((po->op == OP_POP || po->op == OP_PUSH)
2597 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2602 if (po->op == OP_PUSH) {
2605 else if (po->op == OP_POP) {
2606 if (relevant && depth == 0) {
2607 po->flags |= flags_set;
2614 // for noreturn, assume msvc skipped stack cleanup
2615 return seen_noreturn ? 1 : -1;
2618 // scan for 'reg' pop backwards starting from i
2619 // intended to use for register restore search, so other reg
2620 // references are considered an error
2621 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2623 struct parsed_op *po;
2624 struct label_ref *lr;
2627 ops[i].cc_scratch = magic;
2631 if (g_labels[i] != NULL) {
2632 lr = &g_label_refs[i];
2633 for (; lr != NULL; lr = lr->next) {
2634 check_i(&ops[i], lr->i);
2635 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2639 if (i > 0 && LAST_OP(i - 1))
2647 if (ops[i].cc_scratch == magic)
2649 ops[i].cc_scratch = magic;
2652 if (po->op == OP_POP && po->operand[0].reg == reg) {
2653 if (po->flags & (OPF_RMD|OPF_DONE))
2656 po->flags |= set_flags;
2660 // this also covers the case where we reach corresponding push
2661 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2665 // nothing interesting on this path
2669 static void find_reachable_exits(int i, int opcnt, int magic,
2670 int *exits, int *exit_count)
2672 struct parsed_op *po;
2675 for (; i < opcnt; i++)
2678 if (po->cc_scratch == magic)
2680 po->cc_scratch = magic;
2682 if (po->flags & OPF_TAIL) {
2683 ferr_assert(po, *exit_count < MAX_EXITS);
2684 exits[*exit_count] = i;
2689 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2690 if (po->flags & OPF_RMD)
2693 if (po->btj != NULL) {
2694 for (j = 0; j < po->btj->count; j++) {
2695 check_i(po, po->btj->d[j].bt_i);
2696 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2702 check_i(po, po->bt_i);
2703 if (po->flags & OPF_CJMP)
2704 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2712 // scan for 'reg' pop backwards starting from exits (all paths)
2713 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2715 static int exits[MAX_EXITS];
2716 static int exit_count;
2721 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2723 ferr_assert(&ops[i], exit_count > 0);
2726 for (j = 0; j < exit_count; j++) {
2727 ret = scan_for_rsave_pop_reg(exits[j], i + opcnt * 16 + set_flags,
2736 // scan for one or more pop of push <const>
2737 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2738 int push_i, int is_probe)
2740 struct parsed_op *po;
2741 struct label_ref *lr;
2745 for (; i < opcnt; i++)
2748 if (po->cc_scratch == magic)
2749 return ret; // already checked
2750 po->cc_scratch = magic;
2752 if (po->flags & OPF_JMP) {
2753 if (po->flags & OPF_RMD)
2755 if (po->op == OP_CALL)
2758 if (po->btj != NULL) {
2759 for (j = 0; j < po->btj->count; j++) {
2760 check_i(po, po->btj->d[j].bt_i);
2761 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2769 check_i(po, po->bt_i);
2770 if (po->flags & OPF_CJMP) {
2771 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2782 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2785 if (g_labels[i] != NULL) {
2786 // all refs must be visited
2787 lr = &g_label_refs[i];
2788 for (; lr != NULL; lr = lr->next) {
2790 if (ops[lr->i].cc_scratch != magic)
2793 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2797 if (po->op == OP_POP)
2799 if (po->flags & (OPF_RMD|OPF_DONE))
2803 po->flags |= OPF_DONE;
2804 po->datap = &ops[push_i];
2813 static void scan_for_pop_const(int i, int opcnt, int magic)
2817 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
2819 ops[i].flags |= OPF_RMD | OPF_DONE;
2820 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
2824 // check if all branch targets within a marked path are also marked
2825 // note: the path checked must not be empty or end with a branch
2826 static int check_path_branches(int opcnt, int magic)
2828 struct parsed_op *po;
2831 for (i = 0; i < opcnt; i++) {
2833 if (po->cc_scratch != magic)
2836 if (po->flags & OPF_JMP) {
2837 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
2840 if (po->btj != NULL) {
2841 for (j = 0; j < po->btj->count; j++) {
2842 check_i(po, po->btj->d[j].bt_i);
2843 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
2848 check_i(po, po->bt_i);
2849 if (ops[po->bt_i].cc_scratch != magic)
2851 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
2859 // scan for multiple pushes for given pop
2860 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
2863 int reg = ops[pop_i].operand[0].reg;
2864 struct parsed_op *po;
2865 struct label_ref *lr;
2868 ops[i].cc_scratch = magic;
2872 if (g_labels[i] != NULL) {
2873 lr = &g_label_refs[i];
2874 for (; lr != NULL; lr = lr->next) {
2875 check_i(&ops[i], lr->i);
2876 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
2880 if (i > 0 && LAST_OP(i - 1))
2888 if (ops[i].cc_scratch == magic)
2890 ops[i].cc_scratch = magic;
2893 if (po->op == OP_CALL)
2895 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
2898 if (po->op == OP_PUSH)
2900 if (po->datap != NULL)
2902 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2903 // leave this case for reg save/restore handlers
2907 po->flags |= OPF_PPUSH | OPF_DONE;
2908 po->datap = &ops[pop_i];
2917 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
2919 int magic = i + opcnt * 14;
2922 ret = scan_pushes_for_pop_r(i, magic, i, 1);
2924 ret = check_path_branches(opcnt, magic);
2926 ops[i].flags |= OPF_PPUSH | OPF_DONE;
2927 *regmask_pp |= 1 << ops[i].operand[0].reg;
2928 scan_pushes_for_pop_r(i, magic + 1, i, 0);
2933 static void scan_propagate_df(int i, int opcnt)
2935 struct parsed_op *po = &ops[i];
2938 for (; i < opcnt; i++) {
2940 if (po->flags & OPF_DF)
2941 return; // already resolved
2942 po->flags |= OPF_DF;
2944 if (po->op == OP_CALL)
2945 ferr(po, "call with DF set?\n");
2947 if (po->flags & OPF_JMP) {
2948 if (po->btj != NULL) {
2950 for (j = 0; j < po->btj->count; j++) {
2951 check_i(po, po->btj->d[j].bt_i);
2952 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
2957 if (po->flags & OPF_RMD)
2959 check_i(po, po->bt_i);
2960 if (po->flags & OPF_CJMP)
2961 scan_propagate_df(po->bt_i, opcnt);
2967 if (po->flags & OPF_TAIL)
2970 if (po->op == OP_CLD) {
2971 po->flags |= OPF_RMD | OPF_DONE;
2976 ferr(po, "missing DF clear?\n");
2979 // is operand 'opr' referenced by parsed_op 'po'?
2980 static int is_opr_referenced(const struct parsed_opr *opr,
2981 const struct parsed_op *po)
2985 if (opr->type == OPT_REG) {
2986 mask = po->regmask_dst | po->regmask_src;
2987 if (po->op == OP_CALL)
2988 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
2989 if ((1 << opr->reg) & mask)
2995 for (i = 0; i < po->operand_cnt; i++)
2996 if (IS(po->operand[0].name, opr->name))
3002 // is operand 'opr' read by parsed_op 'po'?
3003 static int is_opr_read(const struct parsed_opr *opr,
3004 const struct parsed_op *po)
3006 if (opr->type == OPT_REG) {
3007 if (po->regmask_src & (1 << opr->reg))
3017 // is operand 'opr' modified by parsed_op 'po'?
3018 static int is_opr_modified(const struct parsed_opr *opr,
3019 const struct parsed_op *po)
3023 if (opr->type == OPT_REG) {
3024 if (po->op == OP_CALL) {
3025 mask = po->regmask_dst;
3026 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
3027 if (mask & (1 << opr->reg))
3033 if (po->regmask_dst & (1 << opr->reg))
3039 return IS(po->operand[0].name, opr->name);
3042 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
3043 static int is_any_opr_modified(const struct parsed_op *po_test,
3044 const struct parsed_op *po, int c_mode)
3049 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
3052 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3055 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
3058 // in reality, it can wreck any register, but in decompiled C
3059 // version it can only overwrite eax or edx:eax
3060 mask = (1 << xAX) | (1 << xDX);
3064 if (po->op == OP_CALL
3065 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
3068 for (i = 0; i < po_test->operand_cnt; i++)
3069 if (IS(po_test->operand[i].name, po->operand[0].name))
3075 // scan for any po_test operand modification in range given
3076 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
3079 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3082 for (; i < opcnt; i++) {
3083 if (is_any_opr_modified(po_test, &ops[i], c_mode))
3090 // scan for po_test operand[0] modification in range given
3091 static int scan_for_mod_opr0(struct parsed_op *po_test,
3094 for (; i < opcnt; i++) {
3095 if (is_opr_modified(&po_test->operand[0], &ops[i]))
3102 static int try_resolve_const(int i, const struct parsed_opr *opr,
3103 int magic, unsigned int *val);
3105 static int scan_for_flag_set(int i, int opcnt, int magic,
3106 int *branched, int *setters, int *setter_cnt)
3108 struct label_ref *lr;
3112 if (ops[i].cc_scratch == magic) {
3113 // is this a problem?
3114 //ferr(&ops[i], "%s looped\n", __func__);
3117 ops[i].cc_scratch = magic;
3119 if (g_labels[i] != NULL) {
3122 lr = &g_label_refs[i];
3123 for (; lr->next; lr = lr->next) {
3124 check_i(&ops[i], lr->i);
3125 ret = scan_for_flag_set(lr->i, opcnt, magic,
3126 branched, setters, setter_cnt);
3131 check_i(&ops[i], lr->i);
3132 if (i > 0 && LAST_OP(i - 1)) {
3136 ret = scan_for_flag_set(lr->i, opcnt, magic,
3137 branched, setters, setter_cnt);
3143 if (ops[i].flags & OPF_FLAGS) {
3144 setters[*setter_cnt] = i;
3147 if (ops[i].flags & OPF_REP) {
3148 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
3151 ret = try_resolve_const(i, &opr, i + opcnt * 7, &uval);
3152 if (ret != 1 || uval == 0) {
3153 // can't treat it as full setter because of ecx=0 case,
3154 // also disallow delayed compare
3163 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3170 // scan back for cdq, if anything modifies edx, fail
3171 static int scan_for_cdq_edx(int i)
3174 if (g_labels[i] != NULL) {
3175 if (g_label_refs[i].next != NULL)
3177 if (i > 0 && LAST_OP(i - 1)) {
3178 i = g_label_refs[i].i;
3185 if (ops[i].op == OP_CDQ)
3188 if (ops[i].regmask_dst & (1 << xDX))
3195 static int scan_for_reg_clear(int i, int reg)
3198 if (g_labels[i] != NULL) {
3199 if (g_label_refs[i].next != NULL)
3201 if (i > 0 && LAST_OP(i - 1)) {
3202 i = g_label_refs[i].i;
3209 if (ops[i].op == OP_XOR
3210 && ops[i].operand[0].lmod == OPLM_DWORD
3211 && ops[i].operand[0].reg == ops[i].operand[1].reg
3212 && ops[i].operand[0].reg == reg)
3215 if (ops[i].regmask_dst & (1 << reg))
3222 static void patch_esp_adjust(struct parsed_op *po, int adj)
3224 ferr_assert(po, po->op == OP_ADD);
3225 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3226 ferr_assert(po, po->operand[1].type == OPT_CONST);
3228 // this is a bit of a hack, but deals with use of
3229 // single adj for multiple calls
3230 po->operand[1].val -= adj;
3231 po->flags |= OPF_RMD;
3232 if (po->operand[1].val == 0)
3233 po->flags |= OPF_DONE;
3234 ferr_assert(po, (int)po->operand[1].val >= 0);
3237 // scan for positive, constant esp adjust
3238 // multipath case is preliminary
3239 static int scan_for_esp_adjust(int i, int opcnt,
3240 int adj_expect, int *adj, int *is_multipath, int do_update)
3242 int adj_expect_unknown = 0;
3243 struct parsed_op *po;
3247 *adj = *is_multipath = 0;
3248 if (adj_expect < 0) {
3249 adj_expect_unknown = 1;
3250 adj_expect = 32 * 4; // enough?
3253 for (; i < opcnt && *adj < adj_expect; i++) {
3254 if (g_labels[i] != NULL)
3258 if (po->flags & OPF_DONE)
3261 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3262 if (po->operand[1].type != OPT_CONST)
3263 ferr(&ops[i], "non-const esp adjust?\n");
3264 *adj += po->operand[1].val;
3266 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3269 patch_esp_adjust(po, adj_expect);
3271 po->flags |= OPF_RMD;
3275 else if (po->op == OP_PUSH) {
3276 //if (first_pop == -1)
3277 // first_pop = -2; // none
3278 *adj -= lmod_bytes(po, po->operand[0].lmod);
3280 else if (po->op == OP_POP) {
3281 if (!(po->flags & OPF_DONE)) {
3282 // seems like msvc only uses 'pop ecx' for stack realignment..
3283 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3285 if (first_pop == -1 && *adj >= 0)
3288 if (do_update && *adj >= 0) {
3289 po->flags |= OPF_RMD;
3291 po->flags |= OPF_DONE | OPF_NOREGS;
3294 *adj += lmod_bytes(po, po->operand[0].lmod);
3295 if (*adj > adj_best)
3298 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3299 if (po->op == OP_JMP && po->btj == NULL) {
3305 if (po->op != OP_CALL)
3307 if (po->operand[0].type != OPT_LABEL)
3309 if (po->pp != NULL && po->pp->is_stdcall)
3311 if (adj_expect_unknown && first_pop >= 0)
3313 // assume it's another cdecl call
3317 if (first_pop >= 0) {
3318 // probably only 'pop ecx' was used
3326 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3328 struct parsed_op *po;
3332 ferr(ops, "%s: followed bad branch?\n", __func__);
3334 for (; i < opcnt; i++) {
3336 if (po->cc_scratch == magic)
3338 po->cc_scratch = magic;
3341 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3342 if (po->btj != NULL) {
3344 for (j = 0; j < po->btj->count; j++)
3345 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3349 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3350 if (!(po->flags & OPF_CJMP))
3353 if (po->flags & OPF_TAIL)
3358 static const struct parsed_proto *try_recover_pp(
3359 struct parsed_op *po, const struct parsed_opr *opr,
3360 int is_call, int *search_instead)
3362 const struct parsed_proto *pp = NULL;
3366 // maybe an arg of g_func?
3367 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3369 char ofs_reg[16] = { 0, };
3370 int arg, arg_s, arg_i;
3377 parse_stack_access(po, opr->name, ofs_reg,
3378 &offset, &stack_ra, NULL, 0);
3379 if (ofs_reg[0] != 0)
3380 ferr(po, "offset reg on arg access?\n");
3381 if (offset <= stack_ra) {
3382 // search who set the stack var instead
3383 if (search_instead != NULL)
3384 *search_instead = 1;
3388 arg_i = (offset - stack_ra - 4) / 4;
3389 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3390 if (g_func_pp->arg[arg].reg != NULL)
3396 if (arg == g_func_pp->argc)
3397 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3399 pp = g_func_pp->arg[arg].pp;
3402 ferr(po, "icall arg: arg%d has no pp\n", arg + 1);
3403 check_func_pp(po, pp, "icall arg");
3406 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3408 p = strchr(opr->name + 1, '[');
3409 memcpy(buf, opr->name, p - opr->name);
3410 buf[p - opr->name] = 0;
3411 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3413 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3414 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3417 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3420 check_func_pp(po, pp, "reg-fptr ref");
3426 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3427 int magic, const struct parsed_proto **pp_found, int *pp_i,
3430 const struct parsed_proto *pp = NULL;
3431 struct parsed_op *po;
3432 struct label_ref *lr;
3434 ops[i].cc_scratch = magic;
3437 if (g_labels[i] != NULL) {
3438 lr = &g_label_refs[i];
3439 for (; lr != NULL; lr = lr->next) {
3440 check_i(&ops[i], lr->i);
3441 scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3443 if (i > 0 && LAST_OP(i - 1))
3451 if (ops[i].cc_scratch == magic)
3453 ops[i].cc_scratch = magic;
3455 if (!(ops[i].flags & OPF_DATA))
3457 if (!is_opr_modified(opr, &ops[i]))
3459 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3460 // most probably trashed by some processing
3465 opr = &ops[i].operand[1];
3466 if (opr->type != OPT_REG)
3470 po = (i >= 0) ? &ops[i] : ops;
3473 // reached the top - can only be an arg-reg
3474 if (opr->type != OPT_REG || g_func_pp == NULL)
3477 for (i = 0; i < g_func_pp->argc; i++) {
3478 if (g_func_pp->arg[i].reg == NULL)
3480 if (IS(opr->name, g_func_pp->arg[i].reg))
3483 if (i == g_func_pp->argc)
3485 pp = g_func_pp->arg[i].pp;
3487 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3488 i + 1, g_func_pp->arg[i].reg);
3489 check_func_pp(po, pp, "icall reg-arg");
3492 pp = try_recover_pp(po, opr, 1, NULL);
3494 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3495 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3496 || (*pp_found)->is_stdcall != pp->is_stdcall
3497 || (*pp_found)->is_fptr != pp->is_fptr
3498 || (*pp_found)->argc != pp->argc
3499 || (*pp_found)->argc_reg != pp->argc_reg
3500 || (*pp_found)->argc_stack != pp->argc_stack)
3502 ferr(po, "icall: parsed_proto mismatch\n");
3512 static void add_label_ref(struct label_ref *lr, int op_i)
3514 struct label_ref *lr_new;
3521 lr_new = calloc(1, sizeof(*lr_new));
3523 lr_new->next = lr->next;
3527 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3529 struct parsed_op *po = &ops[i];
3530 struct parsed_data *pd;
3531 char label[NAMELEN], *p;
3534 p = strchr(po->operand[0].name, '[');
3538 len = p - po->operand[0].name;
3539 strncpy(label, po->operand[0].name, len);
3542 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3543 if (IS(g_func_pd[j].label, label)) {
3549 //ferr(po, "label '%s' not parsed?\n", label);
3552 if (pd->type != OPT_OFFSET)
3553 ferr(po, "label '%s' with non-offset data?\n", label);
3555 // find all labels, link
3556 for (j = 0; j < pd->count; j++) {
3557 for (l = 0; l < opcnt; l++) {
3558 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3559 add_label_ref(&g_label_refs[l], i);
3569 static void clear_labels(int count)
3573 for (i = 0; i < count; i++) {
3574 if (g_labels[i] != NULL) {
3581 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3586 for (i = 0; i < pp->argc; i++) {
3587 if (pp->arg[i].reg != NULL) {
3588 reg = char_array_i(regs_r32,
3589 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3591 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3592 pp->arg[i].reg, pp->name);
3593 regmask |= 1 << reg;
3600 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3605 if (pp->has_retreg) {
3606 for (i = 0; i < pp->argc; i++) {
3607 if (pp->arg[i].type.is_retreg) {
3608 reg = char_array_i(regs_r32,
3609 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3610 ferr_assert(ops, reg >= 0);
3611 regmask |= 1 << reg;
3616 if (strstr(pp->ret_type.name, "int64"))
3617 return regmask | (1 << xAX) | (1 << xDX);
3618 if (IS(pp->ret_type.name, "float")
3619 || IS(pp->ret_type.name, "double"))
3621 return regmask | mxST0;
3623 if (strcasecmp(pp->ret_type.name, "void") == 0)
3626 return regmask | mxAX;
3629 static int are_ops_same(struct parsed_op *po1, struct parsed_op *po2)
3631 return po1->op == po2->op && po1->operand_cnt == po2->operand_cnt
3632 && memcmp(po1->operand, po2->operand,
3633 sizeof(po1->operand[0]) * po1->operand_cnt) == 0;
3636 static void resolve_branches_parse_calls(int opcnt)
3638 static const struct {
3642 unsigned int regmask_src;
3643 unsigned int regmask_dst;
3645 { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3646 { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3647 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3649 const struct parsed_proto *pp_c;
3650 struct parsed_proto *pp;
3651 struct parsed_data *pd;
3652 struct parsed_op *po;
3653 const char *tmpname;
3657 for (i = 0; i < opcnt; i++)
3663 if (po->datap != NULL) {
3664 pp = calloc(1, sizeof(*pp));
3665 my_assert_not(pp, NULL);
3667 ret = parse_protostr(po->datap, pp);
3669 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3675 if (po->op == OP_CALL) {
3680 else if (po->operand[0].type == OPT_LABEL)
3682 tmpname = opr_name(po, 0);
3683 if (IS_START(tmpname, "loc_"))
3684 ferr(po, "call to loc_*\n");
3685 if (IS(tmpname, "__alloca_probe"))
3688 // convert some calls to pseudo-ops
3689 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3690 if (!IS(tmpname, pseudo_ops[l].name))
3693 po->op = pseudo_ops[l].op;
3694 po->operand_cnt = 0;
3695 po->regmask_src = pseudo_ops[l].regmask_src;
3696 po->regmask_dst = pseudo_ops[l].regmask_dst;
3697 po->flags = pseudo_ops[l].flags;
3698 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3701 if (l < ARRAY_SIZE(pseudo_ops))
3704 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3705 if (!g_header_mode && pp_c == NULL)
3706 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3709 pp = proto_clone(pp_c);
3710 my_assert_not(pp, NULL);
3716 check_func_pp(po, pp, "fptr var call");
3717 if (pp->is_noreturn)
3718 po->flags |= OPF_TAIL;
3724 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3727 if (po->operand[0].type == OPT_REGMEM) {
3728 pd = try_resolve_jumptab(i, opcnt);
3736 for (l = 0; l < opcnt; l++) {
3737 if (g_labels[l] != NULL
3738 && IS(po->operand[0].name, g_labels[l]))
3740 if (l == i + 1 && po->op == OP_JMP) {
3741 // yet another alignment type..
3742 po->flags |= OPF_RMD|OPF_DONE;
3745 add_label_ref(&g_label_refs[l], i);
3751 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3754 if (po->operand[0].type == OPT_LABEL)
3758 ferr(po, "unhandled branch\n");
3762 po->flags |= OPF_TAIL;
3763 if (i > 0 && ops[i - 1].op == OP_POP)
3764 po->flags |= OPF_ATAIL;
3769 static void scan_prologue_epilogue(int opcnt)
3771 int ecx_push = 0, esp_sub = 0, pusha = 0;
3772 int sandard_epilogue;
3776 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
3777 && ops[1].op == OP_MOV
3778 && IS(opr_name(&ops[1], 0), "ebp")
3779 && IS(opr_name(&ops[1], 1), "esp"))
3782 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3783 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3786 if (ops[i].op == OP_PUSHA) {
3787 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3792 if (ops[i].op == OP_SUB && IS(opr_name(&ops[i], 0), "esp")) {
3793 g_stack_fsz = opr_const(&ops[i], 1);
3794 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3798 // another way msvc builds stack frame..
3799 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3801 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3805 // and another way..
3806 if (i == 2 && ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3807 && ops[i].operand[1].type == OPT_CONST
3808 && ops[i + 1].op == OP_CALL
3809 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3811 g_stack_fsz += ops[i].operand[1].val;
3812 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3814 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3821 for (; i < opcnt; i++)
3822 if (ops[i].flags & OPF_TAIL)
3825 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3826 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3832 sandard_epilogue = 0;
3833 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
3835 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3836 // the standard epilogue is sometimes even used without a sf
3837 if (ops[j - 1].op == OP_MOV
3838 && IS(opr_name(&ops[j - 1], 0), "esp")
3839 && IS(opr_name(&ops[j - 1], 1), "ebp"))
3840 sandard_epilogue = 1;
3842 else if (ops[j].op == OP_LEAVE)
3844 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3845 sandard_epilogue = 1;
3847 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
3848 && ops[i].pp->is_noreturn)
3850 // on noreturn, msvc sometimes cleans stack, sometimes not
3855 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3856 ferr(&ops[j], "'pop ebp' expected\n");
3858 if (g_stack_fsz != 0 || sandard_epilogue) {
3859 if (ops[j].op == OP_LEAVE)
3861 else if (sandard_epilogue) // mov esp, ebp
3863 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3866 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3868 ferr(&ops[j], "esp restore expected\n");
3871 if (ecx_push && j >= 0 && ops[j].op == OP_POP
3872 && IS(opr_name(&ops[j], 0), "ecx"))
3874 ferr(&ops[j], "unexpected ecx pop\n");
3879 if (ops[j].op == OP_POPA)
3880 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3882 ferr(&ops[j], "popa expected\n");
3887 } while (i < opcnt);
3890 ferr(ops, "missing ebp epilogue\n");
3896 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3897 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3903 for (; i < opcnt; i++) {
3904 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
3906 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
3907 && ops[i].operand[1].type == OPT_CONST)
3909 g_stack_fsz = ops[i].operand[1].val;
3910 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3915 else if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3916 && ops[i].operand[1].type == OPT_CONST
3917 && ops[i + 1].op == OP_CALL
3918 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3920 g_stack_fsz += ops[i].operand[1].val;
3921 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3923 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3930 if (ecx_push && !esp_sub) {
3931 // could actually be args for a call..
3932 for (; i < opcnt; i++)
3933 if (ops[i].op != OP_PUSH)
3936 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
3937 const struct parsed_proto *pp;
3938 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
3939 j = pp ? pp->argc_stack : 0;
3940 while (i > 0 && j > 0) {
3942 if (ops[i].op == OP_PUSH) {
3943 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
3948 ferr(&ops[i], "unhandled prologue\n");
3951 i = g_stack_fsz = ecx_push = 0;
3952 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3953 if (!(ops[i].flags & OPF_RMD))
3963 if (ecx_push || esp_sub)
3968 for (; i < opcnt; i++)
3969 if (ops[i].flags & OPF_TAIL)
3973 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3974 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3981 for (l = 0; l < ecx_push; l++) {
3982 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
3984 else if (ops[j].op == OP_ADD
3985 && IS(opr_name(&ops[j], 0), "esp")
3986 && ops[j].operand[1].type == OPT_CONST)
3989 l += ops[j].operand[1].val / 4 - 1;
3992 ferr(&ops[j], "'pop ecx' expected\n");
3994 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3998 ferr(&ops[j], "epilogue scan failed\n");
4004 if (ops[j].op != OP_ADD
4005 || !IS(opr_name(&ops[j], 0), "esp")
4006 || ops[j].operand[1].type != OPT_CONST
4007 || ops[j].operand[1].val != g_stack_fsz)
4009 if (ops[i].op == OP_CALL && ops[i].pp != NULL
4010 && ops[i].pp->is_noreturn)
4012 // noreturn tailcall with no epilogue
4016 ferr(&ops[j], "'add esp' expected\n");
4019 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4020 ops[j].operand[1].val = 0; // hack for stack arg scanner
4025 } while (i < opcnt);
4028 ferr(ops, "missing esp epilogue\n");
4032 // find an instruction that changed opr before i op
4033 // *op_i must be set to -1 by the caller
4034 // *is_caller is set to 1 if one source is determined to be g_func arg
4035 // returns 1 if found, *op_i is then set to origin
4036 // returns -1 if multiple origins are found
4037 static int resolve_origin(int i, const struct parsed_opr *opr,
4038 int magic, int *op_i, int *is_caller)
4040 struct label_ref *lr;
4044 if (g_labels[i] != NULL) {
4045 lr = &g_label_refs[i];
4046 for (; lr != NULL; lr = lr->next) {
4047 check_i(&ops[i], lr->i);
4048 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4050 if (i > 0 && LAST_OP(i - 1))
4056 if (is_caller != NULL)
4061 if (ops[i].cc_scratch == magic)
4063 ops[i].cc_scratch = magic;
4065 if (!(ops[i].flags & OPF_DATA))
4067 if (!is_opr_modified(opr, &ops[i]))
4071 if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4082 // find an instruction that previously referenced opr
4083 // if multiple results are found - fail
4084 // *op_i must be set to -1 by the caller
4085 // returns 1 if found, *op_i is then set to referencer insn
4086 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4087 int magic, int *op_i)
4089 struct label_ref *lr;
4093 if (g_labels[i] != NULL) {
4094 lr = &g_label_refs[i];
4095 for (; lr != NULL; lr = lr->next) {
4096 check_i(&ops[i], lr->i);
4097 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4099 if (i > 0 && LAST_OP(i - 1))
4107 if (ops[i].cc_scratch == magic)
4109 ops[i].cc_scratch = magic;
4111 if (!is_opr_referenced(opr, &ops[i]))
4122 // adjust datap of all reachable 'op' insns when moving back
4123 // returns 1 if at least 1 op was found
4124 // returns -1 if path without an op was found
4125 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4127 struct label_ref *lr;
4130 if (ops[i].cc_scratch == magic)
4132 ops[i].cc_scratch = magic;
4135 if (g_labels[i] != NULL) {
4136 lr = &g_label_refs[i];
4137 for (; lr != NULL; lr = lr->next) {
4138 check_i(&ops[i], lr->i);
4139 ret |= adjust_prev_op(lr->i, op, magic, datap);
4141 if (i > 0 && LAST_OP(i - 1))
4149 if (ops[i].cc_scratch == magic)
4151 ops[i].cc_scratch = magic;
4153 if (ops[i].op != op)
4156 ops[i].datap = datap;
4161 // find next instruction that reads opr
4162 // *op_i must be set to -1 by the caller
4163 // on return, *op_i is set to first referencer insn
4164 // returns 1 if exactly 1 referencer is found
4165 static int find_next_read(int i, int opcnt,
4166 const struct parsed_opr *opr, int magic, int *op_i)
4168 struct parsed_op *po;
4171 for (; i < opcnt; i++)
4173 if (ops[i].cc_scratch == magic)
4175 ops[i].cc_scratch = magic;
4178 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4179 if (po->btj != NULL) {
4181 for (j = 0; j < po->btj->count; j++) {
4182 check_i(po, po->btj->d[j].bt_i);
4183 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4189 if (po->flags & OPF_RMD)
4191 check_i(po, po->bt_i);
4192 if (po->flags & OPF_CJMP) {
4193 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4202 if (!is_opr_read(opr, po)) {
4204 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4205 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4207 full_opr = po->operand[0].lmod >= opr->lmod;
4209 if (is_opr_modified(opr, po) && full_opr) {
4213 if (po->flags & OPF_TAIL)
4228 // find next instruction that reads opr
4229 // *op_i must be set to -1 by the caller
4230 // on return, *op_i is set to first flag user insn
4231 // returns 1 if exactly 1 flag user is found
4232 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4234 struct parsed_op *po;
4237 for (; i < opcnt; i++)
4239 if (ops[i].cc_scratch == magic)
4241 ops[i].cc_scratch = magic;
4244 if (po->op == OP_CALL)
4246 if (po->flags & OPF_JMP) {
4247 if (po->btj != NULL) {
4249 for (j = 0; j < po->btj->count; j++) {
4250 check_i(po, po->btj->d[j].bt_i);
4251 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4257 if (po->flags & OPF_RMD)
4259 check_i(po, po->bt_i);
4260 if (po->flags & OPF_CJMP)
4267 if (!(po->flags & OPF_CC)) {
4268 if (po->flags & OPF_FLAGS)
4271 if (po->flags & OPF_TAIL)
4287 static int try_resolve_const(int i, const struct parsed_opr *opr,
4288 int magic, unsigned int *val)
4293 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4296 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4299 *val = ops[i].operand[1].val;
4306 static int resolve_used_bits(int i, int opcnt, int reg,
4307 int *mask, int *is_z_check)
4309 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4313 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4317 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4319 fnote(&ops[j], "(first read)\n");
4320 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4323 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4324 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4326 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4327 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4329 *mask = ops[j].operand[1].val;
4330 if (ops[j].operand[0].lmod == OPLM_BYTE
4331 && ops[j].operand[0].name[1] == 'h')
4335 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4338 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4340 *is_z_check = ops[k].pfo == PFO_Z;
4345 static const struct parsed_proto *resolve_deref(int i, int magic,
4346 struct parsed_opr *opr, int level)
4348 struct parsed_opr opr_s = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
4349 const struct parsed_proto *pp = NULL;
4350 int from_caller = 0;
4359 ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4360 if (ret != 2 || len != strlen(opr->name)) {
4361 ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4362 if (ret != 1 || len != strlen(opr->name))
4366 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4371 ret = resolve_origin(i, &opr_s, i + magic, &j, NULL);
4375 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4376 && strlen(ops[j].operand[1].name) == 3
4377 && ops[j].operand[0].lmod == OPLM_DWORD
4378 && ops[j].pp == NULL // no hint
4381 // allow one simple dereference (com/directx)
4382 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4383 ops[j].operand[1].name);
4387 ret = resolve_origin(j, &opr_s, j + magic, &k, NULL);
4392 if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
4395 if (ops[j].pp != NULL) {
4399 else if (ops[j].operand[1].type == OPT_REGMEM) {
4400 pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
4402 // maybe structure ptr in structure
4403 pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
4406 else if (ops[j].operand[1].type == OPT_LABEL)
4407 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4408 else if (ops[j].operand[1].type == OPT_REG) {
4411 ret = resolve_origin(j, &ops[j].operand[1], i + magic,
4413 if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
4414 for (k = 0; k < g_func_pp->argc; k++) {
4415 if (g_func_pp->arg[k].reg == NULL)
4417 if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
4418 pp = g_func_pp->arg[k].pp;
4427 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4429 ferr(&ops[j], "expected struct, got '%s %s'\n",
4430 pp->type.name, pp->name);
4434 return proto_lookup_struct(g_fhdr, pp->type.name, offset);
4437 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4438 int *pp_i, int *multi_src)
4440 const struct parsed_proto *pp = NULL;
4441 int search_advice = 0;
4446 switch (ops[i].operand[0].type) {
4448 // try to resolve struct member calls
4449 pp = resolve_deref(i, i + opcnt * 19, &ops[i].operand[0], 0);
4455 pp = try_recover_pp(&ops[i], &ops[i].operand[0],
4461 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4469 static struct parsed_proto *process_call_early(int i, int opcnt,
4472 struct parsed_op *po = &ops[i];
4473 struct parsed_proto *pp;
4479 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4483 // look for and make use of esp adjust
4485 if (!pp->is_stdcall && pp->argc_stack > 0)
4486 ret = scan_for_esp_adjust(i + 1, opcnt,
4487 pp->argc_stack * 4, &adj, &multipath, 0);
4489 if (pp->argc_stack > adj / 4)
4493 if (ops[ret].op == OP_POP) {
4494 for (j = 1; j < adj / 4; j++) {
4495 if (ops[ret + j].op != OP_POP
4496 || ops[ret + j].operand[0].reg != xCX)
4508 static struct parsed_proto *process_call(int i, int opcnt)
4510 struct parsed_op *po = &ops[i];
4511 const struct parsed_proto *pp_c;
4512 struct parsed_proto *pp;
4513 const char *tmpname;
4514 int call_i = -1, ref_i = -1;
4515 int adj = 0, multipath = 0;
4518 tmpname = opr_name(po, 0);
4523 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4525 if (!pp_c->is_func && !pp_c->is_fptr)
4526 ferr(po, "call to non-func: %s\n", pp_c->name);
4527 pp = proto_clone(pp_c);
4528 my_assert_not(pp, NULL);
4530 // not resolved just to single func
4533 switch (po->operand[0].type) {
4535 // we resolved this call and no longer need the register
4536 po->regmask_src &= ~(1 << po->operand[0].reg);
4538 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4539 && ops[call_i].operand[1].type == OPT_LABEL)
4541 // no other source users?
4542 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4544 if (ret == 1 && call_i == ref_i) {
4545 // and nothing uses it after us?
4547 find_next_read(i + 1, opcnt, &po->operand[0],
4548 i + opcnt * 11, &ref_i);
4550 // then also don't need the source mov
4551 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4563 pp = calloc(1, sizeof(*pp));
4564 my_assert_not(pp, NULL);
4567 ret = scan_for_esp_adjust(i + 1, opcnt,
4568 -1, &adj, &multipath, 0);
4569 if (ret < 0 || adj < 0) {
4570 if (!g_allow_regfunc)
4571 ferr(po, "non-__cdecl indirect call unhandled yet\n");
4572 pp->is_unresolved = 1;
4576 if (adj > ARRAY_SIZE(pp->arg))
4577 ferr(po, "esp adjust too large: %d\n", adj);
4578 pp->ret_type.name = strdup("int");
4579 pp->argc = pp->argc_stack = adj;
4580 for (arg = 0; arg < pp->argc; arg++)
4581 pp->arg[arg].type.name = strdup("int");
4586 // look for and make use of esp adjust
4589 if (!pp->is_stdcall && pp->argc_stack > 0) {
4590 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
4591 ret = scan_for_esp_adjust(i + 1, opcnt,
4592 adj_expect, &adj, &multipath, 0);
4595 if (pp->is_vararg) {
4596 if (adj / 4 < pp->argc_stack) {
4597 fnote(po, "(this call)\n");
4598 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
4599 adj, pp->argc_stack * 4);
4601 // modify pp to make it have varargs as normal args
4603 pp->argc += adj / 4 - pp->argc_stack;
4604 for (; arg < pp->argc; arg++) {
4605 pp->arg[arg].type.name = strdup("int");
4608 if (pp->argc > ARRAY_SIZE(pp->arg))
4609 ferr(po, "too many args for '%s'\n", tmpname);
4611 if (pp->argc_stack > adj / 4) {
4612 fnote(po, "(this call)\n");
4613 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
4614 tmpname, pp->argc_stack * 4, adj);
4617 scan_for_esp_adjust(i + 1, opcnt,
4618 pp->argc_stack * 4, &adj, &multipath, 1);
4620 else if (pp->is_vararg)
4621 ferr(po, "missing esp_adjust for vararg func '%s'\n",
4627 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
4630 struct parsed_op *po;
4636 for (base_arg = 0; base_arg < pp->argc; base_arg++)
4637 if (pp->arg[base_arg].reg == NULL)
4640 for (j = i; j > 0; )
4642 ferr_assert(&ops[j], g_labels[j] == NULL);
4646 ferr_assert(po, po->op != OP_PUSH);
4647 if (po->op == OP_FST)
4649 if (po->operand[0].type != OPT_REGMEM)
4651 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
4654 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3))
4655 ferr(po, "bad offset %d (%d args)\n", offset, pp->argc_stack);
4657 arg = base_arg + offset / 4;
4659 po->p_argnum = arg + 1;
4660 ferr_assert(po, pp->arg[arg].datap == NULL);
4661 pp->arg[arg].datap = po;
4662 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
4663 if (regmask_ffca != NULL)
4664 *regmask_ffca |= 1 << arg;
4666 else if (po->op == OP_SUB && po->operand[0].reg == xSP
4667 && po->operand[1].type == OPT_CONST)
4669 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4674 for (arg = base_arg; arg < pp->argc; arg++) {
4675 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
4676 po = pp->arg[arg].datap;
4678 ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
4679 if (po->operand[0].lmod == OPLM_QWORD)
4686 static int collect_call_args_early(int i, struct parsed_proto *pp,
4687 int *regmask, int *regmask_ffca)
4689 struct parsed_op *po;
4693 for (arg = 0; arg < pp->argc; arg++)
4694 if (pp->arg[arg].reg == NULL)
4697 // first see if it can be easily done
4698 for (j = i; j > 0 && arg < pp->argc; )
4700 if (g_labels[j] != NULL)
4705 if (po->op == OP_CALL)
4707 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
4709 else if (po->op == OP_POP)
4711 else if (po->flags & OPF_CJMP)
4713 else if (po->op == OP_PUSH) {
4714 if (po->flags & (OPF_FARG|OPF_FARGNR))
4716 if (!g_header_mode) {
4717 ret = scan_for_mod(po, j + 1, i, 1);
4722 if (pp->arg[arg].type.is_va_list)
4726 for (arg++; arg < pp->argc; arg++)
4727 if (pp->arg[arg].reg == NULL)
4730 else if (po->op == OP_SUB && po->operand[0].reg == xSP
4731 && po->operand[1].type == OPT_CONST)
4733 if (po->flags & (OPF_RMD|OPF_DONE))
4735 if (po->operand[1].val != pp->argc_stack * 4)
4736 ferr(po, "unexpected esp adjust: %d\n",
4737 po->operand[1].val * 4);
4738 ferr_assert(po, pp->argc - arg == pp->argc_stack);
4739 return collect_call_args_no_push(i, pp, regmask_ffca);
4747 for (arg = 0; arg < pp->argc; arg++)
4748 if (pp->arg[arg].reg == NULL)
4751 for (j = i; j > 0 && arg < pp->argc; )
4755 if (ops[j].op == OP_PUSH)
4757 ops[j].p_argnext = -1;
4758 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
4759 pp->arg[arg].datap = &ops[j];
4761 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
4762 *regmask |= 1 << ops[j].operand[0].reg;
4764 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4765 ops[j].flags &= ~OPF_RSAVE;
4768 for (arg++; arg < pp->argc; arg++)
4769 if (pp->arg[arg].reg == NULL)
4777 static int collect_call_args_r(struct parsed_op *po, int i,
4778 struct parsed_proto *pp, int *regmask, int *save_arg_vars,
4779 int *arg_grp, int arg, int magic, int need_op_saving, int may_reuse)
4781 struct parsed_proto *pp_tmp;
4782 struct parsed_op *po_tmp;
4783 struct label_ref *lr;
4784 int need_to_save_current;
4785 int arg_grp_current = 0;
4786 int save_args_seen = 0;
4794 ferr(po, "dead label encountered\n");
4798 for (; arg < pp->argc; arg++)
4799 if (pp->arg[arg].reg == NULL)
4801 magic = (magic & 0xffffff) | (arg << 24);
4803 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
4805 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
4806 if (ops[j].cc_scratch != magic) {
4807 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
4811 // ok: have already been here
4814 ops[j].cc_scratch = magic;
4816 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
4817 lr = &g_label_refs[j];
4818 if (lr->next != NULL)
4820 for (; lr->next; lr = lr->next) {
4821 check_i(&ops[j], lr->i);
4822 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4824 ret = collect_call_args_r(po, lr->i, pp, regmask, save_arg_vars,
4825 arg_grp, arg, magic, need_op_saving, may_reuse);
4830 check_i(&ops[j], lr->i);
4831 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4833 if (j > 0 && LAST_OP(j - 1)) {
4834 // follow last branch in reverse
4839 ret = collect_call_args_r(po, lr->i, pp, regmask, save_arg_vars,
4840 arg_grp, arg, magic, need_op_saving, may_reuse);
4846 if (ops[j].op == OP_CALL)
4848 if (pp->is_unresolved)
4853 ferr(po, "arg collect hit unparsed call '%s'\n",
4854 ops[j].operand[0].name);
4855 if (may_reuse && pp_tmp->argc_stack > 0)
4856 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
4857 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
4859 // esp adjust of 0 means we collected it before
4860 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
4861 && (ops[j].operand[1].type != OPT_CONST
4862 || ops[j].operand[1].val != 0))
4864 if (pp->is_unresolved)
4867 fnote(po, "(this call)\n");
4868 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
4869 arg, pp->argc, ops[j].operand[1].val);
4871 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
4873 if (pp->is_unresolved)
4876 fnote(po, "(this call)\n");
4877 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
4879 else if (ops[j].flags & OPF_CJMP)
4881 if (pp->is_unresolved)
4886 else if (ops[j].op == OP_PUSH
4887 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
4889 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
4892 ops[j].p_argnext = -1;
4893 po_tmp = pp->arg[arg].datap;
4895 ops[j].p_argnext = po_tmp - ops;
4896 pp->arg[arg].datap = &ops[j];
4898 need_to_save_current = 0;
4901 if (ops[j].operand[0].type == OPT_REG)
4902 reg = ops[j].operand[0].reg;
4904 if (!need_op_saving) {
4905 ret = scan_for_mod(&ops[j], j + 1, i, 1);
4906 need_to_save_current = (ret >= 0);
4908 if (need_op_saving || need_to_save_current) {
4909 // mark this push as one that needs operand saving
4910 ops[j].flags &= ~OPF_RMD;
4911 if (ops[j].p_argnum == 0) {
4912 ops[j].p_argnum = arg + 1;
4913 save_args |= 1 << arg;
4915 else if (ops[j].p_argnum < arg + 1) {
4916 // XXX: might kill valid var..
4917 //*save_arg_vars &= ~(1 << (ops[j].p_argnum - 1));
4918 ops[j].p_argnum = arg + 1;
4919 save_args |= 1 << arg;
4922 if (save_args_seen & (1 << (ops[j].p_argnum - 1))) {
4925 if (arg_grp_current >= MAX_ARG_GRP)
4926 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
4927 ops[j].p_argnum, pp->name);
4930 else if (ops[j].p_argnum == 0)
4931 ops[j].flags |= OPF_RMD;
4933 // some PUSHes are reused by different calls on other branches,
4934 // but that can't happen if we didn't branch, so they
4935 // can be removed from future searches (handles nested calls)
4937 ops[j].flags |= OPF_FARGNR;
4939 ops[j].flags |= OPF_FARG;
4940 ops[j].flags &= ~OPF_RSAVE;
4942 // check for __VALIST
4943 if (!pp->is_unresolved && g_func_pp != NULL
4944 && pp->arg[arg].type.is_va_list)
4947 ret = resolve_origin(j, &ops[j].operand[0],
4948 magic + 1, &k, NULL);
4949 if (ret == 1 && k >= 0)
4951 if (ops[k].op == OP_LEA) {
4952 if (!g_func_pp->is_vararg)
4953 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
4956 snprintf(buf, sizeof(buf), "arg_%X",
4957 g_func_pp->argc_stack * 4);
4958 if (strstr(ops[k].operand[1].name, buf)
4959 || strstr(ops[k].operand[1].name, "arglist"))
4961 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
4962 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
4963 save_args &= ~(1 << arg);
4967 ferr(&ops[k], "va_list arg detection failed\n");
4969 // check for va_list from g_func_pp arg too
4970 else if (ops[k].op == OP_MOV
4971 && is_stack_access(&ops[k], &ops[k].operand[1]))
4973 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
4974 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
4976 ops[k].flags |= OPF_RMD | OPF_DONE;
4977 ops[j].flags |= OPF_RMD;
4978 ops[j].p_argpass = ret + 1;
4979 save_args &= ~(1 << arg);
4986 *save_arg_vars |= save_args;
4988 // tracking reg usage
4990 *regmask |= 1 << reg;
4993 if (!pp->is_unresolved) {
4995 for (; arg < pp->argc; arg++)
4996 if (pp->arg[arg].reg == NULL)
4999 magic = (magic & 0xffffff) | (arg << 24);
5002 if (ops[j].p_arggrp > arg_grp_current) {
5004 arg_grp_current = ops[j].p_arggrp;
5006 if (ops[j].p_argnum > 0)
5007 save_args_seen |= 1 << (ops[j].p_argnum - 1);
5010 if (arg < pp->argc) {
5011 ferr(po, "arg collect failed for '%s': %d/%d\n",
5012 pp->name, arg, pp->argc);
5016 if (arg_grp_current > *arg_grp)
5017 *arg_grp = arg_grp_current;
5022 static int collect_call_args(struct parsed_op *po, int i,
5023 struct parsed_proto *pp, int *regmask, int *save_arg_vars,
5026 // arg group is for cases when pushes for
5027 // multiple funcs are going on
5028 struct parsed_op *po_tmp;
5029 int save_arg_vars_current = 0;
5034 ret = collect_call_args_r(po, i, pp, regmask,
5035 &save_arg_vars_current, &arg_grp, 0, magic, 0, 0);
5040 // propagate arg_grp
5041 for (a = 0; a < pp->argc; a++) {
5042 if (pp->arg[a].reg != NULL)
5045 po_tmp = pp->arg[a].datap;
5046 while (po_tmp != NULL) {
5047 po_tmp->p_arggrp = arg_grp;
5048 if (po_tmp->p_argnext > 0)
5049 po_tmp = &ops[po_tmp->p_argnext];
5055 save_arg_vars[arg_grp] |= save_arg_vars_current;
5057 if (pp->is_unresolved) {
5059 pp->argc_stack += ret;
5060 for (a = 0; a < pp->argc; a++)
5061 if (pp->arg[a].type.name == NULL)
5062 pp->arg[a].type.name = strdup("int");
5068 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5069 int regmask_now, int *regmask,
5070 int regmask_save_now, int *regmask_save,
5071 int *regmask_init, int regmask_arg)
5073 struct parsed_op *po;
5081 for (; i < opcnt; i++)
5084 if (cbits[i >> 3] & (1 << (i & 7)))
5086 cbits[i >> 3] |= (1 << (i & 7));
5088 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5089 if (po->flags & (OPF_RMD|OPF_DONE))
5091 if (po->btj != NULL) {
5092 for (j = 0; j < po->btj->count; j++) {
5093 check_i(po, po->btj->d[j].bt_i);
5094 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5095 regmask_now, regmask, regmask_save_now, regmask_save,
5096 regmask_init, regmask_arg);
5101 check_i(po, po->bt_i);
5102 if (po->flags & OPF_CJMP)
5103 reg_use_pass(po->bt_i, opcnt, cbits,
5104 regmask_now, regmask, regmask_save_now, regmask_save,
5105 regmask_init, regmask_arg);
5111 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5112 && !g_func_pp->is_userstack
5113 && po->operand[0].type == OPT_REG)
5115 reg = po->operand[0].reg;
5116 ferr_assert(po, reg >= 0);
5119 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5120 if (regmask_now & (1 << reg)) {
5121 already_saved = regmask_save_now & (1 << reg);
5122 flags_set = OPF_RSAVE | OPF_DONE;
5125 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, 0);
5127 scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5128 reg, 0, 0, flags_set);
5131 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5133 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5138 ferr_assert(po, !already_saved);
5139 po->flags |= flags_set;
5141 if (regmask_now & (1 << reg)) {
5142 regmask_save_now |= (1 << reg);
5143 *regmask_save |= regmask_save_now;
5148 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5149 reg = po->operand[0].reg;
5150 ferr_assert(po, reg >= 0);
5152 if (regmask_save_now & (1 << reg))
5153 regmask_save_now &= ~(1 << reg);
5155 regmask_now &= ~(1 << reg);
5158 else if (po->op == OP_CALL) {
5159 if ((po->regmask_dst & (1 << xAX))
5160 && !(po->regmask_dst & (1 << xDX)))
5162 if (po->flags & OPF_TAIL)
5163 // don't need eax, will do "return f();" or "f(); return;"
5164 po->regmask_dst &= ~(1 << xAX);
5166 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
5168 find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
5171 po->regmask_dst &= ~(1 << xAX);
5175 // not "full stack" mode and have something in stack
5176 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5177 ferr(po, "float stack is not empty on func call\n");
5180 if (po->flags & OPF_NOREGS)
5183 // if incomplete register is used, clear it on init to avoid
5184 // later use of uninitialized upper part in some situations
5185 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5186 && po->operand[0].lmod != OPLM_DWORD)
5188 reg = po->operand[0].reg;
5189 ferr_assert(po, reg >= 0);
5191 if (!(regmask_now & (1 << reg)))
5192 *regmask_init |= 1 << reg;
5195 regmask_op = po->regmask_src | po->regmask_dst;
5197 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5198 regmask_new &= ~(1 << xSP);
5199 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5200 regmask_new &= ~(1 << xBP);
5202 if (regmask_new != 0)
5203 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5205 if (regmask_op & (1 << xBP)) {
5206 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5207 if (po->regmask_dst & (1 << xBP))
5208 // compiler decided to drop bp frame and use ebp as scratch
5209 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5211 regmask_op &= ~(1 << xBP);
5215 if (po->flags & OPF_FPUSH) {
5216 if (regmask_now & mxST1)
5217 regmask_now |= mxSTa; // switch to "full stack" mode
5218 if (regmask_now & mxSTa)
5219 po->flags |= OPF_FSHIFT;
5220 if (!(regmask_now & mxST7_2)) {
5222 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5226 regmask_now |= regmask_op;
5227 *regmask |= regmask_now;
5230 if (po->flags & OPF_FPOP) {
5231 if ((regmask_now & mxSTa) == 0)
5232 ferr(po, "float pop on empty stack?\n");
5233 if (regmask_now & (mxST7_2 | mxST1))
5234 po->flags |= OPF_FSHIFT;
5235 if (!(regmask_now & mxST7_2)) {
5237 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5241 if (po->flags & OPF_TAIL) {
5242 if (!(regmask_now & mxST7_2)) {
5243 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5244 if (!(regmask_now & mxST0))
5245 ferr(po, "no st0 on float return, mask: %x\n",
5248 else if (regmask_now & mxST1_0)
5249 ferr(po, "float regs on tail: %x\n", regmask_now);
5252 // there is support for "conditional tailcall", sort of
5253 if (!(po->flags & OPF_CC))
5259 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5263 for (i = 0; i < pp->argc; i++)
5264 if (pp->arg[i].reg == NULL)
5268 memmove(&pp->arg[i + 1], &pp->arg[i],
5269 sizeof(pp->arg[0]) * pp->argc_stack);
5270 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5271 pp->arg[i].reg = strdup(reg);
5272 pp->arg[i].type.name = strdup("int");
5277 static void output_std_flags(FILE *fout, struct parsed_op *po,
5278 int *pfomask, const char *dst_opr_text)
5280 if (*pfomask & (1 << PFO_Z)) {
5281 fprintf(fout, "\n cond_z = (%s%s == 0);",
5282 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5283 *pfomask &= ~(1 << PFO_Z);
5285 if (*pfomask & (1 << PFO_S)) {
5286 fprintf(fout, "\n cond_s = (%s%s < 0);",
5287 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5288 *pfomask &= ~(1 << PFO_S);
5293 OPP_FORCE_NORETURN = (1 << 0),
5294 OPP_SIMPLE_ARGS = (1 << 1),
5295 OPP_ALIGN = (1 << 2),
5298 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
5301 const char *cconv = "";
5303 if (pp->is_fastcall)
5304 cconv = "__fastcall ";
5305 else if (pp->is_stdcall && pp->argc_reg == 0)
5306 cconv = "__stdcall ";
5308 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5310 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
5311 fprintf(fout, "noreturn ");
5314 static void output_pp(FILE *fout, const struct parsed_proto *pp,
5319 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5323 output_pp_attrs(fout, pp, flags);
5326 fprintf(fout, "%s", pp->name);
5331 for (i = 0; i < pp->argc; i++) {
5333 fprintf(fout, ", ");
5334 if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
5335 && !(flags & OPP_SIMPLE_ARGS))
5338 output_pp(fout, pp->arg[i].pp, 0);
5340 else if (pp->arg[i].type.is_retreg) {
5341 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
5344 fprintf(fout, "%s", pp->arg[i].type.name);
5346 fprintf(fout, " a%d", i + 1);
5349 if (pp->is_vararg) {
5351 fprintf(fout, ", ");
5352 fprintf(fout, "...");
5357 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
5363 snprintf(buf1, sizeof(buf1), "%d", grp);
5364 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
5369 static void gen_x_cleanup(int opcnt);
5371 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
5373 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
5374 struct parsed_opr *last_arith_dst = NULL;
5375 char buf1[256], buf2[256], buf3[256], cast[64];
5376 struct parsed_proto *pp, *pp_tmp;
5377 struct parsed_data *pd;
5378 int save_arg_vars[MAX_ARG_GRP] = { 0, };
5379 unsigned char cbits[MAX_OPS / 8];
5380 const char *float_type;
5381 const char *float_st0;
5382 const char *float_st1;
5383 int need_float_stack = 0;
5384 int need_float_sw = 0; // status word
5385 int need_tmp_var = 0;
5389 int label_pending = 0;
5390 int need_double = 0;
5391 int regmask_save = 0; // used regs saved/restored in this func
5392 int regmask_arg; // regs from this function args (fastcall, etc)
5393 int regmask_ret; // regs needed on ret
5394 int regmask_now; // temp
5395 int regmask_init = 0; // regs that need zero initialization
5396 int regmask_pp = 0; // regs used in complex push-pop graph
5397 int regmask_ffca = 0; // float function call args
5398 int regmask = 0; // used regs
5408 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
5409 g_stack_frame_used = 0;
5410 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
5411 regmask_init = g_regmask_init;
5413 g_func_pp = proto_parse(fhdr, funcn, 0);
5414 if (g_func_pp == NULL)
5415 ferr(ops, "proto_parse failed for '%s'\n", funcn);
5417 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
5418 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
5421 // - resolve all branches
5422 // - parse calls with labels
5423 resolve_branches_parse_calls(opcnt);
5426 // - handle ebp/esp frame, remove ops related to it
5427 scan_prologue_epilogue(opcnt);
5430 // - remove dead labels
5431 // - set regs needed at ret
5432 for (i = 0; i < opcnt; i++)
5434 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
5439 if (ops[i].op == OP_RET)
5440 ops[i].regmask_src |= regmask_ret;
5444 // - process trivial calls
5445 for (i = 0; i < opcnt; i++)
5448 if (po->flags & (OPF_RMD|OPF_DONE))
5451 if (po->op == OP_CALL)
5453 pp = process_call_early(i, opcnt, &j);
5455 if (!(po->flags & OPF_ATAIL)) {
5456 // since we know the args, try to collect them
5457 ret = collect_call_args_early(i, pp, ®mask, ®mask_ffca);
5465 // commit esp adjust
5466 if (ops[j].op != OP_POP)
5467 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5469 for (l = 0; l < pp->argc_stack; l++)
5470 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
5474 if (strstr(pp->ret_type.name, "int64"))
5477 po->flags |= OPF_DONE;
5483 // - process calls, stage 2
5484 // - handle some push/pop pairs
5485 // - scan for STD/CLD, propagate DF
5486 // - try to resolve needed x87 status word bits
5487 for (i = 0; i < opcnt; i++)
5492 if (po->flags & OPF_RMD)
5495 if (po->op == OP_CALL)
5497 if (!(po->flags & OPF_DONE)) {
5498 pp = process_call(i, opcnt);
5500 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
5501 // since we know the args, collect them
5502 collect_call_args(po, i, pp, ®mask, save_arg_vars,
5505 // for unresolved, collect after other passes
5509 ferr_assert(po, pp != NULL);
5511 po->regmask_src |= get_pp_arg_regmask_src(pp);
5512 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
5514 if (po->regmask_dst & mxST0)
5515 po->flags |= OPF_FPUSH;
5517 if (strstr(pp->ret_type.name, "int64"))
5523 if (po->flags & OPF_DONE)
5528 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
5529 && po->operand[0].type == OPT_CONST)
5531 scan_for_pop_const(i, opcnt, i + opcnt * 12);
5536 scan_pushes_for_pop(i, opcnt, ®mask_pp);
5540 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
5541 scan_propagate_df(i + 1, opcnt);
5546 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
5547 ferr(po, "TODO: fnstsw to mem\n");
5548 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
5550 ferr(po, "fnstsw resolve failed\n");
5551 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
5552 (void *)(long)(mask | (z_check << 16)));
5554 ferr(po, "failed to find fcom: %d\n", ret);
5563 // - find POPs for PUSHes, rm both
5564 // - scan for all used registers
5565 memset(cbits, 0, sizeof(cbits));
5566 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
5567 0, ®mask_save, ®mask_init, regmask_arg);
5570 // - find flag set ops for their users
5571 // - do unresolved calls
5572 // - declare indirect functions
5573 // - other op specific processing
5574 for (i = 0; i < opcnt; i++)
5577 if (po->flags & (OPF_RMD|OPF_DONE))
5580 if (po->flags & OPF_CC)
5582 int setters[16], cnt = 0, branched = 0;
5584 ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
5585 &branched, setters, &cnt);
5586 if (ret < 0 || cnt <= 0)
5587 ferr(po, "unable to trace flag setter(s)\n");
5588 if (cnt > ARRAY_SIZE(setters))
5589 ferr(po, "too many flag setters\n");
5591 for (j = 0; j < cnt; j++)
5593 tmp_op = &ops[setters[j]]; // flag setter
5596 // to get nicer code, we try to delay test and cmp;
5597 // if we can't because of operand modification, or if we
5598 // have arith op, or branch, make it calculate flags explicitly
5599 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
5601 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
5602 pfomask = 1 << po->pfo;
5604 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
5605 pfomask = 1 << po->pfo;
5608 // see if we'll be able to handle based on op result
5609 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
5610 && po->pfo != PFO_Z && po->pfo != PFO_S
5611 && po->pfo != PFO_P)
5613 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
5615 pfomask = 1 << po->pfo;
5618 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
5619 propagate_lmod(tmp_op, &tmp_op->operand[0],
5620 &tmp_op->operand[1]);
5621 if (tmp_op->operand[0].lmod == OPLM_DWORD)
5626 tmp_op->pfomask |= pfomask;
5627 cond_vars |= pfomask;
5629 // note: may overwrite, currently not a problem
5633 if (po->op == OP_RCL || po->op == OP_RCR
5634 || po->op == OP_ADC || po->op == OP_SBB)
5635 cond_vars |= 1 << PFO_C;
5641 cond_vars |= 1 << PFO_Z;
5645 if (po->operand[0].lmod == OPLM_DWORD)
5650 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
5655 // note: resolved non-reg calls are OPF_DONE already
5657 ferr_assert(po, pp != NULL);
5659 if (pp->is_unresolved) {
5660 int regmask_stack = 0;
5661 collect_call_args(po, i, pp, ®mask, save_arg_vars,
5664 // this is pretty rough guess:
5665 // see ecx and edx were pushed (and not their saved versions)
5666 for (arg = 0; arg < pp->argc; arg++) {
5667 if (pp->arg[arg].reg != NULL)
5670 tmp_op = pp->arg[arg].datap;
5672 ferr(po, "parsed_op missing for arg%d\n", arg);
5673 if (tmp_op->p_argnum == 0 && tmp_op->operand[0].type == OPT_REG)
5674 regmask_stack |= 1 << tmp_op->operand[0].reg;
5677 if (!((regmask_stack & (1 << xCX))
5678 && (regmask_stack & (1 << xDX))))
5680 if (pp->argc_stack != 0
5681 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
5683 pp_insert_reg_arg(pp, "ecx");
5684 pp->is_fastcall = 1;
5685 regmask_init |= 1 << xCX;
5686 regmask |= 1 << xCX;
5688 if (pp->argc_stack != 0
5689 || ((regmask | regmask_arg) & (1 << xDX)))
5691 pp_insert_reg_arg(pp, "edx");
5692 regmask_init |= 1 << xDX;
5693 regmask |= 1 << xDX;
5697 // note: __cdecl doesn't fall into is_unresolved category
5698 if (pp->argc_stack > 0)
5704 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
5706 // <var> = offset <something>
5707 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
5708 && !IS_START(po->operand[1].name, "off_"))
5710 if (!po->operand[0].pp->is_fptr)
5711 ferr(po, "%s not declared as fptr when it should be\n",
5712 po->operand[0].name);
5713 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
5714 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
5715 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
5716 fnote(po, "var: %s\n", buf1);
5717 fnote(po, "func: %s\n", buf2);
5718 ferr(po, "^ mismatch\n");
5726 if (po->operand[0].lmod == OPLM_DWORD) {
5727 // 32bit division is common, look for it
5728 if (po->op == OP_DIV)
5729 ret = scan_for_reg_clear(i, xDX);
5731 ret = scan_for_cdq_edx(i);
5733 po->flags |= OPF_32BIT;
5742 po->flags |= OPF_RMD | OPF_DONE;
5752 if (po->operand[0].lmod == OPLM_QWORD)
5762 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
5764 find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
5766 po->flags |= OPF_32BIT;
5775 float_type = need_double ? "double" : "float";
5776 need_float_stack = !!(regmask & mxST7_2);
5777 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
5778 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
5780 // output starts here
5782 // define userstack size
5783 if (g_func_pp->is_userstack) {
5784 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
5785 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
5786 fprintf(fout, "#endif\n");
5789 // the function itself
5790 ferr_assert(ops, !g_func_pp->is_fptr);
5791 output_pp(fout, g_func_pp,
5792 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
5793 fprintf(fout, "\n{\n");
5795 // declare indirect functions
5796 for (i = 0; i < opcnt; i++) {
5798 if (po->flags & OPF_RMD)
5801 if (po->op == OP_CALL) {
5804 ferr(po, "NULL pp\n");
5806 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
5807 if (pp->name[0] != 0) {
5808 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
5809 memcpy(pp->name, "i_", 2);
5811 // might be declared already
5813 for (j = 0; j < i; j++) {
5814 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
5815 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
5825 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
5828 output_pp(fout, pp, OPP_SIMPLE_ARGS);
5829 fprintf(fout, ";\n");
5834 // output LUTs/jumptables
5835 for (i = 0; i < g_func_pd_cnt; i++) {
5837 fprintf(fout, " static const ");
5838 if (pd->type == OPT_OFFSET) {
5839 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
5841 for (j = 0; j < pd->count; j++) {
5843 fprintf(fout, ", ");
5844 fprintf(fout, "&&%s", pd->d[j].u.label);
5848 fprintf(fout, "%s %s[] =\n { ",
5849 lmod_type_u(ops, pd->lmod), pd->label);
5851 for (j = 0; j < pd->count; j++) {
5853 fprintf(fout, ", ");
5854 fprintf(fout, "%u", pd->d[j].u.val);
5857 fprintf(fout, " };\n");
5861 // declare stack frame, va_arg
5863 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
5864 if (g_func_lmods & (1 << OPLM_WORD))
5865 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
5866 if (g_func_lmods & (1 << OPLM_BYTE))
5867 fprintf(fout, " u8 b[%d];", g_stack_fsz);
5868 if (g_func_lmods & (1 << OPLM_QWORD))
5869 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
5870 fprintf(fout, " } sf;\n");
5874 if (g_func_pp->is_userstack) {
5875 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
5876 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
5880 if (g_func_pp->is_vararg) {
5881 fprintf(fout, " va_list ap;\n");
5885 // declare arg-registers
5886 for (i = 0; i < g_func_pp->argc; i++) {
5887 if (g_func_pp->arg[i].reg != NULL) {
5888 reg = char_array_i(regs_r32,
5889 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
5890 if (regmask & (1 << reg)) {
5891 if (g_func_pp->arg[i].type.is_retreg)
5892 fprintf(fout, " u32 %s = *r_%s;\n",
5893 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
5895 fprintf(fout, " u32 %s = (u32)a%d;\n",
5896 g_func_pp->arg[i].reg, i + 1);
5899 if (g_func_pp->arg[i].type.is_retreg)
5900 ferr(ops, "retreg '%s' is unused?\n",
5901 g_func_pp->arg[i].reg);
5902 fprintf(fout, " // %s = a%d; // unused\n",
5903 g_func_pp->arg[i].reg, i + 1);
5909 // declare normal registers
5910 regmask_now = regmask & ~regmask_arg;
5911 regmask_now &= ~(1 << xSP);
5912 if (regmask_now & 0x00ff) {
5913 for (reg = 0; reg < 8; reg++) {
5914 if (regmask_now & (1 << reg)) {
5915 fprintf(fout, " u32 %s", regs_r32[reg]);
5916 if (regmask_init & (1 << reg))
5917 fprintf(fout, " = 0");
5918 fprintf(fout, ";\n");
5924 if (regmask_now & 0xff00) {
5925 for (reg = 8; reg < 16; reg++) {
5926 if (regmask_now & (1 << reg)) {
5927 fprintf(fout, " mmxr %s", regs_r32[reg]);
5928 if (regmask_init & (1 << reg))
5929 fprintf(fout, " = { 0, }");
5930 fprintf(fout, ";\n");
5936 if (need_float_stack) {
5937 fprintf(fout, " %s f_st[8];\n", float_type);
5938 fprintf(fout, " int f_stp = 0;\n");
5942 if (regmask_now & 0xff0000) {
5943 for (reg = 16; reg < 24; reg++) {
5944 if (regmask_now & (1 << reg)) {
5945 fprintf(fout, " %s f_st%d", float_type, reg - 16);
5946 if (regmask_init & (1 << reg))
5947 fprintf(fout, " = 0");
5948 fprintf(fout, ";\n");
5955 if (need_float_sw) {
5956 fprintf(fout, " u16 f_sw;\n");
5961 for (reg = 0; reg < 8; reg++) {
5962 if (regmask_save & (1 << reg)) {
5963 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
5969 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
5970 if (save_arg_vars[i] == 0)
5972 for (reg = 0; reg < 32; reg++) {
5973 if (save_arg_vars[i] & (1 << reg)) {
5974 fprintf(fout, " u32 %s;\n",
5975 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
5982 for (reg = 0; reg < 32; reg++) {
5983 if (regmask_ffca & (1 << reg)) {
5984 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
5990 // declare push-pop temporaries
5992 for (reg = 0; reg < 8; reg++) {
5993 if (regmask_pp & (1 << reg)) {
5994 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
6001 for (i = 0; i < 8; i++) {
6002 if (cond_vars & (1 << i)) {
6003 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
6010 fprintf(fout, " u32 tmp;\n");
6015 fprintf(fout, " u64 tmp64;\n");
6020 fprintf(fout, "\n");
6022 // do stack clear, if needed
6023 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6025 if (g_stack_clear_len != 0) {
6026 if (g_stack_clear_len <= 4) {
6027 for (i = 0; i < g_stack_clear_len; i++)
6028 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6029 fprintf(fout, "0;\n");
6032 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6033 g_stack_clear_start, g_stack_clear_len * 4);
6037 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6040 if (g_func_pp->is_vararg) {
6041 if (g_func_pp->argc_stack == 0)
6042 ferr(ops, "vararg func without stack args?\n");
6043 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
6047 for (i = 0; i < opcnt; i++)
6049 if (g_labels[i] != NULL) {
6050 fprintf(fout, "\n%s:\n", g_labels[i]);
6053 delayed_flag_op = NULL;
6054 last_arith_dst = NULL;
6058 if (po->flags & OPF_RMD)
6063 #define assert_operand_cnt(n_) \
6064 if (po->operand_cnt != n_) \
6065 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6067 // conditional/flag using op?
6068 if (po->flags & OPF_CC)
6074 // we go through all this trouble to avoid using parsed_flag_op,
6075 // which makes generated code much nicer
6076 if (delayed_flag_op != NULL)
6078 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6079 po->pfo, po->pfo_inv);
6082 else if (last_arith_dst != NULL
6083 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6084 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6087 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6088 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6089 last_arith_dst->lmod, buf3);
6092 else if (tmp_op != NULL) {
6093 // use preprocessed flag calc results
6094 if (!(tmp_op->pfomask & (1 << po->pfo)))
6095 ferr(po, "not prepared for pfo %d\n", po->pfo);
6097 // note: pfo_inv was not yet applied
6098 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6099 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6102 ferr(po, "all methods of finding comparison failed\n");
6105 if (po->flags & OPF_JMP) {
6106 fprintf(fout, " if %s", buf1);
6108 else if (po->op == OP_RCL || po->op == OP_RCR
6109 || po->op == OP_ADC || po->op == OP_SBB)
6112 fprintf(fout, " cond_%s = %s;\n",
6113 parsed_flag_op_names[po->pfo], buf1);
6115 else if (po->flags & OPF_DATA) { // SETcc
6116 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6117 fprintf(fout, " %s = %s;", buf2, buf1);
6120 ferr(po, "unhandled conditional op\n");
6124 pfomask = po->pfomask;
6129 assert_operand_cnt(2);
6130 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6131 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6132 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
6133 fprintf(fout, " %s = %s;", buf1,
6134 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6139 assert_operand_cnt(2);
6140 po->operand[1].lmod = OPLM_DWORD; // always
6141 fprintf(fout, " %s = %s;",
6142 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6143 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6148 assert_operand_cnt(2);
6149 fprintf(fout, " %s = %s;",
6150 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6151 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6155 assert_operand_cnt(2);
6156 switch (po->operand[1].lmod) {
6158 strcpy(buf3, "(s8)");
6161 strcpy(buf3, "(s16)");
6164 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6166 fprintf(fout, " %s = %s;",
6167 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6168 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6173 assert_operand_cnt(2);
6174 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6175 fprintf(fout, " tmp = %s;",
6176 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6177 fprintf(fout, " %s = %s;",
6178 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6179 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6180 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6181 fprintf(fout, " %s = %stmp;",
6182 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6183 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
6184 snprintf(g_comment, sizeof(g_comment), "xchg");
6188 assert_operand_cnt(1);
6189 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6190 fprintf(fout, " %s = ~%s;", buf1, buf1);
6194 assert_operand_cnt(2);
6195 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6196 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6197 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6198 strcpy(g_comment, "xlat");
6202 assert_operand_cnt(2);
6203 fprintf(fout, " %s = (s32)%s >> 31;",
6204 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6205 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6206 strcpy(g_comment, "cdq");
6210 assert_operand_cnt(1);
6211 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6212 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
6216 if (po->flags & OPF_REP) {
6217 assert_operand_cnt(3);
6222 assert_operand_cnt(2);
6223 fprintf(fout, " %s = %sesi; esi %c= %d;",
6224 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6225 lmod_cast_u_ptr(po, po->operand[1].lmod),
6226 (po->flags & OPF_DF) ? '-' : '+',
6227 lmod_bytes(po, po->operand[1].lmod));
6228 strcpy(g_comment, "lods");
6233 if (po->flags & OPF_REP) {
6234 assert_operand_cnt(3);
6235 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
6236 (po->flags & OPF_DF) ? '-' : '+',
6237 lmod_bytes(po, po->operand[1].lmod));
6238 fprintf(fout, " %sedi = eax;",
6239 lmod_cast_u_ptr(po, po->operand[1].lmod));
6240 strcpy(g_comment, "rep stos");
6243 assert_operand_cnt(2);
6244 fprintf(fout, " %sedi = eax; edi %c= %d;",
6245 lmod_cast_u_ptr(po, po->operand[1].lmod),
6246 (po->flags & OPF_DF) ? '-' : '+',
6247 lmod_bytes(po, po->operand[1].lmod));
6248 strcpy(g_comment, "stos");
6253 j = lmod_bytes(po, po->operand[0].lmod);
6254 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6255 l = (po->flags & OPF_DF) ? '-' : '+';
6256 if (po->flags & OPF_REP) {
6257 assert_operand_cnt(3);
6259 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
6262 " %sedi = %sesi;", buf1, buf1);
6263 strcpy(g_comment, "rep movs");
6266 assert_operand_cnt(2);
6267 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
6268 buf1, buf1, l, j, l, j);
6269 strcpy(g_comment, "movs");
6274 // repe ~ repeat while ZF=1
6275 j = lmod_bytes(po, po->operand[0].lmod);
6276 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6277 l = (po->flags & OPF_DF) ? '-' : '+';
6278 if (po->flags & OPF_REP) {
6279 assert_operand_cnt(3);
6281 " while (ecx != 0) {\n");
6282 if (pfomask & (1 << PFO_C)) {
6285 " cond_c = %sesi < %sedi;\n", buf1, buf1);
6286 pfomask &= ~(1 << PFO_C);
6289 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
6290 buf1, buf1, l, j, l, j);
6293 " if (cond_z %s 0) break;\n",
6294 (po->flags & OPF_REPZ) ? "==" : "!=");
6297 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
6298 (po->flags & OPF_REPZ) ? "e" : "ne");
6301 assert_operand_cnt(2);
6303 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
6304 buf1, buf1, l, j, l, j);
6305 strcpy(g_comment, "cmps");
6307 pfomask &= ~(1 << PFO_Z);
6308 last_arith_dst = NULL;
6309 delayed_flag_op = NULL;
6313 // only does ZF (for now)
6314 // repe ~ repeat while ZF=1
6315 j = lmod_bytes(po, po->operand[1].lmod);
6316 l = (po->flags & OPF_DF) ? '-' : '+';
6317 if (po->flags & OPF_REP) {
6318 assert_operand_cnt(3);
6320 " while (ecx != 0) {\n");
6322 " cond_z = (%seax == %sedi); edi %c= %d;\n",
6323 lmod_cast_u(po, po->operand[1].lmod),
6324 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6327 " if (cond_z %s 0) break;\n",
6328 (po->flags & OPF_REPZ) ? "==" : "!=");
6331 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
6332 (po->flags & OPF_REPZ) ? "e" : "ne");
6335 assert_operand_cnt(2);
6336 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
6337 lmod_cast_u(po, po->operand[1].lmod),
6338 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6339 strcpy(g_comment, "scas");
6341 pfomask &= ~(1 << PFO_Z);
6342 last_arith_dst = NULL;
6343 delayed_flag_op = NULL;
6346 // arithmetic w/flags
6348 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
6349 goto dualop_arith_const;
6350 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6354 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6355 if (po->operand[1].type == OPT_CONST) {
6356 j = lmod_bytes(po, po->operand[0].lmod);
6357 if (((1ull << j * 8) - 1) == po->operand[1].val)
6358 goto dualop_arith_const;
6363 assert_operand_cnt(2);
6364 fprintf(fout, " %s %s= %s;",
6365 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6367 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6368 output_std_flags(fout, po, &pfomask, buf1);
6369 last_arith_dst = &po->operand[0];
6370 delayed_flag_op = NULL;
6374 // and 0, or ~0 used instead mov
6375 assert_operand_cnt(2);
6376 fprintf(fout, " %s = %s;",
6377 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6378 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6379 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6380 output_std_flags(fout, po, &pfomask, buf1);
6381 last_arith_dst = &po->operand[0];
6382 delayed_flag_op = NULL;
6387 assert_operand_cnt(2);
6388 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6389 if (pfomask & (1 << PFO_C)) {
6390 if (po->operand[1].type == OPT_CONST) {
6391 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6392 j = po->operand[1].val;
6395 if (po->op == OP_SHL)
6399 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
6403 ferr(po, "zero shift?\n");
6407 pfomask &= ~(1 << PFO_C);
6409 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
6410 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6411 if (po->operand[1].type != OPT_CONST)
6412 fprintf(fout, " & 0x1f");
6414 output_std_flags(fout, po, &pfomask, buf1);
6415 last_arith_dst = &po->operand[0];
6416 delayed_flag_op = NULL;
6420 assert_operand_cnt(2);
6421 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6422 fprintf(fout, " %s = %s%s >> %s;", buf1,
6423 lmod_cast_s(po, po->operand[0].lmod), buf1,
6424 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6425 output_std_flags(fout, po, &pfomask, buf1);
6426 last_arith_dst = &po->operand[0];
6427 delayed_flag_op = NULL;
6432 assert_operand_cnt(3);
6433 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6434 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6435 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
6436 if (po->operand[2].type != OPT_CONST) {
6437 // no handling for "undefined" case, hopefully not needed
6438 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
6441 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6442 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6443 if (po->op == OP_SHLD) {
6444 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
6445 buf1, buf3, buf1, buf2, l, buf3);
6446 strcpy(g_comment, "shld");
6449 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
6450 buf1, buf3, buf1, buf2, l, buf3);
6451 strcpy(g_comment, "shrd");
6453 output_std_flags(fout, po, &pfomask, buf1);
6454 last_arith_dst = &po->operand[0];
6455 delayed_flag_op = NULL;
6460 assert_operand_cnt(2);
6461 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6462 if (po->operand[1].type == OPT_CONST) {
6463 j = po->operand[1].val;
6464 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
6465 fprintf(fout, po->op == OP_ROL ?
6466 " %s = (%s << %d) | (%s >> %d);" :
6467 " %s = (%s >> %d) | (%s << %d);",
6468 buf1, buf1, j, buf1,
6469 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
6473 output_std_flags(fout, po, &pfomask, buf1);
6474 last_arith_dst = &po->operand[0];
6475 delayed_flag_op = NULL;
6480 assert_operand_cnt(2);
6481 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6482 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6483 if (po->operand[1].type == OPT_CONST) {
6484 j = po->operand[1].val % l;
6486 ferr(po, "zero rotate\n");
6487 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
6488 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
6489 if (po->op == OP_RCL) {
6491 " %s = (%s << %d) | (cond_c << %d)",
6492 buf1, buf1, j, j - 1);
6494 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
6498 " %s = (%s >> %d) | (cond_c << %d)",
6499 buf1, buf1, j, l - j);
6501 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
6503 fprintf(fout, ";\n");
6504 fprintf(fout, " cond_c = tmp;");
6508 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
6509 output_std_flags(fout, po, &pfomask, buf1);
6510 last_arith_dst = &po->operand[0];
6511 delayed_flag_op = NULL;
6515 assert_operand_cnt(2);
6516 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6517 if (IS(opr_name(po, 0), opr_name(po, 1))) {
6518 // special case for XOR
6519 int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
6520 for (j = 0; j <= PFO_LE; j++) {
6521 if (pfomask & (1 << j)) {
6522 fprintf(fout, " cond_%s = %d;\n",
6523 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
6524 pfomask &= ~(1 << j);
6527 fprintf(fout, " %s = 0;",
6528 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6529 last_arith_dst = &po->operand[0];
6530 delayed_flag_op = NULL;
6536 assert_operand_cnt(2);
6537 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6538 if (pfomask & (1 << PFO_C)) {
6539 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6540 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6541 if (po->operand[0].lmod == OPLM_DWORD) {
6542 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
6543 fprintf(fout, " cond_c = tmp64 >> 32;\n");
6544 fprintf(fout, " %s = (u32)tmp64;",
6545 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6546 strcat(g_comment, " add64");
6549 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
6550 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
6551 fprintf(fout, " %s += %s;",
6552 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6555 pfomask &= ~(1 << PFO_C);
6556 output_std_flags(fout, po, &pfomask, buf1);
6557 last_arith_dst = &po->operand[0];
6558 delayed_flag_op = NULL;
6561 if (pfomask & (1 << PFO_LE)) {
6562 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
6563 fprintf(fout, " cond_%s = %s;\n",
6564 parsed_flag_op_names[PFO_LE], buf1);
6565 pfomask &= ~(1 << PFO_LE);
6570 assert_operand_cnt(2);
6571 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6572 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
6573 for (j = 0; j <= PFO_LE; j++) {
6574 if (!(pfomask & (1 << j)))
6576 if (j == PFO_Z || j == PFO_S)
6579 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6580 fprintf(fout, " cond_%s = %s;\n",
6581 parsed_flag_op_names[j], buf1);
6582 pfomask &= ~(1 << j);
6589 assert_operand_cnt(2);
6590 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6591 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6592 if (po->op == OP_SBB
6593 && IS(po->operand[0].name, po->operand[1].name))
6595 // avoid use of unitialized var
6596 fprintf(fout, " %s = -cond_c;", buf1);
6597 // carry remains what it was
6598 pfomask &= ~(1 << PFO_C);
6601 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
6602 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6604 output_std_flags(fout, po, &pfomask, buf1);
6605 last_arith_dst = &po->operand[0];
6606 delayed_flag_op = NULL;
6610 assert_operand_cnt(2);
6611 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6612 fprintf(fout, " %s = %s ? __builtin_ffs(%s) - 1 : 0;",
6613 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6615 output_std_flags(fout, po, &pfomask, buf1);
6616 last_arith_dst = &po->operand[0];
6617 delayed_flag_op = NULL;
6618 strcat(g_comment, " bsf");
6622 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
6623 for (j = 0; j <= PFO_LE; j++) {
6624 if (!(pfomask & (1 << j)))
6626 if (j == PFO_Z || j == PFO_S || j == PFO_C)
6629 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6630 fprintf(fout, " cond_%s = %s;\n",
6631 parsed_flag_op_names[j], buf1);
6632 pfomask &= ~(1 << j);
6638 if (pfomask & (1 << PFO_C))
6639 // carry is unaffected by inc/dec.. wtf?
6640 ferr(po, "carry propagation needed\n");
6642 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6643 if (po->operand[0].type == OPT_REG) {
6644 strcpy(buf2, po->op == OP_INC ? "++" : "--");
6645 fprintf(fout, " %s%s;", buf1, buf2);
6648 strcpy(buf2, po->op == OP_INC ? "+" : "-");
6649 fprintf(fout, " %s %s= 1;", buf1, buf2);
6651 output_std_flags(fout, po, &pfomask, buf1);
6652 last_arith_dst = &po->operand[0];
6653 delayed_flag_op = NULL;
6657 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6658 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
6659 fprintf(fout, " %s = -%s%s;", buf1,
6660 lmod_cast_s(po, po->operand[0].lmod), buf2);
6661 last_arith_dst = &po->operand[0];
6662 delayed_flag_op = NULL;
6663 if (pfomask & (1 << PFO_C)) {
6664 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
6665 pfomask &= ~(1 << PFO_C);
6670 if (po->operand_cnt == 2) {
6671 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6674 if (po->operand_cnt == 3)
6675 ferr(po, "TODO imul3\n");
6678 assert_operand_cnt(1);
6679 switch (po->operand[0].lmod) {
6681 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
6682 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
6683 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
6684 fprintf(fout, " edx = tmp64 >> 32;\n");
6685 fprintf(fout, " eax = tmp64;");
6688 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
6689 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
6690 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
6694 ferr(po, "TODO: unhandled mul type\n");
6697 last_arith_dst = NULL;
6698 delayed_flag_op = NULL;
6703 assert_operand_cnt(1);
6704 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6705 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
6706 po->op == OP_IDIV));
6707 switch (po->operand[0].lmod) {
6709 if (po->flags & OPF_32BIT)
6710 snprintf(buf2, sizeof(buf2), "%seax", cast);
6712 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
6713 snprintf(buf2, sizeof(buf2), "%stmp64",
6714 (po->op == OP_IDIV) ? "(s64)" : "");
6716 if (po->operand[0].type == OPT_REG
6717 && po->operand[0].reg == xDX)
6719 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
6720 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
6723 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
6724 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
6728 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
6729 snprintf(buf2, sizeof(buf2), "%stmp",
6730 (po->op == OP_IDIV) ? "(s32)" : "");
6731 if (po->operand[0].type == OPT_REG
6732 && po->operand[0].reg == xDX)
6734 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
6736 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
6740 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
6742 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
6745 strcat(g_comment, " div16");
6748 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
6750 last_arith_dst = NULL;
6751 delayed_flag_op = NULL;
6756 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6758 for (j = 0; j < 8; j++) {
6759 if (pfomask & (1 << j)) {
6760 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
6761 fprintf(fout, " cond_%s = %s;",
6762 parsed_flag_op_names[j], buf1);
6769 last_arith_dst = NULL;
6770 delayed_flag_op = po;
6774 // SETcc - should already be handled
6777 // note: we reuse OP_Jcc for SETcc, only flags differ
6779 fprintf(fout, "\n goto %s;", po->operand[0].name);
6783 fprintf(fout, " if (ecx == 0)\n");
6784 fprintf(fout, " goto %s;", po->operand[0].name);
6785 strcat(g_comment, " jecxz");
6789 fprintf(fout, " if (--ecx != 0)\n");
6790 fprintf(fout, " goto %s;", po->operand[0].name);
6791 strcat(g_comment, " loop");
6795 assert_operand_cnt(1);
6796 last_arith_dst = NULL;
6797 delayed_flag_op = NULL;
6799 if (po->operand[0].type == OPT_REGMEM) {
6800 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
6803 ferr(po, "parse failure for jmp '%s'\n",
6804 po->operand[0].name);
6805 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
6808 else if (po->operand[0].type != OPT_LABEL)
6809 ferr(po, "unhandled jmp type\n");
6811 fprintf(fout, " goto %s;", po->operand[0].name);
6815 assert_operand_cnt(1);
6817 my_assert_not(pp, NULL);
6820 if (po->flags & OPF_CC) {
6821 // we treat conditional branch to another func
6822 // (yes such code exists..) as conditional tailcall
6824 fprintf(fout, " {\n");
6827 if (pp->is_fptr && !pp->is_arg) {
6828 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
6829 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6831 if (pp->is_unresolved)
6832 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
6833 buf3, asmfn, po->asmln, pp->name);
6836 fprintf(fout, "%s", buf3);
6837 if (strstr(pp->ret_type.name, "int64")) {
6838 if (po->flags & OPF_TAIL)
6839 ferr(po, "int64 and tail?\n");
6840 fprintf(fout, "tmp64 = ");
6842 else if (!IS(pp->ret_type.name, "void")) {
6843 if (po->flags & OPF_TAIL) {
6844 if (regmask_ret & mxAX) {
6845 fprintf(fout, "return ");
6846 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
6847 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
6849 else if (regmask_ret & mxST0)
6850 ferr(po, "float tailcall\n");
6852 else if (po->regmask_dst & mxAX) {
6853 fprintf(fout, "eax = ");
6854 if (pp->ret_type.is_ptr)
6855 fprintf(fout, "(u32)");
6857 else if (po->regmask_dst & mxST0) {
6858 ferr_assert(po, po->flags & OPF_FPUSH);
6859 if (need_float_stack)
6860 fprintf(fout, "f_st[--f_stp & 7] = ");
6862 fprintf(fout, "f_st0 = ");
6866 if (pp->name[0] == 0)
6867 ferr(po, "missing pp->name\n");
6868 fprintf(fout, "%s%s(", pp->name,
6869 pp->has_structarg ? "_sa" : "");
6871 if (po->flags & OPF_ATAIL) {
6872 if (pp->argc_stack != g_func_pp->argc_stack
6873 || (pp->argc_stack > 0
6874 && pp->is_stdcall != g_func_pp->is_stdcall))
6875 ferr(po, "incompatible tailcall\n");
6876 if (g_func_pp->has_retreg)
6877 ferr(po, "TODO: retreg+tailcall\n");
6879 for (arg = j = 0; arg < pp->argc; arg++) {
6881 fprintf(fout, ", ");
6884 if (pp->arg[arg].type.is_ptr)
6885 snprintf(cast, sizeof(cast), "(%s)",
6886 pp->arg[arg].type.name);
6888 if (pp->arg[arg].reg != NULL) {
6889 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6893 for (; j < g_func_pp->argc; j++)
6894 if (g_func_pp->arg[j].reg == NULL)
6896 fprintf(fout, "%sa%d", cast, j + 1);
6901 for (arg = 0; arg < pp->argc; arg++) {
6903 fprintf(fout, ", ");
6906 if (pp->arg[arg].type.is_ptr)
6907 snprintf(cast, sizeof(cast), "(%s)",
6908 pp->arg[arg].type.name);
6910 if (pp->arg[arg].reg != NULL) {
6911 if (pp->arg[arg].type.is_retreg)
6912 fprintf(fout, "&%s", pp->arg[arg].reg);
6914 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6919 tmp_op = pp->arg[arg].datap;
6921 ferr(po, "parsed_op missing for arg%d\n", arg);
6923 if (tmp_op->flags & OPF_VAPUSH) {
6924 fprintf(fout, "ap");
6926 else if (tmp_op->op == OP_FST) {
6927 fprintf(fout, "fs_%d", tmp_op->p_argnum);
6928 if (tmp_op->operand[0].lmod == OPLM_QWORD)
6931 else if (tmp_op->p_argpass != 0) {
6932 fprintf(fout, "a%d", tmp_op->p_argpass);
6934 else if (tmp_op->p_argnum != 0) {
6935 fprintf(fout, "%s%s", cast,
6936 saved_arg_name(buf1, sizeof(buf1),
6937 tmp_op->p_arggrp, tmp_op->p_argnum));
6941 out_src_opr(buf1, sizeof(buf1),
6942 tmp_op, &tmp_op->operand[0], cast, 0));
6946 fprintf(fout, ");");
6948 if (strstr(pp->ret_type.name, "int64")) {
6949 fprintf(fout, "\n");
6950 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
6951 fprintf(fout, "%seax = tmp64;", buf3);
6954 if (pp->is_unresolved) {
6955 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
6957 strcat(g_comment, buf2);
6960 if (po->flags & OPF_TAIL) {
6962 if (i == opcnt - 1 || pp->is_noreturn)
6964 else if (IS(pp->ret_type.name, "void"))
6966 else if (!(regmask_ret & (1 << xAX)))
6968 // else already handled as 'return f()'
6971 fprintf(fout, "\n%sreturn;", buf3);
6972 strcat(g_comment, " ^ tailcall");
6975 strcat(g_comment, " tailcall");
6977 if ((regmask_ret & (1 << xAX))
6978 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
6980 ferr(po, "int func -> void func tailcall?\n");
6983 if (pp->is_noreturn)
6984 strcat(g_comment, " noreturn");
6985 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
6986 strcat(g_comment, " argframe");
6987 if (po->flags & OPF_CC)
6988 strcat(g_comment, " cond");
6990 if (po->flags & OPF_CC)
6991 fprintf(fout, "\n }");
6993 delayed_flag_op = NULL;
6994 last_arith_dst = NULL;
6998 if (g_func_pp->is_vararg)
6999 fprintf(fout, " va_end(ap);\n");
7000 if (g_func_pp->has_retreg) {
7001 for (arg = 0; arg < g_func_pp->argc; arg++)
7002 if (g_func_pp->arg[arg].type.is_retreg)
7003 fprintf(fout, " *r_%s = %s;\n",
7004 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7007 if (regmask_ret & mxST0) {
7008 fprintf(fout, " return %s;", float_st0);
7010 else if (!(regmask_ret & mxAX)) {
7011 if (i != opcnt - 1 || label_pending)
7012 fprintf(fout, " return;");
7014 else if (g_func_pp->ret_type.is_ptr) {
7015 fprintf(fout, " return (%s)eax;",
7016 g_func_pp->ret_type.name);
7018 else if (IS(g_func_pp->ret_type.name, "__int64"))
7019 fprintf(fout, " return ((u64)edx << 32) | eax;");
7021 fprintf(fout, " return eax;");
7023 last_arith_dst = NULL;
7024 delayed_flag_op = NULL;
7028 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7029 if (po->p_argnum != 0) {
7030 // special case - saved func arg
7031 fprintf(fout, " %s = %s;",
7032 saved_arg_name(buf2, sizeof(buf2),
7033 po->p_arggrp, po->p_argnum), buf1);
7036 else if (po->flags & OPF_RSAVE) {
7037 fprintf(fout, " s_%s = %s;", buf1, buf1);
7040 else if (po->flags & OPF_PPUSH) {
7042 ferr_assert(po, tmp_op != NULL);
7043 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7044 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7047 else if (g_func_pp->is_userstack) {
7048 fprintf(fout, " *(--esp) = %s;", buf1);
7051 if (!(g_ida_func_attr & IDAFA_NORETURN))
7052 ferr(po, "stray push encountered\n");
7057 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7058 if (po->flags & OPF_RSAVE) {
7059 fprintf(fout, " %s = s_%s;", buf1, buf1);
7062 else if (po->flags & OPF_PPUSH) {
7063 // push/pop graph / non-const
7064 ferr_assert(po, po->datap == NULL);
7065 fprintf(fout, " %s = pp_%s;", buf1, buf1);
7068 else if (po->datap != NULL) {
7071 fprintf(fout, " %s = %s;", buf1,
7072 out_src_opr(buf2, sizeof(buf2),
7073 tmp_op, &tmp_op->operand[0],
7074 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7077 else if (g_func_pp->is_userstack) {
7078 fprintf(fout, " %s = *esp++;", buf1);
7082 ferr(po, "stray pop encountered\n");
7092 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7093 fprintf(fout, " tmp64 = (s64)tmp64 %s= LOBYTE(ecx);\n",
7094 po->op == OPP_ALLSHL ? "<<" : ">>");
7095 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
7096 strcat(g_comment, po->op == OPP_ALLSHL
7097 ? " allshl" : " allshr");
7102 if (need_float_stack) {
7103 out_src_opr_float(buf1, sizeof(buf1),
7104 po, &po->operand[0], 1);
7105 if (po->regmask_src & mxSTa) {
7106 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7110 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
7113 if (po->flags & OPF_FSHIFT)
7114 fprintf(fout, " f_st1 = f_st0;");
7115 if (po->operand[0].type == OPT_REG
7116 && po->operand[0].reg == xST0)
7118 strcat(g_comment, " fld st");
7121 fprintf(fout, " f_st0 = %s;",
7122 out_src_opr_float(buf1, sizeof(buf1),
7123 po, &po->operand[0], 0));
7125 strcat(g_comment, " fld");
7129 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7130 lmod_cast(po, po->operand[0].lmod, 1), 0);
7131 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7132 if (need_float_stack) {
7133 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
7136 if (po->flags & OPF_FSHIFT)
7137 fprintf(fout, " f_st1 = f_st0;");
7138 fprintf(fout, " f_st0 = %s;", buf2);
7140 strcat(g_comment, " fild");
7144 if (need_float_stack)
7145 fprintf(fout, " f_st[--f_stp & 7] = ");
7147 if (po->flags & OPF_FSHIFT)
7148 fprintf(fout, " f_st1 = f_st0;");
7149 fprintf(fout, " f_st0 = ");
7151 switch (po->operand[0].val) {
7152 case X87_CONST_1: fprintf(fout, "1.0;"); break;
7153 case X87_CONST_LN2: fprintf(fout, "0.693147180559945;"); break;
7154 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
7155 default: ferr(po, "TODO\n"); break;
7160 if (po->flags & OPF_FARG) {
7161 // store to stack as func arg
7162 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7166 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7168 dead_dst = po->operand[0].type == OPT_REG
7169 && po->operand[0].reg == xST0;
7172 fprintf(fout, " %s = %s;", buf1, float_st0);
7173 if (po->flags & OPF_FSHIFT) {
7174 if (need_float_stack)
7175 fprintf(fout, " f_stp++;");
7177 fprintf(fout, " f_st0 = f_st1;");
7179 if (dead_dst && !(po->flags & OPF_FSHIFT))
7182 strcat(g_comment, " fst");
7186 fprintf(fout, " %s = %s%s;",
7187 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7188 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7189 if (po->flags & OPF_FSHIFT) {
7190 if (need_float_stack)
7191 fprintf(fout, " f_stp++;");
7193 fprintf(fout, " f_st0 = f_st1;");
7195 strcat(g_comment, " fist");
7202 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7204 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7206 dead_dst = (po->flags & OPF_FPOP)
7207 && po->operand[0].type == OPT_REG
7208 && po->operand[0].reg == xST0;
7210 case OP_FADD: j = '+'; break;
7211 case OP_FDIV: j = '/'; break;
7212 case OP_FMUL: j = '*'; break;
7213 case OP_FSUB: j = '-'; break;
7214 default: j = 'x'; break;
7216 if (need_float_stack) {
7218 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7219 if (po->flags & OPF_FSHIFT)
7220 fprintf(fout, " f_stp++;");
7223 if (po->flags & OPF_FSHIFT) {
7224 // note: assumes only 2 regs handled
7226 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
7228 fprintf(fout, " f_st0 = f_st1;");
7231 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7233 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7238 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7240 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7242 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
7244 dead_dst = (po->flags & OPF_FPOP)
7245 && po->operand[0].type == OPT_REG
7246 && po->operand[0].reg == xST0;
7247 j = po->op == OP_FDIVR ? '/' : '-';
7248 if (need_float_stack) {
7250 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7251 if (po->flags & OPF_FSHIFT)
7252 fprintf(fout, " f_stp++;");
7255 if (po->flags & OPF_FSHIFT) {
7257 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
7259 fprintf(fout, " f_st0 = f_st1;");
7262 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7264 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7272 case OP_FIADD: j = '+'; break;
7273 case OP_FIDIV: j = '/'; break;
7274 case OP_FIMUL: j = '*'; break;
7275 case OP_FISUB: j = '-'; break;
7276 default: j = 'x'; break;
7278 fprintf(fout, " %s %c= (%s)%s;", float_st0,
7280 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7281 lmod_cast(po, po->operand[0].lmod, 1), 0));
7286 fprintf(fout, " %s = %s %c %s;", float_st0,
7287 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7289 po->op == OP_FIDIVR ? '/' : '-', float_st0);
7294 ferr_assert(po, po->datap != NULL);
7295 mask = (long)po->datap & 0xffff;
7296 z_check = ((long)po->datap >> 16) & 1;
7297 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7299 if (mask == 0x0100) { // C0 -> <
7300 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
7303 else if (mask == 0x4000) { // C3 -> =
7304 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
7307 else if (mask == 0x4100) { // C3, C0
7309 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
7311 strcat(g_comment, " z_chk_det");
7314 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
7315 "(%s < %s ? 0x0100 : 0);",
7316 float_st0, buf1, float_st0, buf1);
7320 ferr(po, "unhandled sw mask: %x\n", mask);
7321 if (po->flags & OPF_FSHIFT) {
7322 if (need_float_stack)
7323 fprintf(fout, " f_stp++;");
7325 fprintf(fout, " f_st0 = f_st1;");
7331 fprintf(fout, " %s = f_sw;",
7332 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7336 fprintf(fout, " %s = -%s;", float_st0, float_st0);
7340 fprintf(fout, " %s = cos%s(%s);", float_st0,
7341 need_double ? "" : "f", float_st0);
7345 if (need_float_stack) {
7346 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
7347 need_double ? "" : "f", float_st1, float_st0);
7348 fprintf(fout, " f_stp++;");
7351 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
7352 need_double ? "" : "f");
7357 if (need_float_stack) {
7358 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
7359 float_st1, need_double ? "" : "f", float_st0);
7360 fprintf(fout, " f_stp++;");
7363 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
7364 need_double ? "" : "f");
7369 fprintf(fout, " %s = sin%s(%s);", float_st0,
7370 need_double ? "" : "f", float_st0);
7374 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
7375 need_double ? "" : "f", float_st0);
7379 dead_dst = po->operand[0].type == OPT_REG
7380 && po->operand[0].reg == xST0;
7382 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7384 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
7385 float_st0, float_st0, buf1, buf1);
7386 strcat(g_comment, " fxch");
7393 ferr_assert(po, po->flags & OPF_32BIT);
7394 fprintf(fout, " eax = (s32)%s;", float_st0);
7395 if (po->flags & OPF_FSHIFT) {
7396 if (need_float_stack)
7397 fprintf(fout, " f_stp++;");
7399 fprintf(fout, " f_st0 = f_st1;");
7401 strcat(g_comment, " ftol");
7406 strcpy(g_comment, " (emms)");
7411 ferr(po, "unhandled op type %d, flags %x\n",
7416 if (g_comment[0] != 0) {
7417 char *p = g_comment;
7418 while (my_isblank(*p))
7420 fprintf(fout, " // %s", p);
7425 fprintf(fout, "\n");
7427 // some sanity checking
7428 if (po->flags & OPF_REP) {
7429 if (po->op != OP_STOS && po->op != OP_MOVS
7430 && po->op != OP_CMPS && po->op != OP_SCAS)
7431 ferr(po, "unexpected rep\n");
7432 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
7433 && (po->op == OP_CMPS || po->op == OP_SCAS))
7434 ferr(po, "cmps/scas with plain rep\n");
7436 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
7437 && po->op != OP_CMPS && po->op != OP_SCAS)
7438 ferr(po, "unexpected repz/repnz\n");
7441 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
7443 // see is delayed flag stuff is still valid
7444 if (delayed_flag_op != NULL && delayed_flag_op != po) {
7445 if (is_any_opr_modified(delayed_flag_op, po, 0))
7446 delayed_flag_op = NULL;
7449 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
7450 if (is_opr_modified(last_arith_dst, po))
7451 last_arith_dst = NULL;
7457 if (g_stack_fsz && !g_stack_frame_used)
7458 fprintf(fout, " (void)sf;\n");
7460 fprintf(fout, "}\n\n");
7462 gen_x_cleanup(opcnt);
7465 static void gen_x_cleanup(int opcnt)
7469 for (i = 0; i < opcnt; i++) {
7470 struct label_ref *lr, *lr_del;
7472 lr = g_label_refs[i].next;
7473 while (lr != NULL) {
7478 g_label_refs[i].i = -1;
7479 g_label_refs[i].next = NULL;
7481 if (ops[i].op == OP_CALL) {
7483 proto_release(ops[i].pp);
7489 struct func_proto_dep;
7491 struct func_prototype {
7496 int has_ret:3; // -1, 0, 1: unresolved, no, yes
7497 unsigned int dep_resolved:1;
7498 unsigned int is_stdcall:1;
7499 struct func_proto_dep *dep_func;
7501 const struct parsed_proto *pp; // seed pp, if any
7504 struct func_proto_dep {
7506 struct func_prototype *proto;
7507 int regmask_live; // .. at the time of call
7508 unsigned int ret_dep:1; // return from this is caller's return
7511 static struct func_prototype *hg_fp;
7512 static int hg_fp_cnt;
7514 static struct scanned_var {
7516 enum opr_lenmod lmod;
7517 unsigned int is_seeded:1;
7518 unsigned int is_c_str:1;
7519 const struct parsed_proto *pp; // seed pp, if any
7521 static int hg_var_cnt;
7523 static char **hg_refs;
7524 static int hg_ref_cnt;
7526 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7529 static struct func_prototype *hg_fp_add(const char *funcn)
7531 struct func_prototype *fp;
7533 if ((hg_fp_cnt & 0xff) == 0) {
7534 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
7535 my_assert_not(hg_fp, NULL);
7536 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
7539 fp = &hg_fp[hg_fp_cnt];
7540 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
7542 fp->argc_stack = -1;
7548 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
7553 for (i = 0; i < fp->dep_func_cnt; i++)
7554 if (IS(fp->dep_func[i].name, name))
7555 return &fp->dep_func[i];
7560 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
7563 if (hg_fp_find_dep(fp, name))
7566 if ((fp->dep_func_cnt & 0xff) == 0) {
7567 fp->dep_func = realloc(fp->dep_func,
7568 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
7569 my_assert_not(fp->dep_func, NULL);
7570 memset(&fp->dep_func[fp->dep_func_cnt], 0,
7571 sizeof(fp->dep_func[0]) * 0x100);
7573 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
7577 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
7579 const struct func_prototype *p1 = p1_, *p2 = p2_;
7580 return strcmp(p1->name, p2->name);
7584 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
7586 const struct func_prototype *p1 = p1_, *p2 = p2_;
7587 return p1->id - p2->id;
7591 static void hg_ref_add(const char *name)
7593 if ((hg_ref_cnt & 0xff) == 0) {
7594 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
7595 my_assert_not(hg_refs, NULL);
7596 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
7599 hg_refs[hg_ref_cnt] = strdup(name);
7600 my_assert_not(hg_refs[hg_ref_cnt], NULL);
7604 // recursive register dep pass
7605 // - track saved regs (part 2)
7606 // - try to figure out arg-regs
7607 // - calculate reg deps
7608 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
7609 struct func_prototype *fp, int regmask_save, int regmask_dst,
7610 int *regmask_dep, int *has_ret)
7612 struct func_proto_dep *dep;
7613 struct parsed_op *po;
7614 int from_caller = 0;
7619 for (; i < opcnt; i++)
7621 if (cbits[i >> 3] & (1 << (i & 7)))
7623 cbits[i >> 3] |= (1 << (i & 7));
7627 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
7628 if (po->flags & OPF_RMD)
7631 if (po->btj != NULL) {
7633 for (j = 0; j < po->btj->count; j++) {
7634 check_i(po, po->btj->d[j].bt_i);
7635 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
7636 regmask_save, regmask_dst, regmask_dep, has_ret);
7641 check_i(po, po->bt_i);
7642 if (po->flags & OPF_CJMP) {
7643 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
7644 regmask_save, regmask_dst, regmask_dep, has_ret);
7652 if (po->flags & OPF_FARG)
7653 /* (just calculate register deps) */;
7654 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
7656 reg = po->operand[0].reg;
7657 ferr_assert(po, reg >= 0);
7659 if (po->flags & OPF_RSAVE) {
7660 regmask_save |= 1 << reg;
7663 if (po->flags & OPF_DONE)
7666 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0, 0);
7668 regmask_save |= 1 << reg;
7669 po->flags |= OPF_RMD;
7670 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, OPF_RMD);
7674 else if (po->flags & OPF_RMD)
7676 else if (po->op == OP_CALL) {
7677 po->regmask_dst |= 1 << xAX;
7679 dep = hg_fp_find_dep(fp, po->operand[0].name);
7681 dep->regmask_live = regmask_save | regmask_dst;
7683 else if (po->op == OP_RET) {
7684 if (po->operand_cnt > 0) {
7686 if (fp->argc_stack >= 0
7687 && fp->argc_stack != po->operand[0].val / 4)
7688 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
7689 fp->argc_stack = po->operand[0].val / 4;
7693 // if has_ret is 0, there is uninitialized eax path,
7694 // which means it's most likely void func
7695 if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
7696 if (po->op == OP_CALL) {
7701 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
7704 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
7707 if (ret != 1 && from_caller) {
7708 // unresolved eax - probably void func
7712 if (j >= 0 && ops[j].op == OP_CALL) {
7713 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
7724 l = regmask_save | regmask_dst;
7725 if (g_bp_frame && !(po->flags & OPF_EBP_S))
7728 l = po->regmask_src & ~l;
7731 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
7732 l, regmask_dst, regmask_save, po->flags);
7735 regmask_dst |= po->regmask_dst;
7737 if (po->flags & OPF_TAIL)
7742 static void gen_hdr(const char *funcn, int opcnt)
7744 int save_arg_vars[MAX_ARG_GRP] = { 0, };
7745 unsigned char cbits[MAX_OPS / 8];
7746 const struct parsed_proto *pp_c;
7747 struct parsed_proto *pp;
7748 struct func_prototype *fp;
7749 struct parsed_op *po;
7750 int regmask_dummy = 0;
7752 int max_bp_offset = 0;
7757 pp_c = proto_parse(g_fhdr, funcn, 1);
7759 // already in seed, will add to hg_fp later
7762 fp = hg_fp_add(funcn);
7764 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
7765 g_stack_frame_used = 0;
7768 // - resolve all branches
7769 // - parse calls with labels
7770 resolve_branches_parse_calls(opcnt);
7773 // - handle ebp/esp frame, remove ops related to it
7774 scan_prologue_epilogue(opcnt);
7777 // - remove dead labels
7779 for (i = 0; i < opcnt; i++)
7781 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7787 if (po->flags & (OPF_RMD|OPF_DONE))
7790 if (po->op == OP_CALL) {
7791 if (po->operand[0].type == OPT_LABEL)
7792 hg_fp_add_dep(fp, opr_name(po, 0));
7793 else if (po->pp != NULL)
7794 hg_fp_add_dep(fp, po->pp->name);
7799 // - remove dead labels
7800 // - handle push <const>/pop pairs
7801 for (i = 0; i < opcnt; i++)
7803 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7809 if (po->flags & (OPF_RMD|OPF_DONE))
7812 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
7813 scan_for_pop_const(i, opcnt, i + opcnt * 13);
7817 // - process trivial calls
7818 for (i = 0; i < opcnt; i++)
7821 if (po->flags & (OPF_RMD|OPF_DONE))
7824 if (po->op == OP_CALL)
7826 pp = process_call_early(i, opcnt, &j);
7828 if (!(po->flags & OPF_ATAIL))
7829 // since we know the args, try to collect them
7830 if (collect_call_args_early(i, pp, NULL, NULL) != 0)
7836 // commit esp adjust
7837 if (ops[j].op != OP_POP)
7838 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
7840 for (l = 0; l < pp->argc_stack; l++)
7841 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
7845 po->flags |= OPF_DONE;
7851 // - track saved regs (simple)
7853 for (i = 0; i < opcnt; i++)
7856 if (po->flags & (OPF_RMD|OPF_DONE))
7859 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
7860 && po->operand[0].reg != xCX)
7862 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
7864 // regmask_save |= 1 << po->operand[0].reg; // do it later
7865 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
7866 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
7869 else if (po->op == OP_CALL)
7871 pp = process_call(i, opcnt);
7873 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
7874 // since we know the args, collect them
7875 ret = collect_call_args(po, i, pp, ®mask_dummy, save_arg_vars,
7882 memset(cbits, 0, sizeof(cbits));
7886 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, ®mask_dep, &has_ret);
7888 // find unreachable code - must be fixed in IDA
7889 for (i = 0; i < opcnt; i++)
7891 if (cbits[i >> 3] & (1 << (i & 7)))
7894 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
7895 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
7897 // the compiler sometimes still generates code after
7898 // noreturn OS functions
7901 if (ops[i].op != OP_NOP)
7902 ferr(&ops[i], "unreachable code\n");
7905 for (i = 0; i < g_eqcnt; i++) {
7906 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
7907 max_bp_offset = g_eqs[i].offset;
7910 if (fp->argc_stack < 0) {
7911 max_bp_offset = (max_bp_offset + 3) & ~3;
7912 fp->argc_stack = max_bp_offset / 4;
7913 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
7917 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
7918 fp->has_ret = has_ret;
7920 printf("// has_ret %d, regmask_dep %x\n",
7921 fp->has_ret, fp->regmask_dep);
7922 output_hdr_fp(stdout, fp, 1);
7923 if (IS(funcn, "sub_10007F72")) exit(1);
7926 gen_x_cleanup(opcnt);
7929 static void hg_fp_resolve_deps(struct func_prototype *fp)
7931 struct func_prototype fp_s;
7935 // this thing is recursive, so mark first..
7936 fp->dep_resolved = 1;
7938 for (i = 0; i < fp->dep_func_cnt; i++) {
7939 strcpy(fp_s.name, fp->dep_func[i].name);
7940 fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
7941 sizeof(hg_fp[0]), hg_fp_cmp_name);
7942 if (fp->dep_func[i].proto != NULL) {
7943 if (!fp->dep_func[i].proto->dep_resolved)
7944 hg_fp_resolve_deps(fp->dep_func[i].proto);
7946 dep = ~fp->dep_func[i].regmask_live
7947 & fp->dep_func[i].proto->regmask_dep;
7948 fp->regmask_dep |= dep;
7949 // printf("dep %s %s |= %x\n", fp->name,
7950 // fp->dep_func[i].name, dep);
7952 if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
7953 fp->has_ret = fp->dep_func[i].proto->has_ret;
7958 // make all thiscall/edx arg functions referenced from .data fastcall
7959 static void do_func_refs_from_data(void)
7961 struct func_prototype *fp, fp_s;
7964 for (i = 0; i < hg_ref_cnt; i++) {
7965 strcpy(fp_s.name, hg_refs[i]);
7966 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
7967 sizeof(hg_fp[0]), hg_fp_cmp_name);
7971 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
7972 fp->regmask_dep |= mxCX | mxDX;
7976 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7979 const struct parsed_proto *pp;
7980 char *p, namebuf[NAMELEN];
7986 for (; count > 0; count--, fp++) {
7987 if (fp->has_ret == -1)
7988 fprintf(fout, "// ret unresolved\n");
7990 fprintf(fout, "// dep:");
7991 for (j = 0; j < fp->dep_func_cnt; j++) {
7992 fprintf(fout, " %s/", fp->dep_func[j].name);
7993 if (fp->dep_func[j].proto != NULL)
7994 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
7995 fp->dep_func[j].proto->has_ret);
7997 fprintf(fout, "\n");
8000 p = strchr(fp->name, '@');
8002 memcpy(namebuf, fp->name, p - fp->name);
8003 namebuf[p - fp->name] = 0;
8011 pp = proto_parse(g_fhdr, name, 1);
8012 if (pp != NULL && pp->is_include)
8015 if (fp->pp != NULL) {
8016 // part of seed, output later
8020 regmask_dep = fp->regmask_dep;
8021 argc_normal = fp->argc_stack;
8023 fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
8024 (fp->has_ret ? "int" : "void"));
8025 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
8026 && (regmask_dep & ~mxCX) == 0)
8028 fprintf(fout, "/*__thiscall*/ ");
8032 else if (regmask_dep && (fp->is_stdcall || fp->argc_stack == 0)
8033 && (regmask_dep & ~(mxCX | mxDX)) == 0)
8035 fprintf(fout, " __fastcall ");
8036 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8042 else if (regmask_dep && !fp->is_stdcall) {
8043 fprintf(fout, "/*__usercall*/ ");
8045 else if (regmask_dep) {
8046 fprintf(fout, "/*__userpurge*/ ");
8048 else if (fp->is_stdcall)
8049 fprintf(fout, " __stdcall ");
8051 fprintf(fout, " __cdecl ");
8053 fprintf(fout, "%s(", name);
8056 for (j = 0; j < xSP; j++) {
8057 if (regmask_dep & (1 << j)) {
8060 fprintf(fout, ", ");
8062 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8064 fprintf(fout, "int");
8065 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
8069 for (j = 0; j < argc_normal; j++) {
8072 fprintf(fout, ", ");
8073 if (fp->pp != NULL) {
8074 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8075 if (!fp->pp->arg[arg - 1].type.is_ptr)
8079 fprintf(fout, "int ");
8080 fprintf(fout, "a%d", arg);
8083 fprintf(fout, ");\n");
8087 static void output_hdr(FILE *fout)
8089 static const char *lmod_c_names[] = {
8090 [OPLM_UNSPEC] = "???",
8091 [OPLM_BYTE] = "uint8_t",
8092 [OPLM_WORD] = "uint16_t",
8093 [OPLM_DWORD] = "uint32_t",
8094 [OPLM_QWORD] = "uint64_t",
8096 const struct scanned_var *var;
8097 struct func_prototype *fp;
8098 char line[256] = { 0, };
8102 // add stuff from headers
8103 for (i = 0; i < pp_cache_size; i++) {
8104 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
8105 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
8107 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
8108 fp = hg_fp_add(name);
8109 fp->pp = &pp_cache[i];
8110 fp->argc_stack = fp->pp->argc_stack;
8111 fp->is_stdcall = fp->pp->is_stdcall;
8112 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
8113 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
8117 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
8118 for (i = 0; i < hg_fp_cnt; i++)
8119 hg_fp_resolve_deps(&hg_fp[i]);
8121 // adjust functions referenced from data segment
8122 do_func_refs_from_data();
8124 // note: messes up .proto ptr, don't use
8125 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
8128 for (i = 0; i < hg_var_cnt; i++) {
8131 if (var->pp != NULL)
8134 else if (var->is_c_str)
8135 fprintf(fout, "extern %-8s %s[];", "char", var->name);
8137 fprintf(fout, "extern %-8s %s;",
8138 lmod_c_names[var->lmod], var->name);
8141 fprintf(fout, " // seeded");
8142 fprintf(fout, "\n");
8145 fprintf(fout, "\n");
8147 // output function prototypes
8148 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
8151 fprintf(fout, "\n// - seed -\n");
8154 while (fgets(line, sizeof(line), g_fhdr))
8155 fwrite(line, 1, strlen(line), fout);
8158 // '=' needs special treatment
8160 static char *next_word_s(char *w, size_t wsize, char *s)
8167 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
8169 for (i = 1; i < wsize - 1; i++) {
8171 printf("warning: missing closing quote: \"%s\"\n", s);
8180 for (; i < wsize - 1; i++) {
8181 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
8187 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
8188 printf("warning: '%s' truncated\n", w);
8193 static int cmpstringp(const void *p1, const void *p2)
8195 return strcmp(*(char * const *)p1, *(char * const *)p2);
8198 static int is_xref_needed(char *p, char **rlist, int rlist_len)
8203 if (strstr(p, "..."))
8204 // unable to determine, assume needed
8207 if (*p == '.') // .text, .data, ...
8208 // ref from other data or non-function -> no
8211 p2 = strpbrk(p, "+:\r\n\x18");
8214 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8215 // referenced from removed code
8221 static int ida_xrefs_show_need(FILE *fasm, char *p,
8222 char **rlist, int rlist_len)
8228 p = strrchr(p, ';');
8229 if (p != NULL && *p == ';' && IS_START(p + 2, "DATA XREF: ")) {
8231 if (is_xref_needed(p, rlist, rlist_len))
8238 if (!my_fgets(line, sizeof(line), fasm))
8240 // non-first line is always indented
8241 if (!my_isblank(line[0]))
8244 // should be no content, just comment
8249 p = strrchr(p, ';');
8251 // it's printed once, but no harm to check again
8252 if (IS_START(p, "DATA XREF: "))
8255 if (is_xref_needed(p, rlist, rlist_len)) {
8260 fseek(fasm, pos, SEEK_SET);
8264 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
8266 struct scanned_var *var;
8267 char line[256] = { 0, };
8276 // skip to next data section
8277 while (my_fgets(line, sizeof(line), fasm))
8282 if (*p == 0 || *p == ';')
8285 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
8286 if (*p == 0 || *p == ';')
8289 if (*p != 's' || !IS_START(p, "segment para public"))
8295 if (p == NULL || !IS_START(p, "segment para public"))
8299 if (!IS_START(p, "'DATA'"))
8303 while (my_fgets(line, sizeof(line), fasm))
8308 no_identifier = my_isblank(*p);
8311 if (*p == 0 || *p == ';')
8314 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8315 words[wordc][0] = 0;
8316 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8317 if (*p == 0 || *p == ';') {
8323 if (wordc == 2 && IS(words[1], "ends"))
8328 if (no_identifier) {
8329 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
8330 hg_ref_add(words[2]);
8334 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
8335 // when this starts, we don't need anything from this section
8339 // check refs comment(s)
8340 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
8343 if ((hg_var_cnt & 0xff) == 0) {
8344 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
8345 * (hg_var_cnt + 0x100));
8346 my_assert_not(hg_vars, NULL);
8347 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
8350 var = &hg_vars[hg_var_cnt++];
8351 snprintf(var->name, sizeof(var->name), "%s", words[0]);
8353 // maybe already in seed header?
8354 var->pp = proto_parse(g_fhdr, var->name, 1);
8355 if (var->pp != NULL) {
8356 if (var->pp->is_fptr) {
8357 var->lmod = OPLM_DWORD;
8360 else if (var->pp->is_func)
8362 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
8363 aerr("unhandled C type '%s' for '%s'\n",
8364 var->pp->type.name, var->name);
8370 if (IS(words[1], "dd")) {
8371 var->lmod = OPLM_DWORD;
8372 if (wordc >= 4 && IS(words[2], "offset"))
8373 hg_ref_add(words[3]);
8375 else if (IS(words[1], "dw"))
8376 var->lmod = OPLM_WORD;
8377 else if (IS(words[1], "db")) {
8378 var->lmod = OPLM_BYTE;
8379 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
8380 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
8384 else if (IS(words[1], "dq"))
8385 var->lmod = OPLM_QWORD;
8386 //else if (IS(words[1], "dt"))
8388 aerr("type '%s' not known\n", words[1]);
8396 static void set_label(int i, const char *name)
8402 p = strchr(name, ':');
8406 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
8407 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
8408 g_labels[i] = realloc(g_labels[i], len + 1);
8409 my_assert_not(g_labels[i], NULL);
8410 memcpy(g_labels[i], name, len);
8411 g_labels[i][len] = 0;
8420 static struct chunk_item *func_chunks;
8421 static int func_chunk_cnt;
8422 static int func_chunk_alloc;
8424 static void add_func_chunk(FILE *fasm, const char *name, int line)
8426 if (func_chunk_cnt >= func_chunk_alloc) {
8427 func_chunk_alloc *= 2;
8428 func_chunks = realloc(func_chunks,
8429 func_chunk_alloc * sizeof(func_chunks[0]));
8430 my_assert_not(func_chunks, NULL);
8432 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
8433 func_chunks[func_chunk_cnt].name = strdup(name);
8434 func_chunks[func_chunk_cnt].asmln = line;
8438 static int cmp_chunks(const void *p1, const void *p2)
8440 const struct chunk_item *c1 = p1, *c2 = p2;
8441 return strcmp(c1->name, c2->name);
8444 static void scan_ahead(FILE *fasm)
8454 oldpos = ftell(fasm);
8457 while (my_fgets(line, sizeof(line), fasm))
8468 // get rid of random tabs
8469 for (i = 0; line[i] != 0; i++)
8470 if (line[i] == '\t')
8473 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8476 next_word(words[0], sizeof(words[0]), p);
8477 if (words[0][0] == 0)
8478 aerr("missing name for func chunk?\n");
8480 add_func_chunk(fasm, words[0], asmln);
8482 else if (IS_START(p, "; sctend"))
8488 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8489 words[wordc][0] = 0;
8490 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8491 if (*p == 0 || *p == ';') {
8497 if (wordc == 2 && IS(words[1], "ends"))
8501 fseek(fasm, oldpos, SEEK_SET);
8505 int main(int argc, char *argv[])
8507 FILE *fout, *fasm, *frlist;
8508 struct parsed_data *pd = NULL;
8510 char **rlist = NULL;
8512 int rlist_alloc = 0;
8513 int func_chunks_used = 0;
8514 int func_chunks_sorted = 0;
8515 int func_chunk_i = -1;
8516 long func_chunk_ret = 0;
8517 int func_chunk_ret_ln = 0;
8518 int scanned_ahead = 0;
8520 char words[20][256];
8521 enum opr_lenmod lmod;
8522 char *sctproto = NULL;
8524 int pending_endp = 0;
8526 int skip_warned = 0;
8539 for (arg = 1; arg < argc; arg++) {
8540 if (IS(argv[arg], "-v"))
8542 else if (IS(argv[arg], "-rf"))
8543 g_allow_regfunc = 1;
8544 else if (IS(argv[arg], "-m"))
8546 else if (IS(argv[arg], "-hdr"))
8547 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
8552 if (argc < arg + 3) {
8553 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
8554 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
8556 " -hdr - header generation mode\n"
8557 " -rf - allow unannotated indirect calls\n"
8558 " -m - allow multiple .text sections\n"
8559 "[rlist] is a file with function names to skip,"
8567 asmfn = argv[arg++];
8568 fasm = fopen(asmfn, "r");
8569 my_assert_not(fasm, NULL);
8571 hdrfn = argv[arg++];
8572 g_fhdr = fopen(hdrfn, "r");
8573 my_assert_not(g_fhdr, NULL);
8576 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
8577 my_assert_not(rlist, NULL);
8578 // needs special handling..
8579 rlist[rlist_len++] = "__alloca_probe";
8581 func_chunk_alloc = 32;
8582 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
8583 my_assert_not(func_chunks, NULL);
8585 memset(words, 0, sizeof(words));
8587 for (; arg < argc; arg++) {
8588 frlist = fopen(argv[arg], "r");
8589 my_assert_not(frlist, NULL);
8591 while (my_fgets(line, sizeof(line), frlist)) {
8593 if (*p == 0 || *p == ';')
8596 if (IS_START(p, "#if 0")
8597 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
8601 else if (IS_START(p, "#endif"))
8608 p = next_word(words[0], sizeof(words[0]), p);
8609 if (words[0][0] == 0)
8612 if (rlist_len >= rlist_alloc) {
8613 rlist_alloc = rlist_alloc * 2 + 64;
8614 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
8615 my_assert_not(rlist, NULL);
8617 rlist[rlist_len++] = strdup(words[0]);
8626 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
8628 fout = fopen(argv[arg_out], "w");
8629 my_assert_not(fout, NULL);
8632 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
8633 my_assert_not(g_eqs, NULL);
8635 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
8636 g_label_refs[i].i = -1;
8637 g_label_refs[i].next = NULL;
8641 scan_variables(fasm, rlist, rlist_len);
8643 while (my_fgets(line, sizeof(line), fasm))
8652 // get rid of random tabs
8653 for (i = 0; line[i] != 0; i++)
8654 if (line[i] == '\t')
8659 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
8660 goto do_pending_endp; // eww..
8662 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
8664 static const char *attrs[] = {
8673 // parse IDA's attribute-list comment
8674 g_ida_func_attr = 0;
8677 for (; *p != 0; p = sskip(p)) {
8678 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8679 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8680 g_ida_func_attr |= 1 << i;
8681 p += strlen(attrs[i]);
8685 if (i == ARRAY_SIZE(attrs)) {
8686 anote("unparsed IDA attr: %s\n", p);
8689 if (IS(attrs[i], "fpd=")) {
8690 p = next_word(words[0], sizeof(words[0]), p);
8695 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
8697 static const char *attrs[] = {
8702 // parse manual attribute-list comment
8703 g_sct_func_attr = 0;
8706 for (; *p != 0; p = sskip(p)) {
8707 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8708 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8709 g_sct_func_attr |= 1 << i;
8710 p += strlen(attrs[i]);
8717 // clear_sf=start,len (in dwords)
8718 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
8719 &g_stack_clear_len, &j);
8721 // clear_regmask=<mask>
8722 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
8724 anote("unparsed attr value: %s\n", p);
8729 else if (i == ARRAY_SIZE(attrs)) {
8730 anote("unparsed sct attr: %s\n", p);
8735 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8738 next_word(words[0], sizeof(words[0]), p);
8739 if (words[0][0] == 0)
8740 aerr("missing name for func chunk?\n");
8742 if (!scanned_ahead) {
8743 add_func_chunk(fasm, words[0], asmln);
8744 func_chunks_sorted = 0;
8747 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
8749 if (func_chunk_i >= 0) {
8750 if (func_chunk_i < func_chunk_cnt
8751 && IS(func_chunks[func_chunk_i].name, g_func))
8753 // move on to next chunk
8754 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
8756 aerr("seek failed for '%s' chunk #%d\n",
8757 g_func, func_chunk_i);
8758 asmln = func_chunks[func_chunk_i].asmln;
8762 if (func_chunk_ret == 0)
8763 aerr("no return from chunk?\n");
8764 fseek(fasm, func_chunk_ret, SEEK_SET);
8765 asmln = func_chunk_ret_ln;
8771 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
8772 func_chunks_used = 1;
8774 if (IS_START(g_func, "sub_")) {
8775 unsigned long addr = strtoul(p, NULL, 16);
8776 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
8777 if (addr > f_addr && !scanned_ahead) {
8778 //anote("scan_ahead caused by '%s', addr %lx\n",
8782 func_chunks_sorted = 0;
8790 for (i = wordc; i < ARRAY_SIZE(words); i++)
8792 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8793 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8794 if (*p == 0 || *p == ';') {
8799 if (*p != 0 && *p != ';')
8800 aerr("too many words\n");
8802 // alow asm patches in comments
8804 if (IS_START(p, "; sctpatch:")) {
8806 if (*p == 0 || *p == ';')
8808 goto parse_words; // lame
8810 if (IS_START(p, "; sctproto:")) {
8811 sctproto = strdup(p + 11);
8813 else if (IS_START(p, "; sctend")) {
8822 awarn("wordc == 0?\n");
8826 // don't care about this:
8827 if (words[0][0] == '.'
8828 || IS(words[0], "include")
8829 || IS(words[0], "assume") || IS(words[1], "segment")
8830 || IS(words[0], "align"))
8836 // do delayed endp processing to collect switch jumptables
8838 if (in_func && !g_skip_func && !end && wordc >= 2
8839 && ((words[0][0] == 'd' && words[0][2] == 0)
8840 || (words[1][0] == 'd' && words[1][2] == 0)))
8843 if (words[1][0] == 'd' && words[1][2] == 0) {
8845 if (g_func_pd_cnt >= pd_alloc) {
8846 pd_alloc = pd_alloc * 2 + 16;
8847 g_func_pd = realloc(g_func_pd,
8848 sizeof(g_func_pd[0]) * pd_alloc);
8849 my_assert_not(g_func_pd, NULL);
8851 pd = &g_func_pd[g_func_pd_cnt];
8853 memset(pd, 0, sizeof(*pd));
8854 strcpy(pd->label, words[0]);
8855 pd->type = OPT_CONST;
8856 pd->lmod = lmod_from_directive(words[1]);
8862 anote("skipping alignment byte?\n");
8865 lmod = lmod_from_directive(words[0]);
8866 if (lmod != pd->lmod)
8867 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
8870 if (pd->count_alloc < pd->count + wordc) {
8871 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
8872 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
8873 my_assert_not(pd->d, NULL);
8875 for (; i < wordc; i++) {
8876 if (IS(words[i], "offset")) {
8877 pd->type = OPT_OFFSET;
8880 p = strchr(words[i], ',');
8883 if (pd->type == OPT_OFFSET)
8884 pd->d[pd->count].u.label = strdup(words[i]);
8886 pd->d[pd->count].u.val = parse_number(words[i]);
8887 pd->d[pd->count].bt_i = -1;
8893 if (in_func && !g_skip_func) {
8895 gen_hdr(g_func, pi);
8897 gen_func(fout, g_fhdr, g_func, pi);
8902 g_ida_func_attr = 0;
8903 g_sct_func_attr = 0;
8904 g_stack_clear_start = 0;
8905 g_stack_clear_len = 0;
8910 func_chunks_used = 0;
8913 memset(&ops, 0, pi * sizeof(ops[0]));
8918 for (i = 0; i < g_func_pd_cnt; i++) {
8920 if (pd->type == OPT_OFFSET) {
8921 for (j = 0; j < pd->count; j++)
8922 free(pd->d[j].u.label);
8937 if (IS(words[1], "proc")) {
8939 aerr("proc '%s' while in_func '%s'?\n",
8942 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8944 strcpy(g_func, words[0]);
8945 set_label(0, words[0]);
8950 if (IS(words[1], "endp"))
8953 aerr("endp '%s' while not in_func?\n", words[0]);
8954 if (!IS(g_func, words[0]))
8955 aerr("endp '%s' while in_func '%s'?\n",
8958 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
8959 && ops[0].op == OP_JMP && ops[0].operand[0].had_ds)
8965 if (!g_skip_func && func_chunks_used) {
8966 // start processing chunks
8967 struct chunk_item *ci, key = { g_func, 0 };
8969 func_chunk_ret = ftell(fasm);
8970 func_chunk_ret_ln = asmln;
8971 if (!func_chunks_sorted) {
8972 qsort(func_chunks, func_chunk_cnt,
8973 sizeof(func_chunks[0]), cmp_chunks);
8974 func_chunks_sorted = 1;
8976 ci = bsearch(&key, func_chunks, func_chunk_cnt,
8977 sizeof(func_chunks[0]), cmp_chunks);
8979 aerr("'%s' needs chunks, but none found\n", g_func);
8980 func_chunk_i = ci - func_chunks;
8981 for (; func_chunk_i > 0; func_chunk_i--)
8982 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
8985 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
8987 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
8988 asmln = func_chunks[func_chunk_i].asmln;
8996 if (wordc == 2 && IS(words[1], "ends")) {
9000 goto do_pending_endp;
9004 // scan for next text segment
9005 while (my_fgets(line, sizeof(line), fasm)) {
9008 if (*p == 0 || *p == ';')
9011 if (strstr(p, "segment para public 'CODE' use32"))
9018 p = strchr(words[0], ':');
9020 set_label(pi, words[0]);
9024 if (!in_func || g_skip_func) {
9025 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
9027 anote("skipping from '%s'\n", g_labels[pi]);
9031 g_labels[pi] = NULL;
9035 if (wordc > 1 && IS(words[1], "="))
9038 aerr("unhandled equ, wc=%d\n", wordc);
9039 if (g_eqcnt >= eq_alloc) {
9041 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
9042 my_assert_not(g_eqs, NULL);
9045 len = strlen(words[0]);
9046 if (len > sizeof(g_eqs[0].name) - 1)
9047 aerr("equ name too long: %d\n", len);
9048 strcpy(g_eqs[g_eqcnt].name, words[0]);
9050 if (!IS(words[3], "ptr"))
9051 aerr("unhandled equ\n");
9052 if (IS(words[2], "dword"))
9053 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
9054 else if (IS(words[2], "word"))
9055 g_eqs[g_eqcnt].lmod = OPLM_WORD;
9056 else if (IS(words[2], "byte"))
9057 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
9058 else if (IS(words[2], "qword"))
9059 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
9061 aerr("bad lmod: '%s'\n", words[2]);
9063 g_eqs[g_eqcnt].offset = parse_number(words[4]);
9068 if (pi >= ARRAY_SIZE(ops))
9069 aerr("too many ops\n");
9071 parse_op(&ops[pi], words, wordc);
9073 ops[pi].datap = sctproto;
9088 // vim:ts=2:shiftwidth=2:expandtab