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 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1786 eq = equ_find(po, bp_arg, &offset);
1788 ferr(po, "detected but missing eq\n");
1789 offset += eq->offset;
1792 if (!strncmp(name, "ebp", 3))
1795 // yes it sometimes LEAs ra for compares..
1796 if (!is_lea && ofs_reg[0] == 0
1797 && stack_ra <= offset && offset < stack_ra + 4)
1799 ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1802 *offset_out = offset;
1804 *stack_ra_out = stack_ra;
1806 *bp_arg_out = bp_arg;
1809 static int parse_stack_esp_offset(struct parsed_op *po,
1810 const char *name, int *offset_out)
1812 char ofs_reg[16] = { 0, };
1813 struct parsed_equ *eq;
1819 if (strstr(name, "esp") == NULL)
1821 bp_arg = parse_stack_el(name, ofs_reg, &base_val, 0);
1822 if (bp_arg == NULL) {
1823 // just plain offset?
1824 if (!IS_START(name, "esp+"))
1826 offset = strtol(name + 4, &endp, 0);
1827 if (endp == NULL || *endp != 0)
1829 *offset_out = offset;
1833 if (ofs_reg[0] != 0)
1835 eq = equ_find(po, bp_arg, &offset);
1837 ferr(po, "detected but missing eq\n");
1838 offset += eq->offset;
1839 *offset_out = base_val + offset;
1843 static int stack_frame_access(struct parsed_op *po,
1844 struct parsed_opr *popr, char *buf, size_t buf_size,
1845 const char *name, const char *cast, int is_src, int is_lea)
1847 enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1848 const char *prefix = "";
1849 const char *bp_arg = NULL;
1850 char ofs_reg[16] = { 0, };
1851 int i, arg_i, arg_s;
1859 if (po->flags & OPF_EBP_S)
1860 ferr(po, "stack_frame_access while ebp is scratch\n");
1862 parse_stack_access(po, name, ofs_reg, &offset,
1863 &stack_ra, &bp_arg, is_lea);
1865 if (offset > stack_ra)
1867 arg_i = (offset - stack_ra - 4) / 4;
1868 if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1870 if (g_func_pp->is_vararg
1871 && arg_i == g_func_pp->argc_stack && is_lea)
1873 // should be va_list
1876 snprintf(buf, buf_size, "%sap", cast);
1879 ferr(po, "offset %d (%s,%d) doesn't map to any arg\n",
1880 offset, bp_arg, arg_i);
1882 if (ofs_reg[0] != 0)
1883 ferr(po, "offset reg on arg access?\n");
1885 for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1886 if (g_func_pp->arg[i].reg != NULL)
1892 if (i == g_func_pp->argc)
1893 ferr(po, "arg %d not in prototype?\n", arg_i);
1895 popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
1902 ferr(po, "lea/byte to arg?\n");
1903 if (is_src && (offset & 3) == 0)
1904 snprintf(buf, buf_size, "%sa%d",
1905 simplify_cast(cast, "(u8)"), i + 1);
1907 snprintf(buf, buf_size, "%sBYTE%d(a%d)",
1908 cast, offset & 3, i + 1);
1913 ferr(po, "lea/word to arg?\n");
1918 ferr(po, "problematic arg store\n");
1919 snprintf(buf, buf_size, "%s((char *)&a%d + 1)",
1920 simplify_cast(cast, "*(u16 *)"), i + 1);
1923 ferr(po, "unaligned arg word load\n");
1925 else if (is_src && (offset & 2) == 0)
1926 snprintf(buf, buf_size, "%sa%d",
1927 simplify_cast(cast, "(u16)"), i + 1);
1929 snprintf(buf, buf_size, "%s%sWORD(a%d)",
1930 cast, (offset & 2) ? "HI" : "LO", i + 1);
1942 snprintf(buf, buf_size, "(u32)&a%d + %d",
1945 ferr(po, "unaligned arg store\n");
1947 // mov edx, [ebp+arg_4+2]; movsx ecx, dx
1948 snprintf(buf, buf_size, "%s(a%d >> %d)",
1949 prefix, i + 1, (offset & 3) * 8);
1953 snprintf(buf, buf_size, "%s%sa%d",
1954 prefix, is_lea ? "&" : "", i + 1);
1959 ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
1963 snprintf(g_comment, sizeof(g_comment), "%s unaligned", bp_arg);
1966 guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
1967 if (tmp_lmod != OPLM_DWORD
1968 && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
1969 < lmod_bytes(po, popr->lmod) + (offset & 3))))
1971 ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
1972 i + 1, offset, g_func_pp->arg[i].type.name);
1974 // can't check this because msvc likes to reuse
1975 // arg space for scratch..
1976 //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
1977 // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
1981 if (g_stack_fsz == 0)
1982 ferr(po, "stack var access without stackframe\n");
1983 g_stack_frame_used = 1;
1985 sf_ofs = g_stack_fsz + offset;
1986 lim = (ofs_reg[0] != 0) ? -4 : 0;
1987 if (offset > 0 || sf_ofs < lim)
1988 ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
1998 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1999 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2003 if ((sf_ofs & 1) || ofs_reg[0] != 0) {
2004 // known unaligned or possibly unaligned
2005 strcat(g_comment, " unaligned");
2007 prefix = "*(u16 *)&";
2008 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2009 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2012 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
2016 if ((sf_ofs & 3) || ofs_reg[0] != 0) {
2017 // known unaligned or possibly unaligned
2018 strcat(g_comment, " unaligned");
2020 prefix = "*(u32 *)&";
2021 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2022 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2025 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
2029 ferr_assert(po, !(sf_ofs & 7));
2030 ferr_assert(po, ofs_reg[0] == 0);
2031 // float callers set is_lea
2032 ferr_assert(po, is_lea);
2033 snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
2037 ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
2044 static void check_func_pp(struct parsed_op *po,
2045 const struct parsed_proto *pp, const char *pfx)
2047 enum opr_lenmod tmp_lmod;
2051 if (pp->argc_reg != 0) {
2052 if (/*!g_allow_regfunc &&*/ !pp->is_fastcall) {
2053 pp_print(buf, sizeof(buf), pp);
2054 ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
2056 if (pp->argc_stack > 0 && pp->argc_reg != 2)
2057 ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
2058 pfx, pp->argc_reg, pp->argc_stack);
2061 // fptrs must use 32bit args, callsite might have no information and
2062 // lack a cast to smaller types, which results in incorrectly masked
2063 // args passed (callee may assume masked args, it does on ARM)
2064 if (!pp->is_osinc) {
2065 for (i = 0; i < pp->argc; i++) {
2066 ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
2067 if (ret && tmp_lmod != OPLM_DWORD)
2068 ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
2069 i + 1, pp->arg[i].type.name);
2074 static const char *check_label_read_ref(struct parsed_op *po,
2077 const struct parsed_proto *pp;
2079 pp = proto_parse(g_fhdr, name, 0);
2081 ferr(po, "proto_parse failed for ref '%s'\n", name);
2084 check_func_pp(po, pp, "ref");
2089 static char *out_src_opr(char *buf, size_t buf_size,
2090 struct parsed_op *po, struct parsed_opr *popr, const char *cast,
2093 char tmp1[256], tmp2[256];
2102 switch (popr->type) {
2105 ferr(po, "lea from reg?\n");
2107 switch (popr->lmod) {
2109 snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2112 snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2115 snprintf(buf, buf_size, "%s%s",
2116 simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2119 if (popr->name[1] == 'h') // XXX..
2120 snprintf(buf, buf_size, "%s(%s >> 8)",
2121 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2123 snprintf(buf, buf_size, "%s%s",
2124 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2127 ferr(po, "invalid src lmod: %d\n", popr->lmod);
2132 if (is_stack_access(po, popr)) {
2133 stack_frame_access(po, popr, buf, buf_size,
2134 popr->name, cast, 1, is_lea);
2138 strcpy(expr, popr->name);
2139 if (strchr(expr, '[')) {
2140 // special case: '[' can only be left for label[reg] form
2141 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2143 ferr(po, "parse failure for '%s'\n", expr);
2144 if (tmp1[0] == '(') {
2145 // (off_4FFF50+3)[eax]
2146 p = strchr(tmp1 + 1, ')');
2147 if (p == NULL || p[1] != 0)
2148 ferr(po, "parse failure (2) for '%s'\n", expr);
2150 memmove(tmp1, tmp1 + 1, strlen(tmp1));
2152 snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2155 // XXX: do we need more parsing?
2157 snprintf(buf, buf_size, "%s", expr);
2161 snprintf(buf, buf_size, "%s(%s)",
2162 simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2166 name = check_label_read_ref(po, popr->name);
2167 if (cast[0] == 0 && popr->is_ptr)
2171 snprintf(buf, buf_size, "(u32)&%s", name);
2172 else if (popr->size_lt)
2173 snprintf(buf, buf_size, "%s%s%s%s", cast,
2174 lmod_cast_u_ptr(po, popr->lmod),
2175 popr->is_array ? "" : "&", name);
2177 snprintf(buf, buf_size, "%s%s%s", cast, name,
2178 popr->is_array ? "[0]" : "");
2182 name = check_label_read_ref(po, popr->name);
2186 ferr(po, "lea an offset?\n");
2187 snprintf(buf, buf_size, "%s&%s", cast, name);
2192 ferr(po, "lea from const?\n");
2194 printf_number(tmp1, sizeof(tmp1), popr->val);
2195 if (popr->val == 0 && strchr(cast, '*'))
2196 snprintf(buf, buf_size, "NULL");
2198 snprintf(buf, buf_size, "%s%s",
2199 simplify_cast_num(cast, popr->val), tmp1);
2203 ferr(po, "invalid src type: %d\n", popr->type);
2209 // note: may set is_ptr (we find that out late for ebp frame..)
2210 static char *out_dst_opr(char *buf, size_t buf_size,
2211 struct parsed_op *po, struct parsed_opr *popr)
2213 switch (popr->type) {
2215 switch (popr->lmod) {
2217 snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2220 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2224 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2228 if (popr->name[1] == 'h') // XXX..
2229 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2231 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2234 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2239 if (is_stack_access(po, popr)) {
2240 stack_frame_access(po, popr, buf, buf_size,
2241 popr->name, "", 0, 0);
2245 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2248 if (popr->size_mismatch)
2249 snprintf(buf, buf_size, "%s%s%s",
2250 lmod_cast_u_ptr(po, popr->lmod),
2251 popr->is_array ? "" : "&", popr->name);
2253 snprintf(buf, buf_size, "%s%s", popr->name,
2254 popr->is_array ? "[0]" : "");
2258 ferr(po, "invalid dst type: %d\n", popr->type);
2264 static char *out_src_opr_u32(char *buf, size_t buf_size,
2265 struct parsed_op *po, struct parsed_opr *popr)
2267 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2270 static char *out_src_opr_float(char *buf, size_t buf_size,
2271 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2273 const char *cast = NULL;
2276 switch (popr->type) {
2278 if (popr->reg < xST0 || popr->reg > xST7)
2279 ferr(po, "bad reg: %d\n", popr->reg);
2281 if (need_float_stack) {
2282 if (popr->reg == xST0)
2283 snprintf(buf, buf_size, "f_st[f_stp & 7]");
2285 snprintf(buf, buf_size, "f_st[(f_stp + %d) & 7]",
2289 snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2295 switch (popr->lmod) {
2303 ferr(po, "unhandled lmod: %d\n", popr->lmod);
2306 out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2307 snprintf(buf, buf_size, "*((%s *)%s)", cast, tmp);
2311 ferr(po, "invalid float type: %d\n", popr->type);
2317 static char *out_dst_opr_float(char *buf, size_t buf_size,
2318 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2321 return out_src_opr_float(buf, buf_size, po, popr, need_float_stack);
2324 static void out_test_for_cc(char *buf, size_t buf_size,
2325 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2326 enum opr_lenmod lmod, const char *expr)
2328 const char *cast, *scast;
2330 cast = lmod_cast_u(po, lmod);
2331 scast = lmod_cast_s(po, lmod);
2335 case PFO_BE: // CF=1||ZF=1; CF=0
2336 snprintf(buf, buf_size, "(%s%s %s 0)",
2337 cast, expr, is_inv ? "!=" : "==");
2341 case PFO_L: // SF!=OF; OF=0
2342 snprintf(buf, buf_size, "(%s%s %s 0)",
2343 scast, expr, is_inv ? ">=" : "<");
2346 case PFO_LE: // ZF=1||SF!=OF; OF=0
2347 snprintf(buf, buf_size, "(%s%s %s 0)",
2348 scast, expr, is_inv ? ">" : "<=");
2352 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2356 static void out_cmp_for_cc(char *buf, size_t buf_size,
2357 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2360 const char *cast, *scast, *cast_use;
2361 char buf1[256], buf2[256];
2362 enum opr_lenmod lmod;
2364 if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2365 ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2366 po->operand[0].lmod, po->operand[1].lmod);
2367 lmod = po->operand[0].lmod;
2369 cast = lmod_cast_u(po, lmod);
2370 scast = lmod_cast_s(po, lmod);
2386 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2389 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2390 if (po->op == OP_DEC)
2391 snprintf(buf2, sizeof(buf2), "1");
2394 snprintf(cast_op2, sizeof(cast_op2) - 1, "%s", cast_use);
2396 strcat(cast_op2, "-");
2397 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_op2, 0);
2402 // note: must be unsigned compare
2403 snprintf(buf, buf_size, "(%s %s %s)",
2404 buf1, is_inv ? ">=" : "<", buf2);
2408 snprintf(buf, buf_size, "(%s %s %s)",
2409 buf1, is_inv ? "!=" : "==", buf2);
2413 // note: must be unsigned compare
2414 snprintf(buf, buf_size, "(%s %s %s)",
2415 buf1, is_inv ? ">" : "<=", buf2);
2418 if (is_inv && lmod == OPLM_BYTE
2419 && po->operand[1].type == OPT_CONST
2420 && po->operand[1].val == 0xff)
2422 snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2423 snprintf(buf, buf_size, "(0)");
2427 // note: must be signed compare
2429 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2430 scast, buf1, buf2, is_inv ? ">=" : "<");
2434 snprintf(buf, buf_size, "(%s %s %s)",
2435 buf1, is_inv ? ">=" : "<", buf2);
2439 snprintf(buf, buf_size, "(%s %s %s)",
2440 buf1, is_inv ? ">" : "<=", buf2);
2448 static void out_cmp_test(char *buf, size_t buf_size,
2449 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2451 char buf1[256], buf2[256], buf3[256];
2453 if (po->op == OP_TEST) {
2454 if (IS(opr_name(po, 0), opr_name(po, 1))) {
2455 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2458 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2459 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2460 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2462 out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2463 po->operand[0].lmod, buf3);
2465 else if (po->op == OP_CMP) {
2466 out_cmp_for_cc(buf, buf_size, po, pfo, is_inv, 0);
2469 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2472 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2473 struct parsed_opr *popr2)
2475 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2476 ferr(po, "missing lmod for both operands\n");
2478 if (popr1->lmod == OPLM_UNSPEC)
2479 popr1->lmod = popr2->lmod;
2480 else if (popr2->lmod == OPLM_UNSPEC)
2481 popr2->lmod = popr1->lmod;
2482 else if (popr1->lmod != popr2->lmod) {
2483 if (popr1->type_from_var) {
2484 popr1->size_mismatch = 1;
2485 if (popr1->lmod < popr2->lmod)
2487 popr1->lmod = popr2->lmod;
2489 else if (popr2->type_from_var) {
2490 popr2->size_mismatch = 1;
2491 if (popr2->lmod < popr1->lmod)
2493 popr2->lmod = popr1->lmod;
2496 ferr(po, "conflicting lmods: %d vs %d\n",
2497 popr1->lmod, popr2->lmod);
2501 static const char *op_to_c(struct parsed_op *po)
2525 ferr(po, "op_to_c was supplied with %d\n", po->op);
2529 // last op in stream - unconditional branch or ret
2530 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2531 || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2532 && ops[_i].op != OP_CALL))
2534 #define check_i(po, i) \
2536 ferr(po, "bad " #i ": %d\n", i)
2538 // note: this skips over calls and rm'd stuff assuming they're handled
2539 // so it's intended to use at one of final passes
2540 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2541 int depth, int flags_set)
2543 struct parsed_op *po;
2548 for (; i < opcnt; i++) {
2550 if (po->cc_scratch == magic)
2551 return ret; // already checked
2552 po->cc_scratch = magic;
2554 if (po->flags & OPF_TAIL) {
2555 if (po->op == OP_CALL) {
2556 if (po->pp != NULL && po->pp->is_noreturn)
2557 // assume no stack cleanup for noreturn
2560 return -1; // deadend
2563 if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
2566 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2567 if (po->btj != NULL) {
2569 for (j = 0; j < po->btj->count; j++) {
2570 check_i(po, po->btj->d[j].bt_i);
2571 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2574 return ret; // dead end
2579 check_i(po, po->bt_i);
2580 if (po->flags & OPF_CJMP) {
2581 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2584 return ret; // dead end
2593 if ((po->op == OP_POP || po->op == OP_PUSH)
2594 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2599 if (po->op == OP_PUSH) {
2602 else if (po->op == OP_POP) {
2603 if (relevant && depth == 0) {
2604 po->flags |= flags_set;
2614 // scan for 'reg' pop backwards starting from i
2615 // intended to use for register restore search, so other reg
2616 // references are considered an error
2617 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2619 struct parsed_op *po;
2620 struct label_ref *lr;
2623 ops[i].cc_scratch = magic;
2627 if (g_labels[i] != NULL) {
2628 lr = &g_label_refs[i];
2629 for (; lr != NULL; lr = lr->next) {
2630 check_i(&ops[i], lr->i);
2631 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2635 if (i > 0 && LAST_OP(i - 1))
2643 if (ops[i].cc_scratch == magic)
2645 ops[i].cc_scratch = magic;
2648 if (po->op == OP_POP && po->operand[0].reg == reg) {
2649 if (po->flags & (OPF_RMD|OPF_DONE))
2652 po->flags |= set_flags;
2656 // this also covers the case where we reach corresponding push
2657 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2661 // nothing interesting on this path
2665 static void find_reachable_exits(int i, int opcnt, int magic,
2666 int *exits, int *exit_count)
2668 struct parsed_op *po;
2671 for (; i < opcnt; i++)
2674 if (po->cc_scratch == magic)
2676 po->cc_scratch = magic;
2678 if (po->flags & OPF_TAIL) {
2679 ferr_assert(po, *exit_count < MAX_EXITS);
2680 exits[*exit_count] = i;
2685 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2686 if (po->flags & OPF_RMD)
2689 if (po->btj != NULL) {
2690 for (j = 0; j < po->btj->count; j++) {
2691 check_i(po, po->btj->d[j].bt_i);
2692 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2698 check_i(po, po->bt_i);
2699 if (po->flags & OPF_CJMP)
2700 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2708 // scan for 'reg' pop backwards starting from exits (all paths)
2709 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2711 static int exits[MAX_EXITS];
2712 static int exit_count;
2717 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2719 ferr_assert(&ops[i], exit_count > 0);
2722 for (j = 0; j < exit_count; j++) {
2723 ret = scan_for_rsave_pop_reg(exits[j], i + opcnt * 16 + set_flags,
2732 // scan for one or more pop of push <const>
2733 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2734 int push_i, int is_probe)
2736 struct parsed_op *po;
2737 struct label_ref *lr;
2741 for (; i < opcnt; i++)
2744 if (po->cc_scratch == magic)
2745 return ret; // already checked
2746 po->cc_scratch = magic;
2748 if (po->flags & OPF_JMP) {
2749 if (po->flags & OPF_RMD)
2751 if (po->op == OP_CALL)
2754 if (po->btj != NULL) {
2755 for (j = 0; j < po->btj->count; j++) {
2756 check_i(po, po->btj->d[j].bt_i);
2757 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2765 check_i(po, po->bt_i);
2766 if (po->flags & OPF_CJMP) {
2767 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2778 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2781 if (g_labels[i] != NULL) {
2782 // all refs must be visited
2783 lr = &g_label_refs[i];
2784 for (; lr != NULL; lr = lr->next) {
2786 if (ops[lr->i].cc_scratch != magic)
2789 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2793 if (po->op == OP_POP)
2795 if (po->flags & (OPF_RMD|OPF_DONE))
2799 po->flags |= OPF_DONE;
2800 po->datap = &ops[push_i];
2809 static void scan_for_pop_const(int i, int opcnt, int magic)
2813 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
2815 ops[i].flags |= OPF_RMD | OPF_DONE;
2816 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
2820 // check if all branch targets within a marked path are also marked
2821 // note: the path checked must not be empty or end with a branch
2822 static int check_path_branches(int opcnt, int magic)
2824 struct parsed_op *po;
2827 for (i = 0; i < opcnt; i++) {
2829 if (po->cc_scratch != magic)
2832 if (po->flags & OPF_JMP) {
2833 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
2836 if (po->btj != NULL) {
2837 for (j = 0; j < po->btj->count; j++) {
2838 check_i(po, po->btj->d[j].bt_i);
2839 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
2844 check_i(po, po->bt_i);
2845 if (ops[po->bt_i].cc_scratch != magic)
2847 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
2855 // scan for multiple pushes for given pop
2856 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
2859 int reg = ops[pop_i].operand[0].reg;
2860 struct parsed_op *po;
2861 struct label_ref *lr;
2864 ops[i].cc_scratch = magic;
2868 if (g_labels[i] != NULL) {
2869 lr = &g_label_refs[i];
2870 for (; lr != NULL; lr = lr->next) {
2871 check_i(&ops[i], lr->i);
2872 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
2876 if (i > 0 && LAST_OP(i - 1))
2884 if (ops[i].cc_scratch == magic)
2886 ops[i].cc_scratch = magic;
2889 if (po->op == OP_CALL)
2891 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
2894 if (po->op == OP_PUSH)
2896 if (po->datap != NULL)
2898 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2899 // leave this case for reg save/restore handlers
2903 po->flags |= OPF_PPUSH | OPF_DONE;
2904 po->datap = &ops[pop_i];
2913 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
2915 int magic = i + opcnt * 14;
2918 ret = scan_pushes_for_pop_r(i, magic, i, 1);
2920 ret = check_path_branches(opcnt, magic);
2922 ops[i].flags |= OPF_PPUSH | OPF_DONE;
2923 *regmask_pp |= 1 << ops[i].operand[0].reg;
2924 scan_pushes_for_pop_r(i, magic + 1, i, 0);
2929 static void scan_propagate_df(int i, int opcnt)
2931 struct parsed_op *po = &ops[i];
2934 for (; i < opcnt; i++) {
2936 if (po->flags & OPF_DF)
2937 return; // already resolved
2938 po->flags |= OPF_DF;
2940 if (po->op == OP_CALL)
2941 ferr(po, "call with DF set?\n");
2943 if (po->flags & OPF_JMP) {
2944 if (po->btj != NULL) {
2946 for (j = 0; j < po->btj->count; j++) {
2947 check_i(po, po->btj->d[j].bt_i);
2948 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
2953 if (po->flags & OPF_RMD)
2955 check_i(po, po->bt_i);
2956 if (po->flags & OPF_CJMP)
2957 scan_propagate_df(po->bt_i, opcnt);
2963 if (po->flags & OPF_TAIL)
2966 if (po->op == OP_CLD) {
2967 po->flags |= OPF_RMD | OPF_DONE;
2972 ferr(po, "missing DF clear?\n");
2975 // is operand 'opr' referenced by parsed_op 'po'?
2976 static int is_opr_referenced(const struct parsed_opr *opr,
2977 const struct parsed_op *po)
2981 if (opr->type == OPT_REG) {
2982 mask = po->regmask_dst | po->regmask_src;
2983 if (po->op == OP_CALL)
2984 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
2985 if ((1 << opr->reg) & mask)
2991 for (i = 0; i < po->operand_cnt; i++)
2992 if (IS(po->operand[0].name, opr->name))
2998 // is operand 'opr' read by parsed_op 'po'?
2999 static int is_opr_read(const struct parsed_opr *opr,
3000 const struct parsed_op *po)
3002 if (opr->type == OPT_REG) {
3003 if (po->regmask_src & (1 << opr->reg))
3013 // is operand 'opr' modified by parsed_op 'po'?
3014 static int is_opr_modified(const struct parsed_opr *opr,
3015 const struct parsed_op *po)
3019 if (opr->type == OPT_REG) {
3020 if (po->op == OP_CALL) {
3021 mask = po->regmask_dst;
3022 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
3023 if (mask & (1 << opr->reg))
3029 if (po->regmask_dst & (1 << opr->reg))
3035 return IS(po->operand[0].name, opr->name);
3038 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
3039 static int is_any_opr_modified(const struct parsed_op *po_test,
3040 const struct parsed_op *po, int c_mode)
3045 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
3048 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3051 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
3054 // in reality, it can wreck any register, but in decompiled C
3055 // version it can only overwrite eax or edx:eax
3056 mask = (1 << xAX) | (1 << xDX);
3060 if (po->op == OP_CALL
3061 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
3064 for (i = 0; i < po_test->operand_cnt; i++)
3065 if (IS(po_test->operand[i].name, po->operand[0].name))
3071 // scan for any po_test operand modification in range given
3072 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
3075 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3078 for (; i < opcnt; i++) {
3079 if (is_any_opr_modified(po_test, &ops[i], c_mode))
3086 // scan for po_test operand[0] modification in range given
3087 static int scan_for_mod_opr0(struct parsed_op *po_test,
3090 for (; i < opcnt; i++) {
3091 if (is_opr_modified(&po_test->operand[0], &ops[i]))
3098 static int try_resolve_const(int i, const struct parsed_opr *opr,
3099 int magic, unsigned int *val);
3101 static int scan_for_flag_set(int i, int opcnt, int magic,
3102 int *branched, int *setters, int *setter_cnt)
3104 struct label_ref *lr;
3108 if (ops[i].cc_scratch == magic) {
3109 // is this a problem?
3110 //ferr(&ops[i], "%s looped\n", __func__);
3113 ops[i].cc_scratch = magic;
3115 if (g_labels[i] != NULL) {
3118 lr = &g_label_refs[i];
3119 for (; lr->next; lr = lr->next) {
3120 check_i(&ops[i], lr->i);
3121 ret = scan_for_flag_set(lr->i, opcnt, magic,
3122 branched, setters, setter_cnt);
3127 check_i(&ops[i], lr->i);
3128 if (i > 0 && LAST_OP(i - 1)) {
3132 ret = scan_for_flag_set(lr->i, opcnt, magic,
3133 branched, setters, setter_cnt);
3139 if (ops[i].flags & OPF_FLAGS) {
3140 setters[*setter_cnt] = i;
3143 if (ops[i].flags & OPF_REP) {
3144 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
3147 ret = try_resolve_const(i, &opr, i + opcnt * 7, &uval);
3148 if (ret != 1 || uval == 0) {
3149 // can't treat it as full setter because of ecx=0 case,
3150 // also disallow delayed compare
3159 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3166 // scan back for cdq, if anything modifies edx, fail
3167 static int scan_for_cdq_edx(int i)
3170 if (g_labels[i] != NULL) {
3171 if (g_label_refs[i].next != NULL)
3173 if (i > 0 && LAST_OP(i - 1)) {
3174 i = g_label_refs[i].i;
3181 if (ops[i].op == OP_CDQ)
3184 if (ops[i].regmask_dst & (1 << xDX))
3191 static int scan_for_reg_clear(int i, int reg)
3194 if (g_labels[i] != NULL) {
3195 if (g_label_refs[i].next != NULL)
3197 if (i > 0 && LAST_OP(i - 1)) {
3198 i = g_label_refs[i].i;
3205 if (ops[i].op == OP_XOR
3206 && ops[i].operand[0].lmod == OPLM_DWORD
3207 && ops[i].operand[0].reg == ops[i].operand[1].reg
3208 && ops[i].operand[0].reg == reg)
3211 if (ops[i].regmask_dst & (1 << reg))
3218 static void patch_esp_adjust(struct parsed_op *po, int adj)
3220 ferr_assert(po, po->op == OP_ADD);
3221 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3222 ferr_assert(po, po->operand[1].type == OPT_CONST);
3224 // this is a bit of a hack, but deals with use of
3225 // single adj for multiple calls
3226 po->operand[1].val -= adj;
3227 po->flags |= OPF_RMD;
3228 if (po->operand[1].val == 0)
3229 po->flags |= OPF_DONE;
3230 ferr_assert(po, (int)po->operand[1].val >= 0);
3233 // scan for positive, constant esp adjust
3234 // multipath case is preliminary
3235 static int scan_for_esp_adjust(int i, int opcnt,
3236 int adj_expect, int *adj, int *is_multipath, int do_update)
3238 int adj_expect_unknown = 0;
3239 struct parsed_op *po;
3243 *adj = *is_multipath = 0;
3244 if (adj_expect < 0) {
3245 adj_expect_unknown = 1;
3246 adj_expect = 32 * 4; // enough?
3249 for (; i < opcnt && *adj < adj_expect; i++) {
3250 if (g_labels[i] != NULL)
3254 if (po->flags & OPF_DONE)
3257 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3258 if (po->operand[1].type != OPT_CONST)
3259 ferr(&ops[i], "non-const esp adjust?\n");
3260 *adj += po->operand[1].val;
3262 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3265 patch_esp_adjust(po, adj_expect);
3267 po->flags |= OPF_RMD;
3271 else if (po->op == OP_PUSH) {
3272 //if (first_pop == -1)
3273 // first_pop = -2; // none
3274 *adj -= lmod_bytes(po, po->operand[0].lmod);
3276 else if (po->op == OP_POP) {
3277 if (!(po->flags & OPF_DONE)) {
3278 // seems like msvc only uses 'pop ecx' for stack realignment..
3279 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3281 if (first_pop == -1 && *adj >= 0)
3284 if (do_update && *adj >= 0) {
3285 po->flags |= OPF_RMD;
3287 po->flags |= OPF_DONE | OPF_NOREGS;
3290 *adj += lmod_bytes(po, po->operand[0].lmod);
3291 if (*adj > adj_best)
3294 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3295 if (po->op == OP_JMP && po->btj == NULL) {
3301 if (po->op != OP_CALL)
3303 if (po->operand[0].type != OPT_LABEL)
3305 if (po->pp != NULL && po->pp->is_stdcall)
3307 if (adj_expect_unknown && first_pop >= 0)
3309 // assume it's another cdecl call
3313 if (first_pop >= 0) {
3314 // probably only 'pop ecx' was used
3322 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3324 struct parsed_op *po;
3328 ferr(ops, "%s: followed bad branch?\n", __func__);
3330 for (; i < opcnt; i++) {
3332 if (po->cc_scratch == magic)
3334 po->cc_scratch = magic;
3337 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3338 if (po->btj != NULL) {
3340 for (j = 0; j < po->btj->count; j++)
3341 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3345 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3346 if (!(po->flags & OPF_CJMP))
3349 if (po->flags & OPF_TAIL)
3354 static const struct parsed_proto *try_recover_pp(
3355 struct parsed_op *po, const struct parsed_opr *opr, int *search_instead)
3357 const struct parsed_proto *pp = NULL;
3361 // maybe an arg of g_func?
3362 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3364 char ofs_reg[16] = { 0, };
3365 int arg, arg_s, arg_i;
3372 parse_stack_access(po, opr->name, ofs_reg,
3373 &offset, &stack_ra, NULL, 0);
3374 if (ofs_reg[0] != 0)
3375 ferr(po, "offset reg on arg access?\n");
3376 if (offset <= stack_ra) {
3377 // search who set the stack var instead
3378 if (search_instead != NULL)
3379 *search_instead = 1;
3383 arg_i = (offset - stack_ra - 4) / 4;
3384 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3385 if (g_func_pp->arg[arg].reg != NULL)
3391 if (arg == g_func_pp->argc)
3392 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3394 pp = g_func_pp->arg[arg].fptr;
3396 ferr(po, "icall sa: arg%d is not a fptr?\n", arg + 1);
3397 check_func_pp(po, pp, "icall arg");
3399 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3401 p = strchr(opr->name + 1, '[');
3402 memcpy(buf, opr->name, p - opr->name);
3403 buf[p - opr->name] = 0;
3404 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3406 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3407 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3410 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3413 check_func_pp(po, pp, "reg-fptr ref");
3419 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3420 int magic, const struct parsed_proto **pp_found, int *pp_i,
3423 const struct parsed_proto *pp = NULL;
3424 struct parsed_op *po;
3425 struct label_ref *lr;
3427 ops[i].cc_scratch = magic;
3430 if (g_labels[i] != NULL) {
3431 lr = &g_label_refs[i];
3432 for (; lr != NULL; lr = lr->next) {
3433 check_i(&ops[i], lr->i);
3434 scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3436 if (i > 0 && LAST_OP(i - 1))
3444 if (ops[i].cc_scratch == magic)
3446 ops[i].cc_scratch = magic;
3448 if (!(ops[i].flags & OPF_DATA))
3450 if (!is_opr_modified(opr, &ops[i]))
3452 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3453 // most probably trashed by some processing
3458 opr = &ops[i].operand[1];
3459 if (opr->type != OPT_REG)
3463 po = (i >= 0) ? &ops[i] : ops;
3466 // reached the top - can only be an arg-reg
3467 if (opr->type != OPT_REG || g_func_pp == NULL)
3470 for (i = 0; i < g_func_pp->argc; i++) {
3471 if (g_func_pp->arg[i].reg == NULL)
3473 if (IS(opr->name, g_func_pp->arg[i].reg))
3476 if (i == g_func_pp->argc)
3478 pp = g_func_pp->arg[i].fptr;
3480 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3481 i + 1, g_func_pp->arg[i].reg);
3482 check_func_pp(po, pp, "icall reg-arg");
3485 pp = try_recover_pp(po, opr, NULL);
3487 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3488 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3489 || (*pp_found)->is_stdcall != pp->is_stdcall
3490 || (*pp_found)->is_fptr != pp->is_fptr
3491 || (*pp_found)->argc != pp->argc
3492 || (*pp_found)->argc_reg != pp->argc_reg
3493 || (*pp_found)->argc_stack != pp->argc_stack)
3495 ferr(po, "icall: parsed_proto mismatch\n");
3505 static void add_label_ref(struct label_ref *lr, int op_i)
3507 struct label_ref *lr_new;
3514 lr_new = calloc(1, sizeof(*lr_new));
3516 lr_new->next = lr->next;
3520 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3522 struct parsed_op *po = &ops[i];
3523 struct parsed_data *pd;
3524 char label[NAMELEN], *p;
3527 p = strchr(po->operand[0].name, '[');
3531 len = p - po->operand[0].name;
3532 strncpy(label, po->operand[0].name, len);
3535 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3536 if (IS(g_func_pd[j].label, label)) {
3542 //ferr(po, "label '%s' not parsed?\n", label);
3545 if (pd->type != OPT_OFFSET)
3546 ferr(po, "label '%s' with non-offset data?\n", label);
3548 // find all labels, link
3549 for (j = 0; j < pd->count; j++) {
3550 for (l = 0; l < opcnt; l++) {
3551 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3552 add_label_ref(&g_label_refs[l], i);
3562 static void clear_labels(int count)
3566 for (i = 0; i < count; i++) {
3567 if (g_labels[i] != NULL) {
3574 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3579 for (i = 0; i < pp->argc; i++) {
3580 if (pp->arg[i].reg != NULL) {
3581 reg = char_array_i(regs_r32,
3582 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3584 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3585 pp->arg[i].reg, pp->name);
3586 regmask |= 1 << reg;
3593 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3598 if (pp->has_retreg) {
3599 for (i = 0; i < pp->argc; i++) {
3600 if (pp->arg[i].type.is_retreg) {
3601 reg = char_array_i(regs_r32,
3602 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3603 ferr_assert(ops, reg >= 0);
3604 regmask |= 1 << reg;
3609 if (strstr(pp->ret_type.name, "int64"))
3610 return regmask | (1 << xAX) | (1 << xDX);
3611 if (IS(pp->ret_type.name, "float")
3612 || IS(pp->ret_type.name, "double"))
3614 return regmask | mxST0;
3616 if (strcasecmp(pp->ret_type.name, "void") == 0)
3619 return regmask | mxAX;
3622 static void resolve_branches_parse_calls(int opcnt)
3624 static const struct {
3628 unsigned int regmask_src;
3629 unsigned int regmask_dst;
3631 { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3632 { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3633 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3635 const struct parsed_proto *pp_c;
3636 struct parsed_proto *pp;
3637 struct parsed_data *pd;
3638 struct parsed_op *po;
3639 const char *tmpname;
3643 for (i = 0; i < opcnt; i++)
3649 if (po->datap != NULL) {
3650 pp = calloc(1, sizeof(*pp));
3651 my_assert_not(pp, NULL);
3653 ret = parse_protostr(po->datap, pp);
3655 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3661 if (po->op == OP_CALL) {
3666 else if (po->operand[0].type == OPT_LABEL)
3668 tmpname = opr_name(po, 0);
3669 if (IS_START(tmpname, "loc_"))
3670 ferr(po, "call to loc_*\n");
3671 if (IS(tmpname, "__alloca_probe"))
3674 // convert some calls to pseudo-ops
3675 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3676 if (!IS(tmpname, pseudo_ops[l].name))
3679 po->op = pseudo_ops[l].op;
3680 po->operand_cnt = 0;
3681 po->regmask_src = pseudo_ops[l].regmask_src;
3682 po->regmask_dst = pseudo_ops[l].regmask_dst;
3683 po->flags = pseudo_ops[l].flags;
3684 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3687 if (l < ARRAY_SIZE(pseudo_ops))
3690 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3691 if (!g_header_mode && pp_c == NULL)
3692 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3695 pp = proto_clone(pp_c);
3696 my_assert_not(pp, NULL);
3702 check_func_pp(po, pp, "fptr var call");
3703 if (pp->is_noreturn)
3704 po->flags |= OPF_TAIL;
3710 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3713 if (po->operand[0].type == OPT_REGMEM) {
3714 pd = try_resolve_jumptab(i, opcnt);
3722 for (l = 0; l < opcnt; l++) {
3723 if (g_labels[l] != NULL
3724 && IS(po->operand[0].name, g_labels[l]))
3726 if (l == i + 1 && po->op == OP_JMP) {
3727 // yet another alignment type..
3728 po->flags |= OPF_RMD|OPF_DONE;
3731 add_label_ref(&g_label_refs[l], i);
3737 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3740 if (po->operand[0].type == OPT_LABEL)
3744 ferr(po, "unhandled branch\n");
3748 po->flags |= OPF_TAIL;
3749 if (i > 0 && ops[i - 1].op == OP_POP)
3750 po->flags |= OPF_ATAIL;
3755 static void scan_prologue_epilogue(int opcnt)
3757 int ecx_push = 0, esp_sub = 0, pusha = 0;
3758 int sandard_epilogue;
3762 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
3763 && ops[1].op == OP_MOV
3764 && IS(opr_name(&ops[1], 0), "ebp")
3765 && IS(opr_name(&ops[1], 1), "esp"))
3768 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3769 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3772 if (ops[i].op == OP_PUSHA) {
3773 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3778 if (ops[i].op == OP_SUB && IS(opr_name(&ops[i], 0), "esp")) {
3779 g_stack_fsz = opr_const(&ops[i], 1);
3780 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3784 // another way msvc builds stack frame..
3785 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3787 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3791 // and another way..
3792 if (i == 2 && ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3793 && ops[i].operand[1].type == OPT_CONST
3794 && ops[i + 1].op == OP_CALL
3795 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3797 g_stack_fsz += ops[i].operand[1].val;
3798 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3800 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3807 for (; i < opcnt; i++)
3808 if (ops[i].flags & OPF_TAIL)
3811 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3812 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3818 sandard_epilogue = 0;
3819 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
3821 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3822 // the standard epilogue is sometimes even used without a sf
3823 if (ops[j - 1].op == OP_MOV
3824 && IS(opr_name(&ops[j - 1], 0), "esp")
3825 && IS(opr_name(&ops[j - 1], 1), "ebp"))
3826 sandard_epilogue = 1;
3828 else if (ops[j].op == OP_LEAVE)
3830 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3831 sandard_epilogue = 1;
3833 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
3834 && ops[i].pp->is_noreturn)
3836 // on noreturn, msvc sometimes cleans stack, sometimes not
3841 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3842 ferr(&ops[j], "'pop ebp' expected\n");
3844 if (g_stack_fsz != 0 || sandard_epilogue) {
3845 if (ops[j].op == OP_LEAVE)
3847 else if (sandard_epilogue) // mov esp, ebp
3849 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3852 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3854 ferr(&ops[j], "esp restore expected\n");
3857 if (ecx_push && j >= 0 && ops[j].op == OP_POP
3858 && IS(opr_name(&ops[j], 0), "ecx"))
3860 ferr(&ops[j], "unexpected ecx pop\n");
3865 if (ops[j].op == OP_POPA)
3866 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3868 ferr(&ops[j], "popa expected\n");
3873 } while (i < opcnt);
3876 ferr(ops, "missing ebp epilogue\n");
3882 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3883 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3889 for (; i < opcnt; i++) {
3890 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
3892 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
3893 && ops[i].operand[1].type == OPT_CONST)
3895 g_stack_fsz = ops[i].operand[1].val;
3896 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3901 else if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3902 && ops[i].operand[1].type == OPT_CONST
3903 && ops[i + 1].op == OP_CALL
3904 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3906 g_stack_fsz += ops[i].operand[1].val;
3907 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3909 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3916 if (ecx_push && !esp_sub) {
3917 // could actually be args for a call..
3918 for (; i < opcnt; i++)
3919 if (ops[i].op != OP_PUSH)
3922 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
3923 const struct parsed_proto *pp;
3924 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
3925 j = pp ? pp->argc_stack : 0;
3926 while (i > 0 && j > 0) {
3928 if (ops[i].op == OP_PUSH) {
3929 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
3934 ferr(&ops[i], "unhandled prologue\n");
3937 i = g_stack_fsz = ecx_push = 0;
3938 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3939 if (!(ops[i].flags & OPF_RMD))
3949 if (ecx_push || esp_sub)
3954 for (; i < opcnt; i++)
3955 if (ops[i].flags & OPF_TAIL)
3959 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3960 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3967 for (l = 0; l < ecx_push; l++) {
3968 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
3970 else if (ops[j].op == OP_ADD
3971 && IS(opr_name(&ops[j], 0), "esp")
3972 && ops[j].operand[1].type == OPT_CONST)
3975 l += ops[j].operand[1].val / 4 - 1;
3978 ferr(&ops[j], "'pop ecx' expected\n");
3980 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3984 ferr(&ops[j], "epilogue scan failed\n");
3990 if (ops[j].op != OP_ADD
3991 || !IS(opr_name(&ops[j], 0), "esp")
3992 || ops[j].operand[1].type != OPT_CONST
3993 || ops[j].operand[1].val != g_stack_fsz)
3995 if (ops[i].op == OP_CALL && ops[i].pp != NULL
3996 && ops[i].pp->is_noreturn)
3998 // noreturn tailcall with no epilogue
4002 ferr(&ops[j], "'add esp' expected\n");
4005 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4006 ops[j].operand[1].val = 0; // hack for stack arg scanner
4011 } while (i < opcnt);
4014 ferr(ops, "missing esp epilogue\n");
4018 // find an instruction that changed opr before i op
4019 // *op_i must be set to -1 by the caller
4020 // *is_caller is set to 1 if one source is determined to be g_func arg
4021 // returns 1 if found, *op_i is then set to origin
4022 // returns -1 if multiple origins are found
4023 static int resolve_origin(int i, const struct parsed_opr *opr,
4024 int magic, int *op_i, int *is_caller)
4026 struct label_ref *lr;
4029 if (ops[i].cc_scratch == magic)
4031 ops[i].cc_scratch = magic;
4034 if (g_labels[i] != NULL) {
4035 lr = &g_label_refs[i];
4036 for (; lr != NULL; lr = lr->next) {
4037 check_i(&ops[i], lr->i);
4038 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4040 if (i > 0 && LAST_OP(i - 1))
4046 if (is_caller != NULL)
4051 if (ops[i].cc_scratch == magic)
4053 ops[i].cc_scratch = magic;
4055 if (!(ops[i].flags & OPF_DATA))
4057 if (!is_opr_modified(opr, &ops[i]))
4064 // XXX: could check if the other op does the same
4073 // find an instruction that previously referenced opr
4074 // if multiple results are found - fail
4075 // *op_i must be set to -1 by the caller
4076 // returns 1 if found, *op_i is then set to referencer insn
4077 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4078 int magic, int *op_i)
4080 struct label_ref *lr;
4083 if (ops[i].cc_scratch == magic)
4085 ops[i].cc_scratch = magic;
4088 if (g_labels[i] != NULL) {
4089 lr = &g_label_refs[i];
4090 for (; lr != NULL; lr = lr->next) {
4091 check_i(&ops[i], lr->i);
4092 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4094 if (i > 0 && LAST_OP(i - 1))
4102 if (ops[i].cc_scratch == magic)
4104 ops[i].cc_scratch = magic;
4106 if (!is_opr_referenced(opr, &ops[i]))
4117 // adjust datap of all reachable 'op' insns when moving back
4118 // returns 1 if at least 1 op was found
4119 // returns -1 if path without an op was found
4120 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4122 struct label_ref *lr;
4125 if (ops[i].cc_scratch == magic)
4127 ops[i].cc_scratch = magic;
4130 if (g_labels[i] != NULL) {
4131 lr = &g_label_refs[i];
4132 for (; lr != NULL; lr = lr->next) {
4133 check_i(&ops[i], lr->i);
4134 ret |= adjust_prev_op(lr->i, op, magic, datap);
4136 if (i > 0 && LAST_OP(i - 1))
4144 if (ops[i].cc_scratch == magic)
4146 ops[i].cc_scratch = magic;
4148 if (ops[i].op != op)
4151 ops[i].datap = datap;
4156 // find next instruction that reads opr
4157 // *op_i must be set to -1 by the caller
4158 // on return, *op_i is set to first referencer insn
4159 // returns 1 if exactly 1 referencer is found
4160 static int find_next_read(int i, int opcnt,
4161 const struct parsed_opr *opr, int magic, int *op_i)
4163 struct parsed_op *po;
4166 for (; i < opcnt; i++)
4168 if (ops[i].cc_scratch == magic)
4170 ops[i].cc_scratch = magic;
4173 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4174 if (po->btj != NULL) {
4176 for (j = 0; j < po->btj->count; j++) {
4177 check_i(po, po->btj->d[j].bt_i);
4178 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4184 if (po->flags & OPF_RMD)
4186 check_i(po, po->bt_i);
4187 if (po->flags & OPF_CJMP) {
4188 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4197 if (!is_opr_read(opr, po)) {
4199 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4200 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4202 full_opr = po->operand[0].lmod >= opr->lmod;
4204 if (is_opr_modified(opr, po) && full_opr) {
4208 if (po->flags & OPF_TAIL)
4223 // find next instruction that reads opr
4224 // *op_i must be set to -1 by the caller
4225 // on return, *op_i is set to first flag user insn
4226 // returns 1 if exactly 1 flag user is found
4227 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4229 struct parsed_op *po;
4232 for (; i < opcnt; i++)
4234 if (ops[i].cc_scratch == magic)
4236 ops[i].cc_scratch = magic;
4239 if (po->op == OP_CALL)
4241 if (po->flags & OPF_JMP) {
4242 if (po->btj != NULL) {
4244 for (j = 0; j < po->btj->count; j++) {
4245 check_i(po, po->btj->d[j].bt_i);
4246 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4252 if (po->flags & OPF_RMD)
4254 check_i(po, po->bt_i);
4255 if (po->flags & OPF_CJMP)
4262 if (!(po->flags & OPF_CC)) {
4263 if (po->flags & OPF_FLAGS)
4266 if (po->flags & OPF_TAIL)
4282 static int try_resolve_const(int i, const struct parsed_opr *opr,
4283 int magic, unsigned int *val)
4288 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4291 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4294 *val = ops[i].operand[1].val;
4301 static int resolve_used_bits(int i, int opcnt, int reg,
4302 int *mask, int *is_z_check)
4304 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4308 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4312 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4314 fnote(&ops[j], "(first read)\n");
4315 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4318 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4319 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4321 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4322 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4324 *mask = ops[j].operand[1].val;
4325 if (ops[j].operand[0].lmod == OPLM_BYTE
4326 && ops[j].operand[0].name[1] == 'h')
4330 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4333 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4335 *is_z_check = ops[k].pfo == PFO_Z;
4340 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4341 int *pp_i, int *multi_src)
4343 const struct parsed_proto *pp = NULL;
4344 int search_advice = 0;
4354 switch (ops[i].operand[0].type) {
4356 // try to resolve struct member calls
4357 ret = sscanf(ops[i].operand[0].name, "%3s+%x%n",
4358 s_reg, &offset, &len);
4359 if (ret == 2 && len == strlen(ops[i].operand[0].name))
4361 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4363 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, reg);
4365 ret = resolve_origin(i, &opr, i + opcnt * 19, &j, NULL);
4368 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4369 && ops[j].operand[0].lmod == OPLM_DWORD
4370 && ops[j].pp == NULL) // no hint
4372 // allow one simple dereference (directx)
4373 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4374 ops[j].operand[1].name);
4377 struct parsed_opr opr2 = OPR_INIT(OPT_REG, OPLM_DWORD, reg);
4379 ret = resolve_origin(j, &opr2, j + opcnt * 19, &k, NULL);
4384 if (ops[j].op != OP_MOV)
4386 if (ops[j].operand[0].lmod != OPLM_DWORD)
4388 if (ops[j].pp != NULL) {
4392 else if (ops[j].operand[1].type == OPT_REGMEM) {
4393 // allow 'hello[ecx]' - assume array of same type items
4394 ret = sscanf(ops[j].operand[1].name, "%[^[][e%2s]",
4398 pp = proto_parse(g_fhdr, name, g_quiet_pp);
4400 else if (ops[j].operand[1].type == OPT_LABEL)
4401 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4406 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4410 pp = proto_lookup_struct(g_fhdr, pp->type.name, offset);
4417 pp = try_recover_pp(&ops[i], &ops[i].operand[0], &search_advice);
4422 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4430 static struct parsed_proto *process_call_early(int i, int opcnt,
4433 struct parsed_op *po = &ops[i];
4434 struct parsed_proto *pp;
4440 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4444 // look for and make use of esp adjust
4446 if (!pp->is_stdcall && pp->argc_stack > 0)
4447 ret = scan_for_esp_adjust(i + 1, opcnt,
4448 pp->argc_stack * 4, &adj, &multipath, 0);
4450 if (pp->argc_stack > adj / 4)
4454 if (ops[ret].op == OP_POP) {
4455 for (j = 1; j < adj / 4; j++) {
4456 if (ops[ret + j].op != OP_POP
4457 || ops[ret + j].operand[0].reg != xCX)
4469 static struct parsed_proto *process_call(int i, int opcnt)
4471 struct parsed_op *po = &ops[i];
4472 const struct parsed_proto *pp_c;
4473 struct parsed_proto *pp;
4474 const char *tmpname;
4475 int call_i = -1, ref_i = -1;
4476 int adj = 0, multipath = 0;
4479 tmpname = opr_name(po, 0);
4484 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4486 if (!pp_c->is_func && !pp_c->is_fptr)
4487 ferr(po, "call to non-func: %s\n", pp_c->name);
4488 pp = proto_clone(pp_c);
4489 my_assert_not(pp, NULL);
4491 // not resolved just to single func
4494 switch (po->operand[0].type) {
4496 // we resolved this call and no longer need the register
4497 po->regmask_src &= ~(1 << po->operand[0].reg);
4499 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4500 && ops[call_i].operand[1].type == OPT_LABEL)
4502 // no other source users?
4503 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4505 if (ret == 1 && call_i == ref_i) {
4506 // and nothing uses it after us?
4508 find_next_read(i + 1, opcnt, &po->operand[0],
4509 i + opcnt * 11, &ref_i);
4511 // then also don't need the source mov
4512 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4524 pp = calloc(1, sizeof(*pp));
4525 my_assert_not(pp, NULL);
4528 ret = scan_for_esp_adjust(i + 1, opcnt,
4529 -1, &adj, &multipath, 0);
4530 if (ret < 0 || adj < 0) {
4531 if (!g_allow_regfunc)
4532 ferr(po, "non-__cdecl indirect call unhandled yet\n");
4533 pp->is_unresolved = 1;
4537 if (adj > ARRAY_SIZE(pp->arg))
4538 ferr(po, "esp adjust too large: %d\n", adj);
4539 pp->ret_type.name = strdup("int");
4540 pp->argc = pp->argc_stack = adj;
4541 for (arg = 0; arg < pp->argc; arg++)
4542 pp->arg[arg].type.name = strdup("int");
4547 // look for and make use of esp adjust
4550 if (!pp->is_stdcall && pp->argc_stack > 0) {
4551 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
4552 ret = scan_for_esp_adjust(i + 1, opcnt,
4553 adj_expect, &adj, &multipath, 0);
4556 if (pp->is_vararg) {
4557 if (adj / 4 < pp->argc_stack) {
4558 fnote(po, "(this call)\n");
4559 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
4560 adj, pp->argc_stack * 4);
4562 // modify pp to make it have varargs as normal args
4564 pp->argc += adj / 4 - pp->argc_stack;
4565 for (; arg < pp->argc; arg++) {
4566 pp->arg[arg].type.name = strdup("int");
4569 if (pp->argc > ARRAY_SIZE(pp->arg))
4570 ferr(po, "too many args for '%s'\n", tmpname);
4572 if (pp->argc_stack > adj / 4) {
4573 fnote(po, "(this call)\n");
4574 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
4575 tmpname, pp->argc_stack * 4, adj);
4578 scan_for_esp_adjust(i + 1, opcnt,
4579 pp->argc_stack * 4, &adj, &multipath, 1);
4581 else if (pp->is_vararg)
4582 ferr(po, "missing esp_adjust for vararg func '%s'\n",
4588 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
4591 struct parsed_op *po;
4597 for (base_arg = 0; base_arg < pp->argc; base_arg++)
4598 if (pp->arg[base_arg].reg == NULL)
4601 for (j = i; j > 0; )
4603 ferr_assert(&ops[j], g_labels[j] == NULL);
4607 ferr_assert(po, po->op != OP_PUSH);
4608 if (po->op == OP_FST)
4610 if (po->operand[0].type != OPT_REGMEM)
4612 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
4615 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3))
4616 ferr(po, "bad offset %d (%d args)\n", offset, pp->argc_stack);
4618 arg = base_arg + offset / 4;
4620 po->p_argnum = arg + 1;
4621 ferr_assert(po, pp->arg[arg].datap == NULL);
4622 pp->arg[arg].datap = po;
4623 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
4624 if (regmask_ffca != NULL)
4625 *regmask_ffca |= 1 << arg;
4627 else if (po->op == OP_SUB && po->operand[0].reg == xSP
4628 && po->operand[1].type == OPT_CONST)
4630 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4635 for (arg = base_arg; arg < pp->argc; arg++) {
4636 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
4637 po = pp->arg[arg].datap;
4639 ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
4640 if (po->operand[0].lmod == OPLM_QWORD)
4647 static int collect_call_args_early(int i, struct parsed_proto *pp,
4648 int *regmask, int *regmask_ffca)
4650 struct parsed_op *po;
4654 for (arg = 0; arg < pp->argc; arg++)
4655 if (pp->arg[arg].reg == NULL)
4658 // first see if it can be easily done
4659 for (j = i; j > 0 && arg < pp->argc; )
4661 if (g_labels[j] != NULL)
4666 if (po->op == OP_CALL)
4668 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
4670 else if (po->op == OP_POP)
4672 else if (po->flags & OPF_CJMP)
4674 else if (po->op == OP_PUSH) {
4675 if (po->flags & (OPF_FARG|OPF_FARGNR))
4677 if (!g_header_mode) {
4678 ret = scan_for_mod(po, j + 1, i, 1);
4683 if (pp->arg[arg].type.is_va_list)
4687 for (arg++; arg < pp->argc; arg++)
4688 if (pp->arg[arg].reg == NULL)
4691 else if (po->op == OP_SUB && po->operand[0].reg == xSP
4692 && po->operand[1].type == OPT_CONST)
4694 if (po->flags & (OPF_RMD|OPF_DONE))
4696 if (po->operand[1].val != pp->argc_stack * 4)
4697 ferr(po, "unexpected esp adjust: %d\n",
4698 po->operand[1].val * 4);
4699 ferr_assert(po, pp->argc - arg == pp->argc_stack);
4700 return collect_call_args_no_push(i, pp, regmask_ffca);
4708 for (arg = 0; arg < pp->argc; arg++)
4709 if (pp->arg[arg].reg == NULL)
4712 for (j = i; j > 0 && arg < pp->argc; )
4716 if (ops[j].op == OP_PUSH)
4718 ops[j].p_argnext = -1;
4719 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
4720 pp->arg[arg].datap = &ops[j];
4722 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
4723 *regmask |= 1 << ops[j].operand[0].reg;
4725 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4726 ops[j].flags &= ~OPF_RSAVE;
4729 for (arg++; arg < pp->argc; arg++)
4730 if (pp->arg[arg].reg == NULL)
4738 static int collect_call_args_r(struct parsed_op *po, int i,
4739 struct parsed_proto *pp, int *regmask, int *save_arg_vars,
4740 int *arg_grp, int arg, int magic, int need_op_saving, int may_reuse)
4742 struct parsed_proto *pp_tmp;
4743 struct parsed_op *po_tmp;
4744 struct label_ref *lr;
4745 int need_to_save_current;
4746 int arg_grp_current = 0;
4747 int save_args_seen = 0;
4755 ferr(po, "dead label encountered\n");
4759 for (; arg < pp->argc; arg++)
4760 if (pp->arg[arg].reg == NULL)
4762 magic = (magic & 0xffffff) | (arg << 24);
4764 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
4766 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
4767 if (ops[j].cc_scratch != magic) {
4768 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
4772 // ok: have already been here
4775 ops[j].cc_scratch = magic;
4777 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
4778 lr = &g_label_refs[j];
4779 if (lr->next != NULL)
4781 for (; lr->next; lr = lr->next) {
4782 check_i(&ops[j], lr->i);
4783 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4785 ret = collect_call_args_r(po, lr->i, pp, regmask, save_arg_vars,
4786 arg_grp, arg, magic, need_op_saving, may_reuse);
4791 check_i(&ops[j], lr->i);
4792 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4794 if (j > 0 && LAST_OP(j - 1)) {
4795 // follow last branch in reverse
4800 ret = collect_call_args_r(po, lr->i, pp, regmask, save_arg_vars,
4801 arg_grp, arg, magic, need_op_saving, may_reuse);
4807 if (ops[j].op == OP_CALL)
4809 if (pp->is_unresolved)
4814 ferr(po, "arg collect hit unparsed call '%s'\n",
4815 ops[j].operand[0].name);
4816 if (may_reuse && pp_tmp->argc_stack > 0)
4817 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
4818 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
4820 // esp adjust of 0 means we collected it before
4821 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
4822 && (ops[j].operand[1].type != OPT_CONST
4823 || ops[j].operand[1].val != 0))
4825 if (pp->is_unresolved)
4828 fnote(po, "(this call)\n");
4829 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
4830 arg, pp->argc, ops[j].operand[1].val);
4832 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
4834 if (pp->is_unresolved)
4837 fnote(po, "(this call)\n");
4838 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
4840 else if (ops[j].flags & OPF_CJMP)
4842 if (pp->is_unresolved)
4847 else if (ops[j].op == OP_PUSH
4848 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
4850 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
4853 ops[j].p_argnext = -1;
4854 po_tmp = pp->arg[arg].datap;
4856 ops[j].p_argnext = po_tmp - ops;
4857 pp->arg[arg].datap = &ops[j];
4859 need_to_save_current = 0;
4862 if (ops[j].operand[0].type == OPT_REG)
4863 reg = ops[j].operand[0].reg;
4865 if (!need_op_saving) {
4866 ret = scan_for_mod(&ops[j], j + 1, i, 1);
4867 need_to_save_current = (ret >= 0);
4869 if (need_op_saving || need_to_save_current) {
4870 // mark this push as one that needs operand saving
4871 ops[j].flags &= ~OPF_RMD;
4872 if (ops[j].p_argnum == 0) {
4873 ops[j].p_argnum = arg + 1;
4874 save_args |= 1 << arg;
4876 else if (ops[j].p_argnum < arg + 1) {
4877 // XXX: might kill valid var..
4878 //*save_arg_vars &= ~(1 << (ops[j].p_argnum - 1));
4879 ops[j].p_argnum = arg + 1;
4880 save_args |= 1 << arg;
4883 if (save_args_seen & (1 << (ops[j].p_argnum - 1))) {
4886 if (arg_grp_current >= MAX_ARG_GRP)
4887 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
4888 ops[j].p_argnum, pp->name);
4891 else if (ops[j].p_argnum == 0)
4892 ops[j].flags |= OPF_RMD;
4894 // some PUSHes are reused by different calls on other branches,
4895 // but that can't happen if we didn't branch, so they
4896 // can be removed from future searches (handles nested calls)
4898 ops[j].flags |= OPF_FARGNR;
4900 ops[j].flags |= OPF_FARG;
4901 ops[j].flags &= ~OPF_RSAVE;
4903 // check for __VALIST
4904 if (!pp->is_unresolved && g_func_pp != NULL
4905 && pp->arg[arg].type.is_va_list)
4908 ret = resolve_origin(j, &ops[j].operand[0],
4909 magic + 1, &k, NULL);
4910 if (ret == 1 && k >= 0)
4912 if (ops[k].op == OP_LEA) {
4913 if (!g_func_pp->is_vararg)
4914 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
4917 snprintf(buf, sizeof(buf), "arg_%X",
4918 g_func_pp->argc_stack * 4);
4919 if (strstr(ops[k].operand[1].name, buf)
4920 || strstr(ops[k].operand[1].name, "arglist"))
4922 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
4923 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
4924 save_args &= ~(1 << arg);
4928 ferr(&ops[k], "va_list arg detection failed\n");
4930 // check for va_list from g_func_pp arg too
4931 else if (ops[k].op == OP_MOV
4932 && is_stack_access(&ops[k], &ops[k].operand[1]))
4934 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
4935 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
4937 ops[k].flags |= OPF_RMD | OPF_DONE;
4938 ops[j].flags |= OPF_RMD;
4939 ops[j].p_argpass = ret + 1;
4940 save_args &= ~(1 << arg);
4947 *save_arg_vars |= save_args;
4949 // tracking reg usage
4951 *regmask |= 1 << reg;
4954 if (!pp->is_unresolved) {
4956 for (; arg < pp->argc; arg++)
4957 if (pp->arg[arg].reg == NULL)
4960 magic = (magic & 0xffffff) | (arg << 24);
4963 if (ops[j].p_arggrp > arg_grp_current) {
4965 arg_grp_current = ops[j].p_arggrp;
4967 if (ops[j].p_argnum > 0)
4968 save_args_seen |= 1 << (ops[j].p_argnum - 1);
4971 if (arg < pp->argc) {
4972 ferr(po, "arg collect failed for '%s': %d/%d\n",
4973 pp->name, arg, pp->argc);
4977 if (arg_grp_current > *arg_grp)
4978 *arg_grp = arg_grp_current;
4983 static int collect_call_args(struct parsed_op *po, int i,
4984 struct parsed_proto *pp, int *regmask, int *save_arg_vars,
4987 // arg group is for cases when pushes for
4988 // multiple funcs are going on
4989 struct parsed_op *po_tmp;
4990 int save_arg_vars_current = 0;
4995 ret = collect_call_args_r(po, i, pp, regmask,
4996 &save_arg_vars_current, &arg_grp, 0, magic, 0, 0);
5001 // propagate arg_grp
5002 for (a = 0; a < pp->argc; a++) {
5003 if (pp->arg[a].reg != NULL)
5006 po_tmp = pp->arg[a].datap;
5007 while (po_tmp != NULL) {
5008 po_tmp->p_arggrp = arg_grp;
5009 if (po_tmp->p_argnext > 0)
5010 po_tmp = &ops[po_tmp->p_argnext];
5016 save_arg_vars[arg_grp] |= save_arg_vars_current;
5018 if (pp->is_unresolved) {
5020 pp->argc_stack += ret;
5021 for (a = 0; a < pp->argc; a++)
5022 if (pp->arg[a].type.name == NULL)
5023 pp->arg[a].type.name = strdup("int");
5029 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5030 int regmask_now, int *regmask,
5031 int regmask_save_now, int *regmask_save,
5032 int *regmask_init, int regmask_arg)
5034 struct parsed_op *po;
5042 for (; i < opcnt; i++)
5045 if (cbits[i >> 3] & (1 << (i & 7)))
5047 cbits[i >> 3] |= (1 << (i & 7));
5049 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5050 if (po->flags & (OPF_RMD|OPF_DONE))
5052 if (po->btj != NULL) {
5053 for (j = 0; j < po->btj->count; j++) {
5054 check_i(po, po->btj->d[j].bt_i);
5055 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5056 regmask_now, regmask, regmask_save_now, regmask_save,
5057 regmask_init, regmask_arg);
5062 check_i(po, po->bt_i);
5063 if (po->flags & OPF_CJMP)
5064 reg_use_pass(po->bt_i, opcnt, cbits,
5065 regmask_now, regmask, regmask_save_now, regmask_save,
5066 regmask_init, regmask_arg);
5072 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5073 && !g_func_pp->is_userstack
5074 && po->operand[0].type == OPT_REG)
5076 reg = po->operand[0].reg;
5077 ferr_assert(po, reg >= 0);
5080 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5081 if (regmask_now & (1 << reg)) {
5082 already_saved = regmask_save_now & (1 << reg);
5083 flags_set = OPF_RSAVE | OPF_DONE;
5086 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0);
5088 scan_for_pop(i + 1, opcnt, i + opcnt * 4, reg, 0, flags_set);
5091 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5093 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5098 ferr_assert(po, !already_saved);
5099 po->flags |= flags_set;
5101 if (regmask_now & (1 << reg)) {
5102 regmask_save_now |= (1 << reg);
5103 *regmask_save |= regmask_save_now;
5108 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5109 reg = po->operand[0].reg;
5110 ferr_assert(po, reg >= 0);
5112 if (regmask_save_now & (1 << reg))
5113 regmask_save_now &= ~(1 << reg);
5115 regmask_now &= ~(1 << reg);
5118 else if (po->op == OP_CALL) {
5119 if ((po->regmask_dst & (1 << xAX))
5120 && !(po->regmask_dst & (1 << xDX)))
5122 if (po->flags & OPF_TAIL)
5123 // don't need eax, will do "return f();" or "f(); return;"
5124 po->regmask_dst &= ~(1 << xAX);
5126 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
5128 find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
5131 po->regmask_dst &= ~(1 << xAX);
5135 // not "full stack" mode and have something in stack
5136 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5137 ferr(po, "float stack is not empty on func call\n");
5140 if (po->flags & OPF_NOREGS)
5143 // if incomplete register is used, clear it on init to avoid
5144 // later use of uninitialized upper part in some situations
5145 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5146 && po->operand[0].lmod != OPLM_DWORD)
5148 reg = po->operand[0].reg;
5149 ferr_assert(po, reg >= 0);
5151 if (!(regmask_now & (1 << reg)))
5152 *regmask_init |= 1 << reg;
5155 regmask_op = po->regmask_src | po->regmask_dst;
5157 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5158 regmask_new &= ~(1 << xSP);
5159 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5160 regmask_new &= ~(1 << xBP);
5162 if (regmask_new != 0)
5163 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5165 if (regmask_op & (1 << xBP)) {
5166 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5167 if (po->regmask_dst & (1 << xBP))
5168 // compiler decided to drop bp frame and use ebp as scratch
5169 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5171 regmask_op &= ~(1 << xBP);
5175 if (po->flags & OPF_FPUSH) {
5176 if (regmask_now & mxST1)
5177 regmask_now |= mxSTa; // switch to "full stack" mode
5178 if (regmask_now & mxSTa)
5179 po->flags |= OPF_FSHIFT;
5180 if (!(regmask_now & mxST7_2)) {
5182 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5186 regmask_now |= regmask_op;
5187 *regmask |= regmask_now;
5190 if (po->flags & OPF_FPOP) {
5191 if ((regmask_now & mxSTa) == 0)
5192 ferr(po, "float pop on empty stack?\n");
5193 if (regmask_now & (mxST7_2 | mxST1))
5194 po->flags |= OPF_FSHIFT;
5195 if (!(regmask_now & mxST7_2)) {
5197 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5201 if (po->flags & OPF_TAIL) {
5202 if (!(regmask_now & mxST7_2)) {
5203 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5204 if (!(regmask_now & mxST0))
5205 ferr(po, "no st0 on float return, mask: %x\n",
5208 else if (regmask_now & mxST1_0)
5209 ferr(po, "float regs on tail: %x\n", regmask_now);
5212 // there is support for "conditional tailcall", sort of
5213 if (!(po->flags & OPF_CC))
5219 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5223 for (i = 0; i < pp->argc; i++)
5224 if (pp->arg[i].reg == NULL)
5228 memmove(&pp->arg[i + 1], &pp->arg[i],
5229 sizeof(pp->arg[0]) * pp->argc_stack);
5230 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5231 pp->arg[i].reg = strdup(reg);
5232 pp->arg[i].type.name = strdup("int");
5237 static void output_std_flags(FILE *fout, struct parsed_op *po,
5238 int *pfomask, const char *dst_opr_text)
5240 if (*pfomask & (1 << PFO_Z)) {
5241 fprintf(fout, "\n cond_z = (%s%s == 0);",
5242 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5243 *pfomask &= ~(1 << PFO_Z);
5245 if (*pfomask & (1 << PFO_S)) {
5246 fprintf(fout, "\n cond_s = (%s%s < 0);",
5247 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5248 *pfomask &= ~(1 << PFO_S);
5253 OPP_FORCE_NORETURN = (1 << 0),
5254 OPP_SIMPLE_ARGS = (1 << 1),
5255 OPP_ALIGN = (1 << 2),
5258 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
5261 const char *cconv = "";
5263 if (pp->is_fastcall)
5264 cconv = "__fastcall ";
5265 else if (pp->is_stdcall && pp->argc_reg == 0)
5266 cconv = "__stdcall ";
5268 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5270 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
5271 fprintf(fout, "noreturn ");
5274 static void output_pp(FILE *fout, const struct parsed_proto *pp,
5279 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5283 output_pp_attrs(fout, pp, flags);
5286 fprintf(fout, "%s", pp->name);
5291 for (i = 0; i < pp->argc; i++) {
5293 fprintf(fout, ", ");
5294 if (pp->arg[i].fptr != NULL && !(flags & OPP_SIMPLE_ARGS)) {
5296 output_pp(fout, pp->arg[i].fptr, 0);
5298 else if (pp->arg[i].type.is_retreg) {
5299 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
5302 fprintf(fout, "%s", pp->arg[i].type.name);
5304 fprintf(fout, " a%d", i + 1);
5307 if (pp->is_vararg) {
5309 fprintf(fout, ", ");
5310 fprintf(fout, "...");
5315 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
5321 snprintf(buf1, sizeof(buf1), "%d", grp);
5322 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
5327 static void gen_x_cleanup(int opcnt);
5329 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
5331 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
5332 struct parsed_opr *last_arith_dst = NULL;
5333 char buf1[256], buf2[256], buf3[256], cast[64];
5334 struct parsed_proto *pp, *pp_tmp;
5335 struct parsed_data *pd;
5336 int save_arg_vars[MAX_ARG_GRP] = { 0, };
5337 unsigned char cbits[MAX_OPS / 8];
5338 const char *float_type;
5339 const char *float_st0;
5340 const char *float_st1;
5341 int need_float_stack = 0;
5342 int need_float_sw = 0; // status word
5343 int need_tmp_var = 0;
5347 int label_pending = 0;
5348 int need_double = 0;
5349 int regmask_save = 0; // used regs saved/restored in this func
5350 int regmask_arg; // regs from this function args (fastcall, etc)
5351 int regmask_ret; // regs needed on ret
5352 int regmask_now; // temp
5353 int regmask_init = 0; // regs that need zero initialization
5354 int regmask_pp = 0; // regs used in complex push-pop graph
5355 int regmask_ffca = 0; // float function call args
5356 int regmask = 0; // used regs
5366 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
5367 g_stack_frame_used = 0;
5368 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
5369 regmask_init = g_regmask_init;
5371 g_func_pp = proto_parse(fhdr, funcn, 0);
5372 if (g_func_pp == NULL)
5373 ferr(ops, "proto_parse failed for '%s'\n", funcn);
5375 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
5376 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
5379 // - resolve all branches
5380 // - parse calls with labels
5381 resolve_branches_parse_calls(opcnt);
5384 // - handle ebp/esp frame, remove ops related to it
5385 scan_prologue_epilogue(opcnt);
5388 // - remove dead labels
5389 // - set regs needed at ret
5390 for (i = 0; i < opcnt; i++)
5392 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
5397 if (ops[i].op == OP_RET)
5398 ops[i].regmask_src |= regmask_ret;
5402 // - process trivial calls
5403 for (i = 0; i < opcnt; i++)
5406 if (po->flags & (OPF_RMD|OPF_DONE))
5409 if (po->op == OP_CALL)
5411 pp = process_call_early(i, opcnt, &j);
5413 if (!(po->flags & OPF_ATAIL)) {
5414 // since we know the args, try to collect them
5415 ret = collect_call_args_early(i, pp, ®mask, ®mask_ffca);
5423 // commit esp adjust
5424 if (ops[j].op != OP_POP)
5425 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5427 for (l = 0; l < pp->argc_stack; l++)
5428 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
5432 if (strstr(pp->ret_type.name, "int64"))
5435 po->flags |= OPF_DONE;
5441 // - process calls, stage 2
5442 // - handle some push/pop pairs
5443 // - scan for STD/CLD, propagate DF
5444 // - try to resolve needed x87 status word bits
5445 for (i = 0; i < opcnt; i++)
5450 if (po->flags & OPF_RMD)
5453 if (po->op == OP_CALL)
5455 if (!(po->flags & OPF_DONE)) {
5456 pp = process_call(i, opcnt);
5458 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
5459 // since we know the args, collect them
5460 collect_call_args(po, i, pp, ®mask, save_arg_vars,
5463 // for unresolved, collect after other passes
5467 ferr_assert(po, pp != NULL);
5469 po->regmask_src |= get_pp_arg_regmask_src(pp);
5470 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
5472 if (po->regmask_dst & mxST0)
5473 po->flags |= OPF_FPUSH;
5475 if (strstr(pp->ret_type.name, "int64"))
5481 if (po->flags & OPF_DONE)
5486 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
5487 && po->operand[0].type == OPT_CONST)
5489 scan_for_pop_const(i, opcnt, i + opcnt * 12);
5494 scan_pushes_for_pop(i, opcnt, ®mask_pp);
5498 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
5499 scan_propagate_df(i + 1, opcnt);
5504 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
5505 ferr(po, "TODO: fnstsw to mem\n");
5506 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
5508 ferr(po, "fnstsw resolve failed\n");
5509 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
5510 (void *)(long)(mask | (z_check << 16)));
5512 ferr(po, "failed to find fcom: %d\n", ret);
5521 // - find POPs for PUSHes, rm both
5522 // - scan for all used registers
5523 memset(cbits, 0, sizeof(cbits));
5524 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
5525 0, ®mask_save, ®mask_init, regmask_arg);
5528 // - find flag set ops for their users
5529 // - do unresolved calls
5530 // - declare indirect functions
5531 // - other op specific processing
5532 for (i = 0; i < opcnt; i++)
5535 if (po->flags & (OPF_RMD|OPF_DONE))
5538 if (po->flags & OPF_CC)
5540 int setters[16], cnt = 0, branched = 0;
5542 ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
5543 &branched, setters, &cnt);
5544 if (ret < 0 || cnt <= 0)
5545 ferr(po, "unable to trace flag setter(s)\n");
5546 if (cnt > ARRAY_SIZE(setters))
5547 ferr(po, "too many flag setters\n");
5549 for (j = 0; j < cnt; j++)
5551 tmp_op = &ops[setters[j]]; // flag setter
5554 // to get nicer code, we try to delay test and cmp;
5555 // if we can't because of operand modification, or if we
5556 // have arith op, or branch, make it calculate flags explicitly
5557 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
5559 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
5560 pfomask = 1 << po->pfo;
5562 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
5563 pfomask = 1 << po->pfo;
5566 // see if we'll be able to handle based on op result
5567 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
5568 && po->pfo != PFO_Z && po->pfo != PFO_S
5569 && po->pfo != PFO_P)
5571 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
5573 pfomask = 1 << po->pfo;
5576 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
5577 propagate_lmod(tmp_op, &tmp_op->operand[0],
5578 &tmp_op->operand[1]);
5579 if (tmp_op->operand[0].lmod == OPLM_DWORD)
5584 tmp_op->pfomask |= pfomask;
5585 cond_vars |= pfomask;
5587 // note: may overwrite, currently not a problem
5591 if (po->op == OP_RCL || po->op == OP_RCR
5592 || po->op == OP_ADC || po->op == OP_SBB)
5593 cond_vars |= 1 << PFO_C;
5599 cond_vars |= 1 << PFO_Z;
5603 if (po->operand[0].lmod == OPLM_DWORD)
5608 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
5613 // note: resolved non-reg calls are OPF_DONE already
5615 ferr_assert(po, pp != NULL);
5617 if (pp->is_unresolved) {
5618 int regmask_stack = 0;
5619 collect_call_args(po, i, pp, ®mask, save_arg_vars,
5622 // this is pretty rough guess:
5623 // see ecx and edx were pushed (and not their saved versions)
5624 for (arg = 0; arg < pp->argc; arg++) {
5625 if (pp->arg[arg].reg != NULL)
5628 tmp_op = pp->arg[arg].datap;
5630 ferr(po, "parsed_op missing for arg%d\n", arg);
5631 if (tmp_op->p_argnum == 0 && tmp_op->operand[0].type == OPT_REG)
5632 regmask_stack |= 1 << tmp_op->operand[0].reg;
5635 if (!((regmask_stack & (1 << xCX))
5636 && (regmask_stack & (1 << xDX))))
5638 if (pp->argc_stack != 0
5639 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
5641 pp_insert_reg_arg(pp, "ecx");
5642 pp->is_fastcall = 1;
5643 regmask_init |= 1 << xCX;
5644 regmask |= 1 << xCX;
5646 if (pp->argc_stack != 0
5647 || ((regmask | regmask_arg) & (1 << xDX)))
5649 pp_insert_reg_arg(pp, "edx");
5650 regmask_init |= 1 << xDX;
5651 regmask |= 1 << xDX;
5655 // note: __cdecl doesn't fall into is_unresolved category
5656 if (pp->argc_stack > 0)
5662 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
5664 // <var> = offset <something>
5665 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
5666 && !IS_START(po->operand[1].name, "off_"))
5668 if (!po->operand[0].pp->is_fptr)
5669 ferr(po, "%s not declared as fptr when it should be\n",
5670 po->operand[0].name);
5671 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
5672 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
5673 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
5674 fnote(po, "var: %s\n", buf1);
5675 fnote(po, "func: %s\n", buf2);
5676 ferr(po, "^ mismatch\n");
5684 if (po->operand[0].lmod == OPLM_DWORD) {
5685 // 32bit division is common, look for it
5686 if (po->op == OP_DIV)
5687 ret = scan_for_reg_clear(i, xDX);
5689 ret = scan_for_cdq_edx(i);
5691 po->flags |= OPF_32BIT;
5700 po->flags |= OPF_RMD | OPF_DONE;
5710 if (po->operand[0].lmod == OPLM_QWORD)
5720 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
5722 find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
5724 po->flags |= OPF_32BIT;
5733 float_type = need_double ? "double" : "float";
5734 need_float_stack = !!(regmask & mxST7_2);
5735 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
5736 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
5738 // output starts here
5740 // define userstack size
5741 if (g_func_pp->is_userstack) {
5742 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
5743 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
5744 fprintf(fout, "#endif\n");
5747 // the function itself
5748 ferr_assert(ops, !g_func_pp->is_fptr);
5749 output_pp(fout, g_func_pp,
5750 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
5751 fprintf(fout, "\n{\n");
5753 // declare indirect functions
5754 for (i = 0; i < opcnt; i++) {
5756 if (po->flags & OPF_RMD)
5759 if (po->op == OP_CALL) {
5762 ferr(po, "NULL pp\n");
5764 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
5765 if (pp->name[0] != 0) {
5766 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
5767 memcpy(pp->name, "i_", 2);
5769 // might be declared already
5771 for (j = 0; j < i; j++) {
5772 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
5773 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
5783 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
5786 output_pp(fout, pp, OPP_SIMPLE_ARGS);
5787 fprintf(fout, ";\n");
5792 // output LUTs/jumptables
5793 for (i = 0; i < g_func_pd_cnt; i++) {
5795 fprintf(fout, " static const ");
5796 if (pd->type == OPT_OFFSET) {
5797 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
5799 for (j = 0; j < pd->count; j++) {
5801 fprintf(fout, ", ");
5802 fprintf(fout, "&&%s", pd->d[j].u.label);
5806 fprintf(fout, "%s %s[] =\n { ",
5807 lmod_type_u(ops, pd->lmod), pd->label);
5809 for (j = 0; j < pd->count; j++) {
5811 fprintf(fout, ", ");
5812 fprintf(fout, "%u", pd->d[j].u.val);
5815 fprintf(fout, " };\n");
5819 // declare stack frame, va_arg
5821 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
5822 if (g_func_lmods & (1 << OPLM_WORD))
5823 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
5824 if (g_func_lmods & (1 << OPLM_BYTE))
5825 fprintf(fout, " u8 b[%d];", g_stack_fsz);
5826 if (g_func_lmods & (1 << OPLM_QWORD))
5827 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
5828 fprintf(fout, " } sf;\n");
5832 if (g_func_pp->is_userstack) {
5833 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
5834 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
5838 if (g_func_pp->is_vararg) {
5839 fprintf(fout, " va_list ap;\n");
5843 // declare arg-registers
5844 for (i = 0; i < g_func_pp->argc; i++) {
5845 if (g_func_pp->arg[i].reg != NULL) {
5846 reg = char_array_i(regs_r32,
5847 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
5848 if (regmask & (1 << reg)) {
5849 if (g_func_pp->arg[i].type.is_retreg)
5850 fprintf(fout, " u32 %s = *r_%s;\n",
5851 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
5853 fprintf(fout, " u32 %s = (u32)a%d;\n",
5854 g_func_pp->arg[i].reg, i + 1);
5857 if (g_func_pp->arg[i].type.is_retreg)
5858 ferr(ops, "retreg '%s' is unused?\n",
5859 g_func_pp->arg[i].reg);
5860 fprintf(fout, " // %s = a%d; // unused\n",
5861 g_func_pp->arg[i].reg, i + 1);
5867 // declare normal registers
5868 regmask_now = regmask & ~regmask_arg;
5869 regmask_now &= ~(1 << xSP);
5870 if (regmask_now & 0x00ff) {
5871 for (reg = 0; reg < 8; reg++) {
5872 if (regmask_now & (1 << reg)) {
5873 fprintf(fout, " u32 %s", regs_r32[reg]);
5874 if (regmask_init & (1 << reg))
5875 fprintf(fout, " = 0");
5876 fprintf(fout, ";\n");
5882 if (regmask_now & 0xff00) {
5883 for (reg = 8; reg < 16; reg++) {
5884 if (regmask_now & (1 << reg)) {
5885 fprintf(fout, " mmxr %s", regs_r32[reg]);
5886 if (regmask_init & (1 << reg))
5887 fprintf(fout, " = { 0, }");
5888 fprintf(fout, ";\n");
5894 if (need_float_stack) {
5895 fprintf(fout, " %s f_st[8];\n", float_type);
5896 fprintf(fout, " int f_stp = 0;\n");
5900 if (regmask_now & 0xff0000) {
5901 for (reg = 16; reg < 24; reg++) {
5902 if (regmask_now & (1 << reg)) {
5903 fprintf(fout, " %s f_st%d", float_type, reg - 16);
5904 if (regmask_init & (1 << reg))
5905 fprintf(fout, " = 0");
5906 fprintf(fout, ";\n");
5913 if (need_float_sw) {
5914 fprintf(fout, " u16 f_sw;\n");
5919 for (reg = 0; reg < 8; reg++) {
5920 if (regmask_save & (1 << reg)) {
5921 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
5927 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
5928 if (save_arg_vars[i] == 0)
5930 for (reg = 0; reg < 32; reg++) {
5931 if (save_arg_vars[i] & (1 << reg)) {
5932 fprintf(fout, " u32 %s;\n",
5933 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
5940 for (reg = 0; reg < 32; reg++) {
5941 if (regmask_ffca & (1 << reg)) {
5942 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
5948 // declare push-pop temporaries
5950 for (reg = 0; reg < 8; reg++) {
5951 if (regmask_pp & (1 << reg)) {
5952 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
5959 for (i = 0; i < 8; i++) {
5960 if (cond_vars & (1 << i)) {
5961 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
5968 fprintf(fout, " u32 tmp;\n");
5973 fprintf(fout, " u64 tmp64;\n");
5978 fprintf(fout, "\n");
5980 // do stack clear, if needed
5981 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
5983 if (g_stack_clear_len != 0) {
5984 if (g_stack_clear_len <= 4) {
5985 for (i = 0; i < g_stack_clear_len; i++)
5986 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
5987 fprintf(fout, "0;\n");
5990 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
5991 g_stack_clear_start, g_stack_clear_len * 4);
5995 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
5998 if (g_func_pp->is_vararg) {
5999 if (g_func_pp->argc_stack == 0)
6000 ferr(ops, "vararg func without stack args?\n");
6001 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
6005 for (i = 0; i < opcnt; i++)
6007 if (g_labels[i] != NULL) {
6008 fprintf(fout, "\n%s:\n", g_labels[i]);
6011 delayed_flag_op = NULL;
6012 last_arith_dst = NULL;
6016 if (po->flags & OPF_RMD)
6021 #define assert_operand_cnt(n_) \
6022 if (po->operand_cnt != n_) \
6023 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6025 // conditional/flag using op?
6026 if (po->flags & OPF_CC)
6032 // we go through all this trouble to avoid using parsed_flag_op,
6033 // which makes generated code much nicer
6034 if (delayed_flag_op != NULL)
6036 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6037 po->pfo, po->pfo_inv);
6040 else if (last_arith_dst != NULL
6041 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6042 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6045 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6046 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6047 last_arith_dst->lmod, buf3);
6050 else if (tmp_op != NULL) {
6051 // use preprocessed flag calc results
6052 if (!(tmp_op->pfomask & (1 << po->pfo)))
6053 ferr(po, "not prepared for pfo %d\n", po->pfo);
6055 // note: pfo_inv was not yet applied
6056 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6057 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6060 ferr(po, "all methods of finding comparison failed\n");
6063 if (po->flags & OPF_JMP) {
6064 fprintf(fout, " if %s", buf1);
6066 else if (po->op == OP_RCL || po->op == OP_RCR
6067 || po->op == OP_ADC || po->op == OP_SBB)
6070 fprintf(fout, " cond_%s = %s;\n",
6071 parsed_flag_op_names[po->pfo], buf1);
6073 else if (po->flags & OPF_DATA) { // SETcc
6074 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6075 fprintf(fout, " %s = %s;", buf2, buf1);
6078 ferr(po, "unhandled conditional op\n");
6082 pfomask = po->pfomask;
6087 assert_operand_cnt(2);
6088 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6089 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6090 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
6091 fprintf(fout, " %s = %s;", buf1,
6092 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6097 assert_operand_cnt(2);
6098 po->operand[1].lmod = OPLM_DWORD; // always
6099 fprintf(fout, " %s = %s;",
6100 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6101 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6106 assert_operand_cnt(2);
6107 fprintf(fout, " %s = %s;",
6108 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6109 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6113 assert_operand_cnt(2);
6114 switch (po->operand[1].lmod) {
6116 strcpy(buf3, "(s8)");
6119 strcpy(buf3, "(s16)");
6122 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6124 fprintf(fout, " %s = %s;",
6125 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6126 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6131 assert_operand_cnt(2);
6132 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6133 fprintf(fout, " tmp = %s;",
6134 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6135 fprintf(fout, " %s = %s;",
6136 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6137 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6138 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6139 fprintf(fout, " %s = %stmp;",
6140 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6141 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
6142 snprintf(g_comment, sizeof(g_comment), "xchg");
6146 assert_operand_cnt(1);
6147 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6148 fprintf(fout, " %s = ~%s;", buf1, buf1);
6152 assert_operand_cnt(2);
6153 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6154 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6155 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6156 strcpy(g_comment, "xlat");
6160 assert_operand_cnt(2);
6161 fprintf(fout, " %s = (s32)%s >> 31;",
6162 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6163 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6164 strcpy(g_comment, "cdq");
6168 assert_operand_cnt(1);
6169 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6170 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
6174 if (po->flags & OPF_REP) {
6175 assert_operand_cnt(3);
6180 assert_operand_cnt(2);
6181 fprintf(fout, " %s = %sesi; esi %c= %d;",
6182 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6183 lmod_cast_u_ptr(po, po->operand[1].lmod),
6184 (po->flags & OPF_DF) ? '-' : '+',
6185 lmod_bytes(po, po->operand[1].lmod));
6186 strcpy(g_comment, "lods");
6191 if (po->flags & OPF_REP) {
6192 assert_operand_cnt(3);
6193 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
6194 (po->flags & OPF_DF) ? '-' : '+',
6195 lmod_bytes(po, po->operand[1].lmod));
6196 fprintf(fout, " %sedi = eax;",
6197 lmod_cast_u_ptr(po, po->operand[1].lmod));
6198 strcpy(g_comment, "rep stos");
6201 assert_operand_cnt(2);
6202 fprintf(fout, " %sedi = eax; edi %c= %d;",
6203 lmod_cast_u_ptr(po, po->operand[1].lmod),
6204 (po->flags & OPF_DF) ? '-' : '+',
6205 lmod_bytes(po, po->operand[1].lmod));
6206 strcpy(g_comment, "stos");
6211 j = lmod_bytes(po, po->operand[0].lmod);
6212 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6213 l = (po->flags & OPF_DF) ? '-' : '+';
6214 if (po->flags & OPF_REP) {
6215 assert_operand_cnt(3);
6217 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
6220 " %sedi = %sesi;", buf1, buf1);
6221 strcpy(g_comment, "rep movs");
6224 assert_operand_cnt(2);
6225 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
6226 buf1, buf1, l, j, l, j);
6227 strcpy(g_comment, "movs");
6232 // repe ~ repeat while ZF=1
6233 j = lmod_bytes(po, po->operand[0].lmod);
6234 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6235 l = (po->flags & OPF_DF) ? '-' : '+';
6236 if (po->flags & OPF_REP) {
6237 assert_operand_cnt(3);
6239 " while (ecx != 0) {\n");
6240 if (pfomask & (1 << PFO_C)) {
6243 " cond_c = %sesi < %sedi;\n", buf1, buf1);
6244 pfomask &= ~(1 << PFO_C);
6247 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
6248 buf1, buf1, l, j, l, j);
6251 " if (cond_z %s 0) break;\n",
6252 (po->flags & OPF_REPZ) ? "==" : "!=");
6255 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
6256 (po->flags & OPF_REPZ) ? "e" : "ne");
6259 assert_operand_cnt(2);
6261 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
6262 buf1, buf1, l, j, l, j);
6263 strcpy(g_comment, "cmps");
6265 pfomask &= ~(1 << PFO_Z);
6266 last_arith_dst = NULL;
6267 delayed_flag_op = NULL;
6271 // only does ZF (for now)
6272 // repe ~ repeat while ZF=1
6273 j = lmod_bytes(po, po->operand[1].lmod);
6274 l = (po->flags & OPF_DF) ? '-' : '+';
6275 if (po->flags & OPF_REP) {
6276 assert_operand_cnt(3);
6278 " while (ecx != 0) {\n");
6280 " cond_z = (%seax == %sedi); edi %c= %d;\n",
6281 lmod_cast_u(po, po->operand[1].lmod),
6282 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6285 " if (cond_z %s 0) break;\n",
6286 (po->flags & OPF_REPZ) ? "==" : "!=");
6289 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
6290 (po->flags & OPF_REPZ) ? "e" : "ne");
6293 assert_operand_cnt(2);
6294 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
6295 lmod_cast_u(po, po->operand[1].lmod),
6296 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6297 strcpy(g_comment, "scas");
6299 pfomask &= ~(1 << PFO_Z);
6300 last_arith_dst = NULL;
6301 delayed_flag_op = NULL;
6304 // arithmetic w/flags
6306 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
6307 goto dualop_arith_const;
6308 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6312 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6313 if (po->operand[1].type == OPT_CONST) {
6314 j = lmod_bytes(po, po->operand[0].lmod);
6315 if (((1ull << j * 8) - 1) == po->operand[1].val)
6316 goto dualop_arith_const;
6321 assert_operand_cnt(2);
6322 fprintf(fout, " %s %s= %s;",
6323 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6325 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6326 output_std_flags(fout, po, &pfomask, buf1);
6327 last_arith_dst = &po->operand[0];
6328 delayed_flag_op = NULL;
6332 // and 0, or ~0 used instead mov
6333 assert_operand_cnt(2);
6334 fprintf(fout, " %s = %s;",
6335 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6336 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6337 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6338 output_std_flags(fout, po, &pfomask, buf1);
6339 last_arith_dst = &po->operand[0];
6340 delayed_flag_op = NULL;
6345 assert_operand_cnt(2);
6346 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6347 if (pfomask & (1 << PFO_C)) {
6348 if (po->operand[1].type == OPT_CONST) {
6349 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6350 j = po->operand[1].val;
6353 if (po->op == OP_SHL)
6357 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
6361 ferr(po, "zero shift?\n");
6365 pfomask &= ~(1 << PFO_C);
6367 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
6368 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6369 if (po->operand[1].type != OPT_CONST)
6370 fprintf(fout, " & 0x1f");
6372 output_std_flags(fout, po, &pfomask, buf1);
6373 last_arith_dst = &po->operand[0];
6374 delayed_flag_op = NULL;
6378 assert_operand_cnt(2);
6379 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6380 fprintf(fout, " %s = %s%s >> %s;", buf1,
6381 lmod_cast_s(po, po->operand[0].lmod), buf1,
6382 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6383 output_std_flags(fout, po, &pfomask, buf1);
6384 last_arith_dst = &po->operand[0];
6385 delayed_flag_op = NULL;
6390 assert_operand_cnt(3);
6391 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6392 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6393 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
6394 if (po->operand[2].type != OPT_CONST) {
6395 // no handling for "undefined" case, hopefully not needed
6396 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
6399 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6400 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6401 if (po->op == OP_SHLD) {
6402 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
6403 buf1, buf3, buf1, buf2, l, buf3);
6404 strcpy(g_comment, "shld");
6407 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
6408 buf1, buf3, buf1, buf2, l, buf3);
6409 strcpy(g_comment, "shrd");
6411 output_std_flags(fout, po, &pfomask, buf1);
6412 last_arith_dst = &po->operand[0];
6413 delayed_flag_op = NULL;
6418 assert_operand_cnt(2);
6419 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6420 if (po->operand[1].type == OPT_CONST) {
6421 j = po->operand[1].val;
6422 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
6423 fprintf(fout, po->op == OP_ROL ?
6424 " %s = (%s << %d) | (%s >> %d);" :
6425 " %s = (%s >> %d) | (%s << %d);",
6426 buf1, buf1, j, buf1,
6427 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
6431 output_std_flags(fout, po, &pfomask, buf1);
6432 last_arith_dst = &po->operand[0];
6433 delayed_flag_op = NULL;
6438 assert_operand_cnt(2);
6439 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6440 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6441 if (po->operand[1].type == OPT_CONST) {
6442 j = po->operand[1].val % l;
6444 ferr(po, "zero rotate\n");
6445 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
6446 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
6447 if (po->op == OP_RCL) {
6449 " %s = (%s << %d) | (cond_c << %d)",
6450 buf1, buf1, j, j - 1);
6452 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
6456 " %s = (%s >> %d) | (cond_c << %d)",
6457 buf1, buf1, j, l - j);
6459 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
6461 fprintf(fout, ";\n");
6462 fprintf(fout, " cond_c = tmp;");
6466 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
6467 output_std_flags(fout, po, &pfomask, buf1);
6468 last_arith_dst = &po->operand[0];
6469 delayed_flag_op = NULL;
6473 assert_operand_cnt(2);
6474 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6475 if (IS(opr_name(po, 0), opr_name(po, 1))) {
6476 // special case for XOR
6477 int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
6478 for (j = 0; j <= PFO_LE; j++) {
6479 if (pfomask & (1 << j)) {
6480 fprintf(fout, " cond_%s = %d;\n",
6481 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
6482 pfomask &= ~(1 << j);
6485 fprintf(fout, " %s = 0;",
6486 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6487 last_arith_dst = &po->operand[0];
6488 delayed_flag_op = NULL;
6494 assert_operand_cnt(2);
6495 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6496 if (pfomask & (1 << PFO_C)) {
6497 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6498 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6499 if (po->operand[0].lmod == OPLM_DWORD) {
6500 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
6501 fprintf(fout, " cond_c = tmp64 >> 32;\n");
6502 fprintf(fout, " %s = (u32)tmp64;",
6503 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6504 strcat(g_comment, " add64");
6507 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
6508 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
6509 fprintf(fout, " %s += %s;",
6510 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6513 pfomask &= ~(1 << PFO_C);
6514 output_std_flags(fout, po, &pfomask, buf1);
6515 last_arith_dst = &po->operand[0];
6516 delayed_flag_op = NULL;
6519 if (pfomask & (1 << PFO_LE)) {
6520 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
6521 fprintf(fout, " cond_%s = %s;\n",
6522 parsed_flag_op_names[PFO_LE], buf1);
6523 pfomask &= ~(1 << PFO_LE);
6528 assert_operand_cnt(2);
6529 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6530 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
6531 for (j = 0; j <= PFO_LE; j++) {
6532 if (!(pfomask & (1 << j)))
6534 if (j == PFO_Z || j == PFO_S)
6537 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6538 fprintf(fout, " cond_%s = %s;\n",
6539 parsed_flag_op_names[j], buf1);
6540 pfomask &= ~(1 << j);
6547 assert_operand_cnt(2);
6548 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6549 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6550 if (po->op == OP_SBB
6551 && IS(po->operand[0].name, po->operand[1].name))
6553 // avoid use of unitialized var
6554 fprintf(fout, " %s = -cond_c;", buf1);
6555 // carry remains what it was
6556 pfomask &= ~(1 << PFO_C);
6559 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
6560 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6562 output_std_flags(fout, po, &pfomask, buf1);
6563 last_arith_dst = &po->operand[0];
6564 delayed_flag_op = NULL;
6568 assert_operand_cnt(2);
6569 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6570 fprintf(fout, " %s = %s ? __builtin_ffs(%s) - 1 : 0;",
6571 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6573 output_std_flags(fout, po, &pfomask, buf1);
6574 last_arith_dst = &po->operand[0];
6575 delayed_flag_op = NULL;
6576 strcat(g_comment, " bsf");
6580 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
6581 for (j = 0; j <= PFO_LE; j++) {
6582 if (!(pfomask & (1 << j)))
6584 if (j == PFO_Z || j == PFO_S || j == PFO_C)
6587 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6588 fprintf(fout, " cond_%s = %s;\n",
6589 parsed_flag_op_names[j], buf1);
6590 pfomask &= ~(1 << j);
6596 if (pfomask & (1 << PFO_C))
6597 // carry is unaffected by inc/dec.. wtf?
6598 ferr(po, "carry propagation needed\n");
6600 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6601 if (po->operand[0].type == OPT_REG) {
6602 strcpy(buf2, po->op == OP_INC ? "++" : "--");
6603 fprintf(fout, " %s%s;", buf1, buf2);
6606 strcpy(buf2, po->op == OP_INC ? "+" : "-");
6607 fprintf(fout, " %s %s= 1;", buf1, buf2);
6609 output_std_flags(fout, po, &pfomask, buf1);
6610 last_arith_dst = &po->operand[0];
6611 delayed_flag_op = NULL;
6615 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6616 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
6617 fprintf(fout, " %s = -%s%s;", buf1,
6618 lmod_cast_s(po, po->operand[0].lmod), buf2);
6619 last_arith_dst = &po->operand[0];
6620 delayed_flag_op = NULL;
6621 if (pfomask & (1 << PFO_C)) {
6622 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
6623 pfomask &= ~(1 << PFO_C);
6628 if (po->operand_cnt == 2) {
6629 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6632 if (po->operand_cnt == 3)
6633 ferr(po, "TODO imul3\n");
6636 assert_operand_cnt(1);
6637 switch (po->operand[0].lmod) {
6639 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
6640 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
6641 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
6642 fprintf(fout, " edx = tmp64 >> 32;\n");
6643 fprintf(fout, " eax = tmp64;");
6646 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
6647 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
6648 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
6652 ferr(po, "TODO: unhandled mul type\n");
6655 last_arith_dst = NULL;
6656 delayed_flag_op = NULL;
6661 assert_operand_cnt(1);
6662 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6663 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
6664 po->op == OP_IDIV));
6665 switch (po->operand[0].lmod) {
6667 if (po->flags & OPF_32BIT)
6668 snprintf(buf2, sizeof(buf2), "%seax", cast);
6670 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
6671 snprintf(buf2, sizeof(buf2), "%stmp64",
6672 (po->op == OP_IDIV) ? "(s64)" : "");
6674 if (po->operand[0].type == OPT_REG
6675 && po->operand[0].reg == xDX)
6677 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
6678 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
6681 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
6682 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
6686 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
6687 snprintf(buf2, sizeof(buf2), "%stmp",
6688 (po->op == OP_IDIV) ? "(s32)" : "");
6689 if (po->operand[0].type == OPT_REG
6690 && po->operand[0].reg == xDX)
6692 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
6694 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
6698 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
6700 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
6703 strcat(g_comment, " div16");
6706 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
6708 last_arith_dst = NULL;
6709 delayed_flag_op = NULL;
6714 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6716 for (j = 0; j < 8; j++) {
6717 if (pfomask & (1 << j)) {
6718 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
6719 fprintf(fout, " cond_%s = %s;",
6720 parsed_flag_op_names[j], buf1);
6727 last_arith_dst = NULL;
6728 delayed_flag_op = po;
6732 // SETcc - should already be handled
6735 // note: we reuse OP_Jcc for SETcc, only flags differ
6737 fprintf(fout, "\n goto %s;", po->operand[0].name);
6741 fprintf(fout, " if (ecx == 0)\n");
6742 fprintf(fout, " goto %s;", po->operand[0].name);
6743 strcat(g_comment, " jecxz");
6747 fprintf(fout, " if (--ecx != 0)\n");
6748 fprintf(fout, " goto %s;", po->operand[0].name);
6749 strcat(g_comment, " loop");
6753 assert_operand_cnt(1);
6754 last_arith_dst = NULL;
6755 delayed_flag_op = NULL;
6757 if (po->operand[0].type == OPT_REGMEM) {
6758 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
6761 ferr(po, "parse failure for jmp '%s'\n",
6762 po->operand[0].name);
6763 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
6766 else if (po->operand[0].type != OPT_LABEL)
6767 ferr(po, "unhandled jmp type\n");
6769 fprintf(fout, " goto %s;", po->operand[0].name);
6773 assert_operand_cnt(1);
6775 my_assert_not(pp, NULL);
6778 if (po->flags & OPF_CC) {
6779 // we treat conditional branch to another func
6780 // (yes such code exists..) as conditional tailcall
6782 fprintf(fout, " {\n");
6785 if (pp->is_fptr && !pp->is_arg) {
6786 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
6787 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6789 if (pp->is_unresolved)
6790 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
6791 buf3, asmfn, po->asmln, pp->name);
6794 fprintf(fout, "%s", buf3);
6795 if (strstr(pp->ret_type.name, "int64")) {
6796 if (po->flags & OPF_TAIL)
6797 ferr(po, "int64 and tail?\n");
6798 fprintf(fout, "tmp64 = ");
6800 else if (!IS(pp->ret_type.name, "void")) {
6801 if (po->flags & OPF_TAIL) {
6802 if (regmask_ret & mxAX) {
6803 fprintf(fout, "return ");
6804 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
6805 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
6807 else if (regmask_ret & mxST0)
6808 ferr(po, "float tailcall\n");
6810 else if (po->regmask_dst & mxAX) {
6811 fprintf(fout, "eax = ");
6812 if (pp->ret_type.is_ptr)
6813 fprintf(fout, "(u32)");
6815 else if (po->regmask_dst & mxST0) {
6816 ferr_assert(po, po->flags & OPF_FPUSH);
6817 if (need_float_stack)
6818 fprintf(fout, "f_st[--f_stp & 7] = ");
6820 fprintf(fout, "f_st0 = ");
6824 if (pp->name[0] == 0)
6825 ferr(po, "missing pp->name\n");
6826 fprintf(fout, "%s%s(", pp->name,
6827 pp->has_structarg ? "_sa" : "");
6829 if (po->flags & OPF_ATAIL) {
6830 if (pp->argc_stack != g_func_pp->argc_stack
6831 || (pp->argc_stack > 0
6832 && pp->is_stdcall != g_func_pp->is_stdcall))
6833 ferr(po, "incompatible tailcall\n");
6834 if (g_func_pp->has_retreg)
6835 ferr(po, "TODO: retreg+tailcall\n");
6837 for (arg = j = 0; arg < pp->argc; arg++) {
6839 fprintf(fout, ", ");
6842 if (pp->arg[arg].type.is_ptr)
6843 snprintf(cast, sizeof(cast), "(%s)",
6844 pp->arg[arg].type.name);
6846 if (pp->arg[arg].reg != NULL) {
6847 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6851 for (; j < g_func_pp->argc; j++)
6852 if (g_func_pp->arg[j].reg == NULL)
6854 fprintf(fout, "%sa%d", cast, j + 1);
6859 for (arg = 0; arg < pp->argc; arg++) {
6861 fprintf(fout, ", ");
6864 if (pp->arg[arg].type.is_ptr)
6865 snprintf(cast, sizeof(cast), "(%s)",
6866 pp->arg[arg].type.name);
6868 if (pp->arg[arg].reg != NULL) {
6869 if (pp->arg[arg].type.is_retreg)
6870 fprintf(fout, "&%s", pp->arg[arg].reg);
6872 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6877 tmp_op = pp->arg[arg].datap;
6879 ferr(po, "parsed_op missing for arg%d\n", arg);
6881 if (tmp_op->flags & OPF_VAPUSH) {
6882 fprintf(fout, "ap");
6884 else if (tmp_op->op == OP_FST) {
6885 fprintf(fout, "fs_%d", tmp_op->p_argnum);
6886 if (tmp_op->operand[0].lmod == OPLM_QWORD)
6889 else if (tmp_op->p_argpass != 0) {
6890 fprintf(fout, "a%d", tmp_op->p_argpass);
6892 else if (tmp_op->p_argnum != 0) {
6893 fprintf(fout, "%s%s", cast,
6894 saved_arg_name(buf1, sizeof(buf1),
6895 tmp_op->p_arggrp, tmp_op->p_argnum));
6899 out_src_opr(buf1, sizeof(buf1),
6900 tmp_op, &tmp_op->operand[0], cast, 0));
6904 fprintf(fout, ");");
6906 if (strstr(pp->ret_type.name, "int64")) {
6907 fprintf(fout, "\n");
6908 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
6909 fprintf(fout, "%seax = tmp64;", buf3);
6912 if (pp->is_unresolved) {
6913 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
6915 strcat(g_comment, buf2);
6918 if (po->flags & OPF_TAIL) {
6920 if (i == opcnt - 1 || pp->is_noreturn)
6922 else if (IS(pp->ret_type.name, "void"))
6924 else if (!(regmask_ret & (1 << xAX)))
6926 // else already handled as 'return f()'
6929 fprintf(fout, "\n%sreturn;", buf3);
6930 strcat(g_comment, " ^ tailcall");
6933 strcat(g_comment, " tailcall");
6935 if ((regmask_ret & (1 << xAX))
6936 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
6938 ferr(po, "int func -> void func tailcall?\n");
6941 if (pp->is_noreturn)
6942 strcat(g_comment, " noreturn");
6943 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
6944 strcat(g_comment, " argframe");
6945 if (po->flags & OPF_CC)
6946 strcat(g_comment, " cond");
6948 if (po->flags & OPF_CC)
6949 fprintf(fout, "\n }");
6951 delayed_flag_op = NULL;
6952 last_arith_dst = NULL;
6956 if (g_func_pp->is_vararg)
6957 fprintf(fout, " va_end(ap);\n");
6958 if (g_func_pp->has_retreg) {
6959 for (arg = 0; arg < g_func_pp->argc; arg++)
6960 if (g_func_pp->arg[arg].type.is_retreg)
6961 fprintf(fout, " *r_%s = %s;\n",
6962 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
6965 if (regmask_ret & mxST0) {
6966 fprintf(fout, " return %s;", float_st0);
6968 else if (!(regmask_ret & mxAX)) {
6969 if (i != opcnt - 1 || label_pending)
6970 fprintf(fout, " return;");
6972 else if (g_func_pp->ret_type.is_ptr) {
6973 fprintf(fout, " return (%s)eax;",
6974 g_func_pp->ret_type.name);
6976 else if (IS(g_func_pp->ret_type.name, "__int64"))
6977 fprintf(fout, " return ((u64)edx << 32) | eax;");
6979 fprintf(fout, " return eax;");
6981 last_arith_dst = NULL;
6982 delayed_flag_op = NULL;
6986 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6987 if (po->p_argnum != 0) {
6988 // special case - saved func arg
6989 fprintf(fout, " %s = %s;",
6990 saved_arg_name(buf2, sizeof(buf2),
6991 po->p_arggrp, po->p_argnum), buf1);
6994 else if (po->flags & OPF_RSAVE) {
6995 fprintf(fout, " s_%s = %s;", buf1, buf1);
6998 else if (po->flags & OPF_PPUSH) {
7000 ferr_assert(po, tmp_op != NULL);
7001 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7002 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7005 else if (g_func_pp->is_userstack) {
7006 fprintf(fout, " *(--esp) = %s;", buf1);
7009 if (!(g_ida_func_attr & IDAFA_NORETURN))
7010 ferr(po, "stray push encountered\n");
7015 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7016 if (po->flags & OPF_RSAVE) {
7017 fprintf(fout, " %s = s_%s;", buf1, buf1);
7020 else if (po->flags & OPF_PPUSH) {
7021 // push/pop graph / non-const
7022 ferr_assert(po, po->datap == NULL);
7023 fprintf(fout, " %s = pp_%s;", buf1, buf1);
7026 else if (po->datap != NULL) {
7029 fprintf(fout, " %s = %s;", buf1,
7030 out_src_opr(buf2, sizeof(buf2),
7031 tmp_op, &tmp_op->operand[0],
7032 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7035 else if (g_func_pp->is_userstack) {
7036 fprintf(fout, " %s = *esp++;", buf1);
7040 ferr(po, "stray pop encountered\n");
7050 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7051 fprintf(fout, " tmp64 = (s64)tmp64 %s= LOBYTE(ecx);\n",
7052 po->op == OPP_ALLSHL ? "<<" : ">>");
7053 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
7054 strcat(g_comment, po->op == OPP_ALLSHL
7055 ? " allshl" : " allshr");
7060 if (need_float_stack) {
7061 out_src_opr_float(buf1, sizeof(buf1),
7062 po, &po->operand[0], 1);
7063 if (po->regmask_src & mxSTa) {
7064 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7068 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
7071 if (po->flags & OPF_FSHIFT)
7072 fprintf(fout, " f_st1 = f_st0;");
7073 if (po->operand[0].type == OPT_REG
7074 && po->operand[0].reg == xST0)
7076 strcat(g_comment, " fld st");
7079 fprintf(fout, " f_st0 = %s;",
7080 out_src_opr_float(buf1, sizeof(buf1),
7081 po, &po->operand[0], 0));
7083 strcat(g_comment, " fld");
7087 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7088 lmod_cast(po, po->operand[0].lmod, 1), 0);
7089 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7090 if (need_float_stack) {
7091 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
7094 if (po->flags & OPF_FSHIFT)
7095 fprintf(fout, " f_st1 = f_st0;");
7096 fprintf(fout, " f_st0 = %s;", buf2);
7098 strcat(g_comment, " fild");
7102 if (need_float_stack)
7103 fprintf(fout, " f_st[--f_stp & 7] = ");
7105 if (po->flags & OPF_FSHIFT)
7106 fprintf(fout, " f_st1 = f_st0;");
7107 fprintf(fout, " f_st0 = ");
7109 switch (po->operand[0].val) {
7110 case X87_CONST_1: fprintf(fout, "1.0;"); break;
7111 case X87_CONST_LN2: fprintf(fout, "0.693147180559945;"); break;
7112 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
7113 default: ferr(po, "TODO\n"); break;
7118 if (po->flags & OPF_FARG) {
7119 // store to stack as func arg
7120 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7124 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7126 dead_dst = po->operand[0].type == OPT_REG
7127 && po->operand[0].reg == xST0;
7130 fprintf(fout, " %s = %s;", buf1, float_st0);
7131 if (po->flags & OPF_FSHIFT) {
7132 if (need_float_stack)
7133 fprintf(fout, " f_stp++;");
7135 fprintf(fout, " f_st0 = f_st1;");
7137 if (dead_dst && !(po->flags & OPF_FSHIFT))
7140 strcat(g_comment, " fst");
7144 fprintf(fout, " %s = %s%s;",
7145 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7146 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7147 if (po->flags & OPF_FSHIFT) {
7148 if (need_float_stack)
7149 fprintf(fout, " f_stp++;");
7151 fprintf(fout, " f_st0 = f_st1;");
7153 strcat(g_comment, " fist");
7160 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7162 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7164 dead_dst = (po->flags & OPF_FPOP)
7165 && po->operand[0].type == OPT_REG
7166 && po->operand[0].reg == xST0;
7168 case OP_FADD: j = '+'; break;
7169 case OP_FDIV: j = '/'; break;
7170 case OP_FMUL: j = '*'; break;
7171 case OP_FSUB: j = '-'; break;
7172 default: j = 'x'; break;
7174 if (need_float_stack) {
7176 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7177 if (po->flags & OPF_FSHIFT)
7178 fprintf(fout, " f_stp++;");
7181 if (po->flags & OPF_FSHIFT) {
7182 // note: assumes only 2 regs handled
7184 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
7186 fprintf(fout, " f_st0 = f_st1;");
7189 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7191 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7196 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7198 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7200 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
7202 dead_dst = (po->flags & OPF_FPOP)
7203 && po->operand[0].type == OPT_REG
7204 && po->operand[0].reg == xST0;
7205 j = po->op == OP_FDIVR ? '/' : '-';
7206 if (need_float_stack) {
7208 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7209 if (po->flags & OPF_FSHIFT)
7210 fprintf(fout, " f_stp++;");
7213 if (po->flags & OPF_FSHIFT) {
7215 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
7217 fprintf(fout, " f_st0 = f_st1;");
7220 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7222 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7230 case OP_FIADD: j = '+'; break;
7231 case OP_FIDIV: j = '/'; break;
7232 case OP_FIMUL: j = '*'; break;
7233 case OP_FISUB: j = '-'; break;
7234 default: j = 'x'; break;
7236 fprintf(fout, " %s %c= (%s)%s;", float_st0,
7238 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7239 lmod_cast(po, po->operand[0].lmod, 1), 0));
7244 fprintf(fout, " %s = %s %c %s;", float_st0,
7245 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7247 po->op == OP_FIDIVR ? '/' : '-', float_st0);
7252 ferr_assert(po, po->datap != NULL);
7253 mask = (long)po->datap & 0xffff;
7254 z_check = ((long)po->datap >> 16) & 1;
7255 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7257 if (mask == 0x0100) { // C0 -> <
7258 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
7261 else if (mask == 0x4000) { // C3 -> =
7262 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
7265 else if (mask == 0x4100) { // C3, C0
7267 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
7269 strcat(g_comment, " z_chk_det");
7272 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
7273 "(%s < %s ? 0x0100 : 0);",
7274 float_st0, buf1, float_st0, buf1);
7278 ferr(po, "unhandled sw mask: %x\n", mask);
7279 if (po->flags & OPF_FSHIFT) {
7280 if (need_float_stack)
7281 fprintf(fout, " f_stp++;");
7283 fprintf(fout, " f_st0 = f_st1;");
7289 fprintf(fout, " %s = f_sw;",
7290 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7294 fprintf(fout, " %s = -%s;", float_st0, float_st0);
7298 fprintf(fout, " %s = cos%s(%s);", float_st0,
7299 need_double ? "" : "f", float_st0);
7303 if (need_float_stack) {
7304 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
7305 need_double ? "" : "f", float_st1, float_st0);
7306 fprintf(fout, " f_stp++;");
7309 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
7310 need_double ? "" : "f");
7315 if (need_float_stack) {
7316 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
7317 float_st1, need_double ? "" : "f", float_st0);
7318 fprintf(fout, " f_stp++;");
7321 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
7322 need_double ? "" : "f");
7327 fprintf(fout, " %s = sin%s(%s);", float_st0,
7328 need_double ? "" : "f", float_st0);
7332 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
7333 need_double ? "" : "f", float_st0);
7337 dead_dst = po->operand[0].type == OPT_REG
7338 && po->operand[0].reg == xST0;
7340 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7342 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
7343 float_st0, float_st0, buf1, buf1);
7344 strcat(g_comment, " fxch");
7351 ferr_assert(po, po->flags & OPF_32BIT);
7352 fprintf(fout, " eax = (s32)%s;", float_st0);
7353 if (po->flags & OPF_FSHIFT) {
7354 if (need_float_stack)
7355 fprintf(fout, " f_stp++;");
7357 fprintf(fout, " f_st0 = f_st1;");
7359 strcat(g_comment, " ftol");
7364 strcpy(g_comment, " (emms)");
7369 ferr(po, "unhandled op type %d, flags %x\n",
7374 if (g_comment[0] != 0) {
7375 char *p = g_comment;
7376 while (my_isblank(*p))
7378 fprintf(fout, " // %s", p);
7383 fprintf(fout, "\n");
7385 // some sanity checking
7386 if (po->flags & OPF_REP) {
7387 if (po->op != OP_STOS && po->op != OP_MOVS
7388 && po->op != OP_CMPS && po->op != OP_SCAS)
7389 ferr(po, "unexpected rep\n");
7390 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
7391 && (po->op == OP_CMPS || po->op == OP_SCAS))
7392 ferr(po, "cmps/scas with plain rep\n");
7394 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
7395 && po->op != OP_CMPS && po->op != OP_SCAS)
7396 ferr(po, "unexpected repz/repnz\n");
7399 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
7401 // see is delayed flag stuff is still valid
7402 if (delayed_flag_op != NULL && delayed_flag_op != po) {
7403 if (is_any_opr_modified(delayed_flag_op, po, 0))
7404 delayed_flag_op = NULL;
7407 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
7408 if (is_opr_modified(last_arith_dst, po))
7409 last_arith_dst = NULL;
7415 if (g_stack_fsz && !g_stack_frame_used)
7416 fprintf(fout, " (void)sf;\n");
7418 fprintf(fout, "}\n\n");
7420 gen_x_cleanup(opcnt);
7423 static void gen_x_cleanup(int opcnt)
7427 for (i = 0; i < opcnt; i++) {
7428 struct label_ref *lr, *lr_del;
7430 lr = g_label_refs[i].next;
7431 while (lr != NULL) {
7436 g_label_refs[i].i = -1;
7437 g_label_refs[i].next = NULL;
7439 if (ops[i].op == OP_CALL) {
7441 proto_release(ops[i].pp);
7447 struct func_proto_dep;
7449 struct func_prototype {
7454 int has_ret:3; // -1, 0, 1: unresolved, no, yes
7455 unsigned int dep_resolved:1;
7456 unsigned int is_stdcall:1;
7457 struct func_proto_dep *dep_func;
7459 const struct parsed_proto *pp; // seed pp, if any
7462 struct func_proto_dep {
7464 struct func_prototype *proto;
7465 int regmask_live; // .. at the time of call
7466 unsigned int ret_dep:1; // return from this is caller's return
7469 static struct func_prototype *hg_fp;
7470 static int hg_fp_cnt;
7472 static struct scanned_var {
7474 enum opr_lenmod lmod;
7475 unsigned int is_seeded:1;
7476 unsigned int is_c_str:1;
7477 const struct parsed_proto *pp; // seed pp, if any
7479 static int hg_var_cnt;
7481 static char **hg_refs;
7482 static int hg_ref_cnt;
7484 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7487 static struct func_prototype *hg_fp_add(const char *funcn)
7489 struct func_prototype *fp;
7491 if ((hg_fp_cnt & 0xff) == 0) {
7492 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
7493 my_assert_not(hg_fp, NULL);
7494 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
7497 fp = &hg_fp[hg_fp_cnt];
7498 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
7500 fp->argc_stack = -1;
7506 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
7511 for (i = 0; i < fp->dep_func_cnt; i++)
7512 if (IS(fp->dep_func[i].name, name))
7513 return &fp->dep_func[i];
7518 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
7521 if (hg_fp_find_dep(fp, name))
7524 if ((fp->dep_func_cnt & 0xff) == 0) {
7525 fp->dep_func = realloc(fp->dep_func,
7526 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
7527 my_assert_not(fp->dep_func, NULL);
7528 memset(&fp->dep_func[fp->dep_func_cnt], 0,
7529 sizeof(fp->dep_func[0]) * 0x100);
7531 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
7535 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
7537 const struct func_prototype *p1 = p1_, *p2 = p2_;
7538 return strcmp(p1->name, p2->name);
7542 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
7544 const struct func_prototype *p1 = p1_, *p2 = p2_;
7545 return p1->id - p2->id;
7549 static void hg_ref_add(const char *name)
7551 if ((hg_ref_cnt & 0xff) == 0) {
7552 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
7553 my_assert_not(hg_refs, NULL);
7554 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
7557 hg_refs[hg_ref_cnt] = strdup(name);
7558 my_assert_not(hg_refs[hg_ref_cnt], NULL);
7562 // recursive register dep pass
7563 // - track saved regs (part 2)
7564 // - try to figure out arg-regs
7565 // - calculate reg deps
7566 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
7567 struct func_prototype *fp, int regmask_save, int regmask_dst,
7568 int *regmask_dep, int *has_ret)
7570 struct func_proto_dep *dep;
7571 struct parsed_op *po;
7572 int from_caller = 0;
7577 for (; i < opcnt; i++)
7579 if (cbits[i >> 3] & (1 << (i & 7)))
7581 cbits[i >> 3] |= (1 << (i & 7));
7585 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
7586 if (po->flags & OPF_RMD)
7589 if (po->btj != NULL) {
7591 for (j = 0; j < po->btj->count; j++) {
7592 check_i(po, po->btj->d[j].bt_i);
7593 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
7594 regmask_save, regmask_dst, regmask_dep, has_ret);
7599 check_i(po, po->bt_i);
7600 if (po->flags & OPF_CJMP) {
7601 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
7602 regmask_save, regmask_dst, regmask_dep, has_ret);
7610 if (po->flags & OPF_FARG)
7611 /* (just calculate register deps) */;
7612 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
7614 reg = po->operand[0].reg;
7615 ferr_assert(po, reg >= 0);
7617 if (po->flags & OPF_RSAVE) {
7618 regmask_save |= 1 << reg;
7621 if (po->flags & OPF_DONE)
7624 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0);
7626 regmask_save |= 1 << reg;
7627 po->flags |= OPF_RMD;
7628 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, OPF_RMD);
7632 else if (po->flags & OPF_RMD)
7634 else if (po->op == OP_CALL) {
7635 po->regmask_dst |= 1 << xAX;
7637 dep = hg_fp_find_dep(fp, po->operand[0].name);
7639 dep->regmask_live = regmask_save | regmask_dst;
7641 else if (po->op == OP_RET) {
7642 if (po->operand_cnt > 0) {
7644 if (fp->argc_stack >= 0
7645 && fp->argc_stack != po->operand[0].val / 4)
7646 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
7647 fp->argc_stack = po->operand[0].val / 4;
7651 // if has_ret is 0, there is uninitialized eax path,
7652 // which means it's most likely void func
7653 if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
7654 if (po->op == OP_CALL) {
7659 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
7662 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
7665 if (ret != 1 && from_caller) {
7666 // unresolved eax - probably void func
7670 if (j >= 0 && ops[j].op == OP_CALL) {
7671 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
7682 l = regmask_save | regmask_dst;
7683 if (g_bp_frame && !(po->flags & OPF_EBP_S))
7686 l = po->regmask_src & ~l;
7689 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
7690 l, regmask_dst, regmask_save, po->flags);
7693 regmask_dst |= po->regmask_dst;
7695 if (po->flags & OPF_TAIL)
7700 static void gen_hdr(const char *funcn, int opcnt)
7702 int save_arg_vars[MAX_ARG_GRP] = { 0, };
7703 unsigned char cbits[MAX_OPS / 8];
7704 const struct parsed_proto *pp_c;
7705 struct parsed_proto *pp;
7706 struct func_prototype *fp;
7707 struct parsed_op *po;
7708 int regmask_dummy = 0;
7710 int max_bp_offset = 0;
7715 pp_c = proto_parse(g_fhdr, funcn, 1);
7717 // already in seed, will add to hg_fp later
7720 fp = hg_fp_add(funcn);
7722 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
7723 g_stack_frame_used = 0;
7726 // - resolve all branches
7727 // - parse calls with labels
7728 resolve_branches_parse_calls(opcnt);
7731 // - handle ebp/esp frame, remove ops related to it
7732 scan_prologue_epilogue(opcnt);
7735 // - remove dead labels
7737 for (i = 0; i < opcnt; i++)
7739 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7745 if (po->flags & (OPF_RMD|OPF_DONE))
7748 if (po->op == OP_CALL) {
7749 if (po->operand[0].type == OPT_LABEL)
7750 hg_fp_add_dep(fp, opr_name(po, 0));
7751 else if (po->pp != NULL)
7752 hg_fp_add_dep(fp, po->pp->name);
7757 // - remove dead labels
7758 // - handle push <const>/pop pairs
7759 for (i = 0; i < opcnt; i++)
7761 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7767 if (po->flags & (OPF_RMD|OPF_DONE))
7770 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
7771 scan_for_pop_const(i, opcnt, i + opcnt * 13);
7775 // - process trivial calls
7776 for (i = 0; i < opcnt; i++)
7779 if (po->flags & (OPF_RMD|OPF_DONE))
7782 if (po->op == OP_CALL)
7784 pp = process_call_early(i, opcnt, &j);
7786 if (!(po->flags & OPF_ATAIL))
7787 // since we know the args, try to collect them
7788 if (collect_call_args_early(i, pp, NULL, NULL) != 0)
7794 // commit esp adjust
7795 if (ops[j].op != OP_POP)
7796 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
7798 for (l = 0; l < pp->argc_stack; l++)
7799 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
7803 po->flags |= OPF_DONE;
7809 // - track saved regs (simple)
7811 for (i = 0; i < opcnt; i++)
7814 if (po->flags & (OPF_RMD|OPF_DONE))
7817 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
7818 && po->operand[0].reg != xCX)
7820 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
7822 // regmask_save |= 1 << po->operand[0].reg; // do it later
7823 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
7824 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
7827 else if (po->op == OP_CALL)
7829 pp = process_call(i, opcnt);
7831 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
7832 // since we know the args, collect them
7833 ret = collect_call_args(po, i, pp, ®mask_dummy, save_arg_vars,
7840 memset(cbits, 0, sizeof(cbits));
7844 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, ®mask_dep, &has_ret);
7846 // find unreachable code - must be fixed in IDA
7847 for (i = 0; i < opcnt; i++)
7849 if (cbits[i >> 3] & (1 << (i & 7)))
7852 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
7853 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
7855 // the compiler sometimes still generates code after
7856 // noreturn OS functions
7859 if (ops[i].op != OP_NOP)
7860 ferr(&ops[i], "unreachable code\n");
7863 for (i = 0; i < g_eqcnt; i++) {
7864 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
7865 max_bp_offset = g_eqs[i].offset;
7868 if (fp->argc_stack < 0) {
7869 max_bp_offset = (max_bp_offset + 3) & ~3;
7870 fp->argc_stack = max_bp_offset / 4;
7871 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
7875 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
7876 fp->has_ret = has_ret;
7878 printf("// has_ret %d, regmask_dep %x\n",
7879 fp->has_ret, fp->regmask_dep);
7880 output_hdr_fp(stdout, fp, 1);
7881 if (IS(funcn, "sub_10007F72")) exit(1);
7884 gen_x_cleanup(opcnt);
7887 static void hg_fp_resolve_deps(struct func_prototype *fp)
7889 struct func_prototype fp_s;
7893 // this thing is recursive, so mark first..
7894 fp->dep_resolved = 1;
7896 for (i = 0; i < fp->dep_func_cnt; i++) {
7897 strcpy(fp_s.name, fp->dep_func[i].name);
7898 fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
7899 sizeof(hg_fp[0]), hg_fp_cmp_name);
7900 if (fp->dep_func[i].proto != NULL) {
7901 if (!fp->dep_func[i].proto->dep_resolved)
7902 hg_fp_resolve_deps(fp->dep_func[i].proto);
7904 dep = ~fp->dep_func[i].regmask_live
7905 & fp->dep_func[i].proto->regmask_dep;
7906 fp->regmask_dep |= dep;
7907 // printf("dep %s %s |= %x\n", fp->name,
7908 // fp->dep_func[i].name, dep);
7910 if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
7911 fp->has_ret = fp->dep_func[i].proto->has_ret;
7916 // make all thiscall/edx arg functions referenced from .data fastcall
7917 static void do_func_refs_from_data(void)
7919 struct func_prototype *fp, fp_s;
7922 for (i = 0; i < hg_ref_cnt; i++) {
7923 strcpy(fp_s.name, hg_refs[i]);
7924 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
7925 sizeof(hg_fp[0]), hg_fp_cmp_name);
7929 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
7930 fp->regmask_dep |= mxCX | mxDX;
7934 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7937 const struct parsed_proto *pp;
7938 char *p, namebuf[NAMELEN];
7944 for (; count > 0; count--, fp++) {
7945 if (fp->has_ret == -1)
7946 fprintf(fout, "// ret unresolved\n");
7948 fprintf(fout, "// dep:");
7949 for (j = 0; j < fp->dep_func_cnt; j++) {
7950 fprintf(fout, " %s/", fp->dep_func[j].name);
7951 if (fp->dep_func[j].proto != NULL)
7952 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
7953 fp->dep_func[j].proto->has_ret);
7955 fprintf(fout, "\n");
7958 p = strchr(fp->name, '@');
7960 memcpy(namebuf, fp->name, p - fp->name);
7961 namebuf[p - fp->name] = 0;
7969 pp = proto_parse(g_fhdr, name, 1);
7970 if (pp != NULL && pp->is_include)
7973 if (fp->pp != NULL) {
7974 // part of seed, output later
7978 regmask_dep = fp->regmask_dep;
7979 argc_normal = fp->argc_stack;
7981 fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
7982 (fp->has_ret ? "int" : "void"));
7983 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
7984 && (regmask_dep & ~mxCX) == 0)
7986 fprintf(fout, "/*__thiscall*/ ");
7990 else if (regmask_dep && (fp->is_stdcall || fp->argc_stack == 0)
7991 && (regmask_dep & ~(mxCX | mxDX)) == 0)
7993 fprintf(fout, " __fastcall ");
7994 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8000 else if (regmask_dep && !fp->is_stdcall) {
8001 fprintf(fout, "/*__usercall*/ ");
8003 else if (regmask_dep) {
8004 fprintf(fout, "/*__userpurge*/ ");
8006 else if (fp->is_stdcall)
8007 fprintf(fout, " __stdcall ");
8009 fprintf(fout, " __cdecl ");
8011 fprintf(fout, "%s(", name);
8014 for (j = 0; j < xSP; j++) {
8015 if (regmask_dep & (1 << j)) {
8018 fprintf(fout, ", ");
8020 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8022 fprintf(fout, "int");
8023 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
8027 for (j = 0; j < argc_normal; j++) {
8030 fprintf(fout, ", ");
8031 if (fp->pp != NULL) {
8032 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8033 if (!fp->pp->arg[arg - 1].type.is_ptr)
8037 fprintf(fout, "int ");
8038 fprintf(fout, "a%d", arg);
8041 fprintf(fout, ");\n");
8045 static void output_hdr(FILE *fout)
8047 static const char *lmod_c_names[] = {
8048 [OPLM_UNSPEC] = "???",
8049 [OPLM_BYTE] = "uint8_t",
8050 [OPLM_WORD] = "uint16_t",
8051 [OPLM_DWORD] = "uint32_t",
8052 [OPLM_QWORD] = "uint64_t",
8054 const struct scanned_var *var;
8055 struct func_prototype *fp;
8056 char line[256] = { 0, };
8060 // add stuff from headers
8061 for (i = 0; i < pp_cache_size; i++) {
8062 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
8063 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
8065 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
8066 fp = hg_fp_add(name);
8067 fp->pp = &pp_cache[i];
8068 fp->argc_stack = fp->pp->argc_stack;
8069 fp->is_stdcall = fp->pp->is_stdcall;
8070 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
8071 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
8075 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
8076 for (i = 0; i < hg_fp_cnt; i++)
8077 hg_fp_resolve_deps(&hg_fp[i]);
8079 // adjust functions referenced from data segment
8080 do_func_refs_from_data();
8082 // note: messes up .proto ptr, don't use
8083 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
8086 for (i = 0; i < hg_var_cnt; i++) {
8089 if (var->pp != NULL)
8092 else if (var->is_c_str)
8093 fprintf(fout, "extern %-8s %s[];", "char", var->name);
8095 fprintf(fout, "extern %-8s %s;",
8096 lmod_c_names[var->lmod], var->name);
8099 fprintf(fout, " // seeded");
8100 fprintf(fout, "\n");
8103 fprintf(fout, "\n");
8105 // output function prototypes
8106 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
8109 fprintf(fout, "\n// - seed -\n");
8112 while (fgets(line, sizeof(line), g_fhdr))
8113 fwrite(line, 1, strlen(line), fout);
8116 // '=' needs special treatment
8118 static char *next_word_s(char *w, size_t wsize, char *s)
8125 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
8127 for (i = 1; i < wsize - 1; i++) {
8129 printf("warning: missing closing quote: \"%s\"\n", s);
8138 for (; i < wsize - 1; i++) {
8139 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
8145 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
8146 printf("warning: '%s' truncated\n", w);
8151 static int cmpstringp(const void *p1, const void *p2)
8153 return strcmp(*(char * const *)p1, *(char * const *)p2);
8156 static int is_xref_needed(char *p, char **rlist, int rlist_len)
8161 if (strstr(p, "..."))
8162 // unable to determine, assume needed
8165 if (*p == '.') // .text, .data, ...
8166 // ref from other data or non-function -> no
8169 p2 = strpbrk(p, "+:\r\n\x18");
8172 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8173 // referenced from removed code
8179 static int ida_xrefs_show_need(FILE *fasm, char *p,
8180 char **rlist, int rlist_len)
8186 p = strrchr(p, ';');
8187 if (p != NULL && *p == ';' && IS_START(p + 2, "DATA XREF: ")) {
8189 if (is_xref_needed(p, rlist, rlist_len))
8196 if (!my_fgets(line, sizeof(line), fasm))
8198 // non-first line is always indented
8199 if (!my_isblank(line[0]))
8202 // should be no content, just comment
8207 p = strrchr(p, ';');
8209 // it's printed once, but no harm to check again
8210 if (IS_START(p, "DATA XREF: "))
8213 if (is_xref_needed(p, rlist, rlist_len)) {
8218 fseek(fasm, pos, SEEK_SET);
8222 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
8224 struct scanned_var *var;
8225 char line[256] = { 0, };
8234 // skip to next data section
8235 while (my_fgets(line, sizeof(line), fasm))
8240 if (*p == 0 || *p == ';')
8243 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
8244 if (*p == 0 || *p == ';')
8247 if (*p != 's' || !IS_START(p, "segment para public"))
8253 if (p == NULL || !IS_START(p, "segment para public"))
8257 if (!IS_START(p, "'DATA'"))
8261 while (my_fgets(line, sizeof(line), fasm))
8266 no_identifier = my_isblank(*p);
8269 if (*p == 0 || *p == ';')
8272 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8273 words[wordc][0] = 0;
8274 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8275 if (*p == 0 || *p == ';') {
8281 if (wordc == 2 && IS(words[1], "ends"))
8286 if (no_identifier) {
8287 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
8288 hg_ref_add(words[2]);
8292 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
8293 // when this starts, we don't need anything from this section
8297 // check refs comment(s)
8298 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
8301 if ((hg_var_cnt & 0xff) == 0) {
8302 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
8303 * (hg_var_cnt + 0x100));
8304 my_assert_not(hg_vars, NULL);
8305 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
8308 var = &hg_vars[hg_var_cnt++];
8309 snprintf(var->name, sizeof(var->name), "%s", words[0]);
8311 // maybe already in seed header?
8312 var->pp = proto_parse(g_fhdr, var->name, 1);
8313 if (var->pp != NULL) {
8314 if (var->pp->is_fptr) {
8315 var->lmod = OPLM_DWORD;
8318 else if (var->pp->is_func)
8320 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
8321 aerr("unhandled C type '%s' for '%s'\n",
8322 var->pp->type.name, var->name);
8328 if (IS(words[1], "dd")) {
8329 var->lmod = OPLM_DWORD;
8330 if (wordc >= 4 && IS(words[2], "offset"))
8331 hg_ref_add(words[3]);
8333 else if (IS(words[1], "dw"))
8334 var->lmod = OPLM_WORD;
8335 else if (IS(words[1], "db")) {
8336 var->lmod = OPLM_BYTE;
8337 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
8338 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
8342 else if (IS(words[1], "dq"))
8343 var->lmod = OPLM_QWORD;
8344 //else if (IS(words[1], "dt"))
8346 aerr("type '%s' not known\n", words[1]);
8354 static void set_label(int i, const char *name)
8360 p = strchr(name, ':');
8364 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
8365 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
8366 g_labels[i] = realloc(g_labels[i], len + 1);
8367 my_assert_not(g_labels[i], NULL);
8368 memcpy(g_labels[i], name, len);
8369 g_labels[i][len] = 0;
8378 static struct chunk_item *func_chunks;
8379 static int func_chunk_cnt;
8380 static int func_chunk_alloc;
8382 static void add_func_chunk(FILE *fasm, const char *name, int line)
8384 if (func_chunk_cnt >= func_chunk_alloc) {
8385 func_chunk_alloc *= 2;
8386 func_chunks = realloc(func_chunks,
8387 func_chunk_alloc * sizeof(func_chunks[0]));
8388 my_assert_not(func_chunks, NULL);
8390 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
8391 func_chunks[func_chunk_cnt].name = strdup(name);
8392 func_chunks[func_chunk_cnt].asmln = line;
8396 static int cmp_chunks(const void *p1, const void *p2)
8398 const struct chunk_item *c1 = p1, *c2 = p2;
8399 return strcmp(c1->name, c2->name);
8402 static void scan_ahead(FILE *fasm)
8412 oldpos = ftell(fasm);
8415 while (my_fgets(line, sizeof(line), fasm))
8426 // get rid of random tabs
8427 for (i = 0; line[i] != 0; i++)
8428 if (line[i] == '\t')
8431 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8434 next_word(words[0], sizeof(words[0]), p);
8435 if (words[0][0] == 0)
8436 aerr("missing name for func chunk?\n");
8438 add_func_chunk(fasm, words[0], asmln);
8440 else if (IS_START(p, "; sctend"))
8446 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8447 words[wordc][0] = 0;
8448 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8449 if (*p == 0 || *p == ';') {
8455 if (wordc == 2 && IS(words[1], "ends"))
8459 fseek(fasm, oldpos, SEEK_SET);
8463 int main(int argc, char *argv[])
8465 FILE *fout, *fasm, *frlist;
8466 struct parsed_data *pd = NULL;
8468 char **rlist = NULL;
8470 int rlist_alloc = 0;
8471 int func_chunks_used = 0;
8472 int func_chunks_sorted = 0;
8473 int func_chunk_i = -1;
8474 long func_chunk_ret = 0;
8475 int func_chunk_ret_ln = 0;
8476 int scanned_ahead = 0;
8478 char words[20][256];
8479 enum opr_lenmod lmod;
8480 char *sctproto = NULL;
8482 int pending_endp = 0;
8484 int skip_warned = 0;
8497 for (arg = 1; arg < argc; arg++) {
8498 if (IS(argv[arg], "-v"))
8500 else if (IS(argv[arg], "-rf"))
8501 g_allow_regfunc = 1;
8502 else if (IS(argv[arg], "-m"))
8504 else if (IS(argv[arg], "-hdr"))
8505 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
8510 if (argc < arg + 3) {
8511 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
8512 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
8514 " -hdr - header generation mode\n"
8515 " -rf - allow unannotated indirect calls\n"
8516 " -m - allow multiple .text sections\n"
8517 "[rlist] is a file with function names to skip,"
8525 asmfn = argv[arg++];
8526 fasm = fopen(asmfn, "r");
8527 my_assert_not(fasm, NULL);
8529 hdrfn = argv[arg++];
8530 g_fhdr = fopen(hdrfn, "r");
8531 my_assert_not(g_fhdr, NULL);
8534 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
8535 my_assert_not(rlist, NULL);
8536 // needs special handling..
8537 rlist[rlist_len++] = "__alloca_probe";
8539 func_chunk_alloc = 32;
8540 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
8541 my_assert_not(func_chunks, NULL);
8543 memset(words, 0, sizeof(words));
8545 for (; arg < argc; arg++) {
8546 frlist = fopen(argv[arg], "r");
8547 my_assert_not(frlist, NULL);
8549 while (my_fgets(line, sizeof(line), frlist)) {
8551 if (*p == 0 || *p == ';')
8554 if (IS_START(p, "#if 0")
8555 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
8559 else if (IS_START(p, "#endif"))
8566 p = next_word(words[0], sizeof(words[0]), p);
8567 if (words[0][0] == 0)
8570 if (rlist_len >= rlist_alloc) {
8571 rlist_alloc = rlist_alloc * 2 + 64;
8572 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
8573 my_assert_not(rlist, NULL);
8575 rlist[rlist_len++] = strdup(words[0]);
8584 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
8586 fout = fopen(argv[arg_out], "w");
8587 my_assert_not(fout, NULL);
8590 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
8591 my_assert_not(g_eqs, NULL);
8593 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
8594 g_label_refs[i].i = -1;
8595 g_label_refs[i].next = NULL;
8599 scan_variables(fasm, rlist, rlist_len);
8601 while (my_fgets(line, sizeof(line), fasm))
8610 // get rid of random tabs
8611 for (i = 0; line[i] != 0; i++)
8612 if (line[i] == '\t')
8617 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
8618 goto do_pending_endp; // eww..
8620 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
8622 static const char *attrs[] = {
8631 // parse IDA's attribute-list comment
8632 g_ida_func_attr = 0;
8635 for (; *p != 0; p = sskip(p)) {
8636 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8637 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8638 g_ida_func_attr |= 1 << i;
8639 p += strlen(attrs[i]);
8643 if (i == ARRAY_SIZE(attrs)) {
8644 anote("unparsed IDA attr: %s\n", p);
8647 if (IS(attrs[i], "fpd=")) {
8648 p = next_word(words[0], sizeof(words[0]), p);
8653 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
8655 static const char *attrs[] = {
8660 // parse manual attribute-list comment
8661 g_sct_func_attr = 0;
8664 for (; *p != 0; p = sskip(p)) {
8665 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8666 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8667 g_sct_func_attr |= 1 << i;
8668 p += strlen(attrs[i]);
8675 // clear_sf=start,len (in dwords)
8676 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
8677 &g_stack_clear_len, &j);
8679 // clear_regmask=<mask>
8680 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
8682 anote("unparsed attr value: %s\n", p);
8687 else if (i == ARRAY_SIZE(attrs)) {
8688 anote("unparsed sct attr: %s\n", p);
8693 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8696 next_word(words[0], sizeof(words[0]), p);
8697 if (words[0][0] == 0)
8698 aerr("missing name for func chunk?\n");
8700 if (!scanned_ahead) {
8701 add_func_chunk(fasm, words[0], asmln);
8702 func_chunks_sorted = 0;
8705 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
8707 if (func_chunk_i >= 0) {
8708 if (func_chunk_i < func_chunk_cnt
8709 && IS(func_chunks[func_chunk_i].name, g_func))
8711 // move on to next chunk
8712 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
8714 aerr("seek failed for '%s' chunk #%d\n",
8715 g_func, func_chunk_i);
8716 asmln = func_chunks[func_chunk_i].asmln;
8720 if (func_chunk_ret == 0)
8721 aerr("no return from chunk?\n");
8722 fseek(fasm, func_chunk_ret, SEEK_SET);
8723 asmln = func_chunk_ret_ln;
8729 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
8730 func_chunks_used = 1;
8732 if (IS_START(g_func, "sub_")) {
8733 unsigned long addr = strtoul(p, NULL, 16);
8734 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
8735 if (addr > f_addr && !scanned_ahead) {
8736 //anote("scan_ahead caused by '%s', addr %lx\n",
8740 func_chunks_sorted = 0;
8748 for (i = wordc; i < ARRAY_SIZE(words); i++)
8750 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8751 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8752 if (*p == 0 || *p == ';') {
8757 if (*p != 0 && *p != ';')
8758 aerr("too many words\n");
8760 // alow asm patches in comments
8762 if (IS_START(p, "; sctpatch:")) {
8764 if (*p == 0 || *p == ';')
8766 goto parse_words; // lame
8768 if (IS_START(p, "; sctproto:")) {
8769 sctproto = strdup(p + 11);
8771 else if (IS_START(p, "; sctend")) {
8780 awarn("wordc == 0?\n");
8784 // don't care about this:
8785 if (words[0][0] == '.'
8786 || IS(words[0], "include")
8787 || IS(words[0], "assume") || IS(words[1], "segment")
8788 || IS(words[0], "align"))
8794 // do delayed endp processing to collect switch jumptables
8796 if (in_func && !g_skip_func && !end && wordc >= 2
8797 && ((words[0][0] == 'd' && words[0][2] == 0)
8798 || (words[1][0] == 'd' && words[1][2] == 0)))
8801 if (words[1][0] == 'd' && words[1][2] == 0) {
8803 if (g_func_pd_cnt >= pd_alloc) {
8804 pd_alloc = pd_alloc * 2 + 16;
8805 g_func_pd = realloc(g_func_pd,
8806 sizeof(g_func_pd[0]) * pd_alloc);
8807 my_assert_not(g_func_pd, NULL);
8809 pd = &g_func_pd[g_func_pd_cnt];
8811 memset(pd, 0, sizeof(*pd));
8812 strcpy(pd->label, words[0]);
8813 pd->type = OPT_CONST;
8814 pd->lmod = lmod_from_directive(words[1]);
8820 anote("skipping alignment byte?\n");
8823 lmod = lmod_from_directive(words[0]);
8824 if (lmod != pd->lmod)
8825 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
8828 if (pd->count_alloc < pd->count + wordc) {
8829 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
8830 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
8831 my_assert_not(pd->d, NULL);
8833 for (; i < wordc; i++) {
8834 if (IS(words[i], "offset")) {
8835 pd->type = OPT_OFFSET;
8838 p = strchr(words[i], ',');
8841 if (pd->type == OPT_OFFSET)
8842 pd->d[pd->count].u.label = strdup(words[i]);
8844 pd->d[pd->count].u.val = parse_number(words[i]);
8845 pd->d[pd->count].bt_i = -1;
8851 if (in_func && !g_skip_func) {
8853 gen_hdr(g_func, pi);
8855 gen_func(fout, g_fhdr, g_func, pi);
8860 g_ida_func_attr = 0;
8861 g_sct_func_attr = 0;
8862 g_stack_clear_start = 0;
8863 g_stack_clear_len = 0;
8868 func_chunks_used = 0;
8871 memset(&ops, 0, pi * sizeof(ops[0]));
8876 for (i = 0; i < g_func_pd_cnt; i++) {
8878 if (pd->type == OPT_OFFSET) {
8879 for (j = 0; j < pd->count; j++)
8880 free(pd->d[j].u.label);
8895 if (IS(words[1], "proc")) {
8897 aerr("proc '%s' while in_func '%s'?\n",
8900 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8902 strcpy(g_func, words[0]);
8903 set_label(0, words[0]);
8908 if (IS(words[1], "endp"))
8911 aerr("endp '%s' while not in_func?\n", words[0]);
8912 if (!IS(g_func, words[0]))
8913 aerr("endp '%s' while in_func '%s'?\n",
8916 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
8917 && ops[0].op == OP_JMP && ops[0].operand[0].had_ds)
8923 if (!g_skip_func && func_chunks_used) {
8924 // start processing chunks
8925 struct chunk_item *ci, key = { g_func, 0 };
8927 func_chunk_ret = ftell(fasm);
8928 func_chunk_ret_ln = asmln;
8929 if (!func_chunks_sorted) {
8930 qsort(func_chunks, func_chunk_cnt,
8931 sizeof(func_chunks[0]), cmp_chunks);
8932 func_chunks_sorted = 1;
8934 ci = bsearch(&key, func_chunks, func_chunk_cnt,
8935 sizeof(func_chunks[0]), cmp_chunks);
8937 aerr("'%s' needs chunks, but none found\n", g_func);
8938 func_chunk_i = ci - func_chunks;
8939 for (; func_chunk_i > 0; func_chunk_i--)
8940 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
8943 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
8945 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
8946 asmln = func_chunks[func_chunk_i].asmln;
8954 if (wordc == 2 && IS(words[1], "ends")) {
8958 goto do_pending_endp;
8962 // scan for next text segment
8963 while (my_fgets(line, sizeof(line), fasm)) {
8966 if (*p == 0 || *p == ';')
8969 if (strstr(p, "segment para public 'CODE' use32"))
8976 p = strchr(words[0], ':');
8978 set_label(pi, words[0]);
8982 if (!in_func || g_skip_func) {
8983 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
8985 anote("skipping from '%s'\n", g_labels[pi]);
8989 g_labels[pi] = NULL;
8993 if (wordc > 1 && IS(words[1], "="))
8996 aerr("unhandled equ, wc=%d\n", wordc);
8997 if (g_eqcnt >= eq_alloc) {
8999 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
9000 my_assert_not(g_eqs, NULL);
9003 len = strlen(words[0]);
9004 if (len > sizeof(g_eqs[0].name) - 1)
9005 aerr("equ name too long: %d\n", len);
9006 strcpy(g_eqs[g_eqcnt].name, words[0]);
9008 if (!IS(words[3], "ptr"))
9009 aerr("unhandled equ\n");
9010 if (IS(words[2], "dword"))
9011 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
9012 else if (IS(words[2], "word"))
9013 g_eqs[g_eqcnt].lmod = OPLM_WORD;
9014 else if (IS(words[2], "byte"))
9015 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
9016 else if (IS(words[2], "qword"))
9017 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
9019 aerr("bad lmod: '%s'\n", words[2]);
9021 g_eqs[g_eqcnt].offset = parse_number(words[4]);
9026 if (pi >= ARRAY_SIZE(ops))
9027 aerr("too many ops\n");
9029 parse_op(&ops[pi], words, wordc);
9031 ops[pi].datap = sctproto;
9046 // vim:ts=2:shiftwidth=2:expandtab