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 scan_for_flag_set(int i, int magic, int *branched,
3099 int *setters, int *setter_cnt)
3101 struct label_ref *lr;
3105 if (ops[i].cc_scratch == magic) {
3106 // is this a problem?
3107 //ferr(&ops[i], "%s looped\n", __func__);
3110 ops[i].cc_scratch = magic;
3112 if (g_labels[i] != NULL) {
3115 lr = &g_label_refs[i];
3116 for (; lr->next; lr = lr->next) {
3117 check_i(&ops[i], lr->i);
3118 ret = scan_for_flag_set(lr->i, magic,
3119 branched, setters, setter_cnt);
3124 check_i(&ops[i], lr->i);
3125 if (i > 0 && LAST_OP(i - 1)) {
3129 ret = scan_for_flag_set(lr->i, magic,
3130 branched, setters, setter_cnt);
3136 if (ops[i].flags & OPF_FLAGS) {
3137 setters[*setter_cnt] = i;
3142 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3149 // scan back for cdq, if anything modifies edx, fail
3150 static int scan_for_cdq_edx(int i)
3153 if (g_labels[i] != NULL) {
3154 if (g_label_refs[i].next != NULL)
3156 if (i > 0 && LAST_OP(i - 1)) {
3157 i = g_label_refs[i].i;
3164 if (ops[i].op == OP_CDQ)
3167 if (ops[i].regmask_dst & (1 << xDX))
3174 static int scan_for_reg_clear(int i, int reg)
3177 if (g_labels[i] != NULL) {
3178 if (g_label_refs[i].next != NULL)
3180 if (i > 0 && LAST_OP(i - 1)) {
3181 i = g_label_refs[i].i;
3188 if (ops[i].op == OP_XOR
3189 && ops[i].operand[0].lmod == OPLM_DWORD
3190 && ops[i].operand[0].reg == ops[i].operand[1].reg
3191 && ops[i].operand[0].reg == reg)
3194 if (ops[i].regmask_dst & (1 << reg))
3201 static void patch_esp_adjust(struct parsed_op *po, int adj)
3203 ferr_assert(po, po->op == OP_ADD);
3204 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3205 ferr_assert(po, po->operand[1].type == OPT_CONST);
3207 // this is a bit of a hack, but deals with use of
3208 // single adj for multiple calls
3209 po->operand[1].val -= adj;
3210 po->flags |= OPF_RMD;
3211 if (po->operand[1].val == 0)
3212 po->flags |= OPF_DONE;
3213 ferr_assert(po, (int)po->operand[1].val >= 0);
3216 // scan for positive, constant esp adjust
3217 // multipath case is preliminary
3218 static int scan_for_esp_adjust(int i, int opcnt,
3219 int adj_expect, int *adj, int *is_multipath, int do_update)
3221 int adj_expect_unknown = 0;
3222 struct parsed_op *po;
3226 *adj = *is_multipath = 0;
3227 if (adj_expect < 0) {
3228 adj_expect_unknown = 1;
3229 adj_expect = 32 * 4; // enough?
3232 for (; i < opcnt && *adj < adj_expect; i++) {
3233 if (g_labels[i] != NULL)
3237 if (po->flags & OPF_DONE)
3240 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3241 if (po->operand[1].type != OPT_CONST)
3242 ferr(&ops[i], "non-const esp adjust?\n");
3243 *adj += po->operand[1].val;
3245 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3248 patch_esp_adjust(po, adj_expect);
3250 po->flags |= OPF_RMD;
3254 else if (po->op == OP_PUSH) {
3255 //if (first_pop == -1)
3256 // first_pop = -2; // none
3257 *adj -= lmod_bytes(po, po->operand[0].lmod);
3259 else if (po->op == OP_POP) {
3260 if (!(po->flags & OPF_DONE)) {
3261 // seems like msvc only uses 'pop ecx' for stack realignment..
3262 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3264 if (first_pop == -1 && *adj >= 0)
3267 if (do_update && *adj >= 0) {
3268 po->flags |= OPF_RMD;
3270 po->flags |= OPF_DONE | OPF_NOREGS;
3273 *adj += lmod_bytes(po, po->operand[0].lmod);
3274 if (*adj > adj_best)
3277 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3278 if (po->op == OP_JMP && po->btj == NULL) {
3284 if (po->op != OP_CALL)
3286 if (po->operand[0].type != OPT_LABEL)
3288 if (po->pp != NULL && po->pp->is_stdcall)
3290 if (adj_expect_unknown && first_pop >= 0)
3292 // assume it's another cdecl call
3296 if (first_pop >= 0) {
3297 // probably only 'pop ecx' was used
3305 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3307 struct parsed_op *po;
3311 ferr(ops, "%s: followed bad branch?\n", __func__);
3313 for (; i < opcnt; i++) {
3315 if (po->cc_scratch == magic)
3317 po->cc_scratch = magic;
3320 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3321 if (po->btj != NULL) {
3323 for (j = 0; j < po->btj->count; j++)
3324 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3328 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3329 if (!(po->flags & OPF_CJMP))
3332 if (po->flags & OPF_TAIL)
3337 static const struct parsed_proto *try_recover_pp(
3338 struct parsed_op *po, const struct parsed_opr *opr, int *search_instead)
3340 const struct parsed_proto *pp = NULL;
3344 // maybe an arg of g_func?
3345 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3347 char ofs_reg[16] = { 0, };
3348 int arg, arg_s, arg_i;
3355 parse_stack_access(po, opr->name, ofs_reg,
3356 &offset, &stack_ra, NULL, 0);
3357 if (ofs_reg[0] != 0)
3358 ferr(po, "offset reg on arg access?\n");
3359 if (offset <= stack_ra) {
3360 // search who set the stack var instead
3361 if (search_instead != NULL)
3362 *search_instead = 1;
3366 arg_i = (offset - stack_ra - 4) / 4;
3367 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3368 if (g_func_pp->arg[arg].reg != NULL)
3374 if (arg == g_func_pp->argc)
3375 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3377 pp = g_func_pp->arg[arg].fptr;
3379 ferr(po, "icall sa: arg%d is not a fptr?\n", arg + 1);
3380 check_func_pp(po, pp, "icall arg");
3382 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3384 p = strchr(opr->name + 1, '[');
3385 memcpy(buf, opr->name, p - opr->name);
3386 buf[p - opr->name] = 0;
3387 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3389 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3390 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3393 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3396 check_func_pp(po, pp, "reg-fptr ref");
3402 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3403 int magic, const struct parsed_proto **pp_found, int *pp_i,
3406 const struct parsed_proto *pp = NULL;
3407 struct parsed_op *po;
3408 struct label_ref *lr;
3410 ops[i].cc_scratch = magic;
3413 if (g_labels[i] != NULL) {
3414 lr = &g_label_refs[i];
3415 for (; lr != NULL; lr = lr->next) {
3416 check_i(&ops[i], lr->i);
3417 scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3419 if (i > 0 && LAST_OP(i - 1))
3427 if (ops[i].cc_scratch == magic)
3429 ops[i].cc_scratch = magic;
3431 if (!(ops[i].flags & OPF_DATA))
3433 if (!is_opr_modified(opr, &ops[i]))
3435 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3436 // most probably trashed by some processing
3441 opr = &ops[i].operand[1];
3442 if (opr->type != OPT_REG)
3446 po = (i >= 0) ? &ops[i] : ops;
3449 // reached the top - can only be an arg-reg
3450 if (opr->type != OPT_REG || g_func_pp == NULL)
3453 for (i = 0; i < g_func_pp->argc; i++) {
3454 if (g_func_pp->arg[i].reg == NULL)
3456 if (IS(opr->name, g_func_pp->arg[i].reg))
3459 if (i == g_func_pp->argc)
3461 pp = g_func_pp->arg[i].fptr;
3463 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3464 i + 1, g_func_pp->arg[i].reg);
3465 check_func_pp(po, pp, "icall reg-arg");
3468 pp = try_recover_pp(po, opr, NULL);
3470 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3471 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3472 || (*pp_found)->is_stdcall != pp->is_stdcall
3473 || (*pp_found)->is_fptr != pp->is_fptr
3474 || (*pp_found)->argc != pp->argc
3475 || (*pp_found)->argc_reg != pp->argc_reg
3476 || (*pp_found)->argc_stack != pp->argc_stack)
3478 ferr(po, "icall: parsed_proto mismatch\n");
3488 static void add_label_ref(struct label_ref *lr, int op_i)
3490 struct label_ref *lr_new;
3497 lr_new = calloc(1, sizeof(*lr_new));
3499 lr_new->next = lr->next;
3503 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3505 struct parsed_op *po = &ops[i];
3506 struct parsed_data *pd;
3507 char label[NAMELEN], *p;
3510 p = strchr(po->operand[0].name, '[');
3514 len = p - po->operand[0].name;
3515 strncpy(label, po->operand[0].name, len);
3518 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3519 if (IS(g_func_pd[j].label, label)) {
3525 //ferr(po, "label '%s' not parsed?\n", label);
3528 if (pd->type != OPT_OFFSET)
3529 ferr(po, "label '%s' with non-offset data?\n", label);
3531 // find all labels, link
3532 for (j = 0; j < pd->count; j++) {
3533 for (l = 0; l < opcnt; l++) {
3534 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3535 add_label_ref(&g_label_refs[l], i);
3545 static void clear_labels(int count)
3549 for (i = 0; i < count; i++) {
3550 if (g_labels[i] != NULL) {
3557 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3562 for (i = 0; i < pp->argc; i++) {
3563 if (pp->arg[i].reg != NULL) {
3564 reg = char_array_i(regs_r32,
3565 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3567 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3568 pp->arg[i].reg, pp->name);
3569 regmask |= 1 << reg;
3576 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3581 if (pp->has_retreg) {
3582 for (i = 0; i < pp->argc; i++) {
3583 if (pp->arg[i].type.is_retreg) {
3584 reg = char_array_i(regs_r32,
3585 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3586 ferr_assert(ops, reg >= 0);
3587 regmask |= 1 << reg;
3592 if (strstr(pp->ret_type.name, "int64"))
3593 return regmask | (1 << xAX) | (1 << xDX);
3594 if (IS(pp->ret_type.name, "float")
3595 || IS(pp->ret_type.name, "double"))
3597 return regmask | mxST0;
3599 if (strcasecmp(pp->ret_type.name, "void") == 0)
3602 return regmask | mxAX;
3605 static void resolve_branches_parse_calls(int opcnt)
3607 static const struct {
3611 unsigned int regmask_src;
3612 unsigned int regmask_dst;
3614 { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3615 { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3616 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3618 const struct parsed_proto *pp_c;
3619 struct parsed_proto *pp;
3620 struct parsed_data *pd;
3621 struct parsed_op *po;
3622 const char *tmpname;
3626 for (i = 0; i < opcnt; i++)
3632 if (po->datap != NULL) {
3633 pp = calloc(1, sizeof(*pp));
3634 my_assert_not(pp, NULL);
3636 ret = parse_protostr(po->datap, pp);
3638 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3644 if (po->op == OP_CALL) {
3649 else if (po->operand[0].type == OPT_LABEL)
3651 tmpname = opr_name(po, 0);
3652 if (IS_START(tmpname, "loc_"))
3653 ferr(po, "call to loc_*\n");
3654 if (IS(tmpname, "__alloca_probe"))
3657 // convert some calls to pseudo-ops
3658 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3659 if (!IS(tmpname, pseudo_ops[l].name))
3662 po->op = pseudo_ops[l].op;
3663 po->operand_cnt = 0;
3664 po->regmask_src = pseudo_ops[l].regmask_src;
3665 po->regmask_dst = pseudo_ops[l].regmask_dst;
3666 po->flags = pseudo_ops[l].flags;
3667 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3670 if (l < ARRAY_SIZE(pseudo_ops))
3673 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3674 if (!g_header_mode && pp_c == NULL)
3675 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3678 pp = proto_clone(pp_c);
3679 my_assert_not(pp, NULL);
3685 check_func_pp(po, pp, "fptr var call");
3686 if (pp->is_noreturn)
3687 po->flags |= OPF_TAIL;
3693 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3696 if (po->operand[0].type == OPT_REGMEM) {
3697 pd = try_resolve_jumptab(i, opcnt);
3705 for (l = 0; l < opcnt; l++) {
3706 if (g_labels[l] != NULL
3707 && IS(po->operand[0].name, g_labels[l]))
3709 if (l == i + 1 && po->op == OP_JMP) {
3710 // yet another alignment type..
3711 po->flags |= OPF_RMD|OPF_DONE;
3714 add_label_ref(&g_label_refs[l], i);
3720 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3723 if (po->operand[0].type == OPT_LABEL)
3727 ferr(po, "unhandled branch\n");
3731 po->flags |= OPF_TAIL;
3732 if (i > 0 && ops[i - 1].op == OP_POP)
3733 po->flags |= OPF_ATAIL;
3738 static void scan_prologue_epilogue(int opcnt)
3740 int ecx_push = 0, esp_sub = 0, pusha = 0;
3741 int sandard_epilogue;
3745 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
3746 && ops[1].op == OP_MOV
3747 && IS(opr_name(&ops[1], 0), "ebp")
3748 && IS(opr_name(&ops[1], 1), "esp"))
3751 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3752 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3755 if (ops[i].op == OP_PUSHA) {
3756 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3761 if (ops[i].op == OP_SUB && IS(opr_name(&ops[i], 0), "esp")) {
3762 g_stack_fsz = opr_const(&ops[i], 1);
3763 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3767 // another way msvc builds stack frame..
3768 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3770 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3774 // and another way..
3775 if (i == 2 && ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3776 && ops[i].operand[1].type == OPT_CONST
3777 && ops[i + 1].op == OP_CALL
3778 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3780 g_stack_fsz += ops[i].operand[1].val;
3781 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3783 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3790 for (; i < opcnt; i++)
3791 if (ops[i].flags & OPF_TAIL)
3794 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3795 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3801 sandard_epilogue = 0;
3802 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
3804 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3805 // the standard epilogue is sometimes even used without a sf
3806 if (ops[j - 1].op == OP_MOV
3807 && IS(opr_name(&ops[j - 1], 0), "esp")
3808 && IS(opr_name(&ops[j - 1], 1), "ebp"))
3809 sandard_epilogue = 1;
3811 else if (ops[j].op == OP_LEAVE)
3813 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3814 sandard_epilogue = 1;
3816 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
3817 && ops[i].pp->is_noreturn)
3819 // on noreturn, msvc sometimes cleans stack, sometimes not
3824 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3825 ferr(&ops[j], "'pop ebp' expected\n");
3827 if (g_stack_fsz != 0 || sandard_epilogue) {
3828 if (ops[j].op == OP_LEAVE)
3830 else if (sandard_epilogue) // mov esp, ebp
3832 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3835 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3837 ferr(&ops[j], "esp restore expected\n");
3840 if (ecx_push && j >= 0 && ops[j].op == OP_POP
3841 && IS(opr_name(&ops[j], 0), "ecx"))
3843 ferr(&ops[j], "unexpected ecx pop\n");
3848 if (ops[j].op == OP_POPA)
3849 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3851 ferr(&ops[j], "popa expected\n");
3856 } while (i < opcnt);
3859 ferr(ops, "missing ebp epilogue\n");
3865 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3866 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3872 for (; i < opcnt; i++) {
3873 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
3875 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
3876 && ops[i].operand[1].type == OPT_CONST)
3878 g_stack_fsz = ops[i].operand[1].val;
3879 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3884 else if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3885 && ops[i].operand[1].type == OPT_CONST
3886 && ops[i + 1].op == OP_CALL
3887 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3889 g_stack_fsz += ops[i].operand[1].val;
3890 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3892 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3899 if (ecx_push && !esp_sub) {
3900 // could actually be args for a call..
3901 for (; i < opcnt; i++)
3902 if (ops[i].op != OP_PUSH)
3905 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
3906 const struct parsed_proto *pp;
3907 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
3908 j = pp ? pp->argc_stack : 0;
3909 while (i > 0 && j > 0) {
3911 if (ops[i].op == OP_PUSH) {
3912 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
3917 ferr(&ops[i], "unhandled prologue\n");
3920 i = g_stack_fsz = ecx_push = 0;
3921 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3922 if (!(ops[i].flags & OPF_RMD))
3932 if (ecx_push || esp_sub)
3937 for (; i < opcnt; i++)
3938 if (ops[i].flags & OPF_TAIL)
3942 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3943 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3950 for (l = 0; l < ecx_push; l++) {
3951 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
3953 else if (ops[j].op == OP_ADD
3954 && IS(opr_name(&ops[j], 0), "esp")
3955 && ops[j].operand[1].type == OPT_CONST)
3958 l += ops[j].operand[1].val / 4 - 1;
3961 ferr(&ops[j], "'pop ecx' expected\n");
3963 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3967 ferr(&ops[j], "epilogue scan failed\n");
3973 if (ops[j].op != OP_ADD
3974 || !IS(opr_name(&ops[j], 0), "esp")
3975 || ops[j].operand[1].type != OPT_CONST
3976 || ops[j].operand[1].val != g_stack_fsz)
3978 if (ops[i].op == OP_CALL && ops[i].pp != NULL
3979 && ops[i].pp->is_noreturn)
3981 // noreturn tailcall with no epilogue
3985 ferr(&ops[j], "'add esp' expected\n");
3988 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3989 ops[j].operand[1].val = 0; // hack for stack arg scanner
3994 } while (i < opcnt);
3997 ferr(ops, "missing esp epilogue\n");
4001 // find an instruction that changed opr before i op
4002 // *op_i must be set to -1 by the caller
4003 // *is_caller is set to 1 if one source is determined to be g_func arg
4004 // returns 1 if found, *op_i is then set to origin
4005 // returns -1 if multiple origins are found
4006 static int resolve_origin(int i, const struct parsed_opr *opr,
4007 int magic, int *op_i, int *is_caller)
4009 struct label_ref *lr;
4012 if (ops[i].cc_scratch == magic)
4014 ops[i].cc_scratch = magic;
4017 if (g_labels[i] != NULL) {
4018 lr = &g_label_refs[i];
4019 for (; lr != NULL; lr = lr->next) {
4020 check_i(&ops[i], lr->i);
4021 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4023 if (i > 0 && LAST_OP(i - 1))
4029 if (is_caller != NULL)
4034 if (ops[i].cc_scratch == magic)
4036 ops[i].cc_scratch = magic;
4038 if (!(ops[i].flags & OPF_DATA))
4040 if (!is_opr_modified(opr, &ops[i]))
4047 // XXX: could check if the other op does the same
4056 // find an instruction that previously referenced opr
4057 // if multiple results are found - fail
4058 // *op_i must be set to -1 by the caller
4059 // returns 1 if found, *op_i is then set to referencer insn
4060 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4061 int magic, int *op_i)
4063 struct label_ref *lr;
4066 if (ops[i].cc_scratch == magic)
4068 ops[i].cc_scratch = magic;
4071 if (g_labels[i] != NULL) {
4072 lr = &g_label_refs[i];
4073 for (; lr != NULL; lr = lr->next) {
4074 check_i(&ops[i], lr->i);
4075 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4077 if (i > 0 && LAST_OP(i - 1))
4085 if (ops[i].cc_scratch == magic)
4087 ops[i].cc_scratch = magic;
4089 if (!is_opr_referenced(opr, &ops[i]))
4100 // adjust datap of all reachable 'op' insns when moving back
4101 // returns 1 if at least 1 op was found
4102 // returns -1 if path without an op was found
4103 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4105 struct label_ref *lr;
4108 if (ops[i].cc_scratch == magic)
4110 ops[i].cc_scratch = magic;
4113 if (g_labels[i] != NULL) {
4114 lr = &g_label_refs[i];
4115 for (; lr != NULL; lr = lr->next) {
4116 check_i(&ops[i], lr->i);
4117 ret |= adjust_prev_op(lr->i, op, magic, datap);
4119 if (i > 0 && LAST_OP(i - 1))
4127 if (ops[i].cc_scratch == magic)
4129 ops[i].cc_scratch = magic;
4131 if (ops[i].op != op)
4134 ops[i].datap = datap;
4139 // find next instruction that reads opr
4140 // *op_i must be set to -1 by the caller
4141 // on return, *op_i is set to first referencer insn
4142 // returns 1 if exactly 1 referencer is found
4143 static int find_next_read(int i, int opcnt,
4144 const struct parsed_opr *opr, int magic, int *op_i)
4146 struct parsed_op *po;
4149 for (; i < opcnt; i++)
4151 if (ops[i].cc_scratch == magic)
4153 ops[i].cc_scratch = magic;
4156 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4157 if (po->btj != NULL) {
4159 for (j = 0; j < po->btj->count; j++) {
4160 check_i(po, po->btj->d[j].bt_i);
4161 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4167 if (po->flags & OPF_RMD)
4169 check_i(po, po->bt_i);
4170 if (po->flags & OPF_CJMP) {
4171 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4180 if (!is_opr_read(opr, po)) {
4182 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4183 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4185 full_opr = po->operand[0].lmod >= opr->lmod;
4187 if (is_opr_modified(opr, po) && full_opr) {
4191 if (po->flags & OPF_TAIL)
4206 // find next instruction that reads opr
4207 // *op_i must be set to -1 by the caller
4208 // on return, *op_i is set to first flag user insn
4209 // returns 1 if exactly 1 flag user is found
4210 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4212 struct parsed_op *po;
4215 for (; i < opcnt; i++)
4217 if (ops[i].cc_scratch == magic)
4219 ops[i].cc_scratch = magic;
4222 if (po->op == OP_CALL)
4224 if (po->flags & OPF_JMP) {
4225 if (po->btj != NULL) {
4227 for (j = 0; j < po->btj->count; j++) {
4228 check_i(po, po->btj->d[j].bt_i);
4229 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4235 if (po->flags & OPF_RMD)
4237 check_i(po, po->bt_i);
4238 if (po->flags & OPF_CJMP)
4245 if (!(po->flags & OPF_CC)) {
4246 if (po->flags & OPF_FLAGS)
4249 if (po->flags & OPF_TAIL)
4265 static int try_resolve_const(int i, const struct parsed_opr *opr,
4266 int magic, unsigned int *val)
4271 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4274 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4277 *val = ops[i].operand[1].val;
4284 static int resolve_used_bits(int i, int opcnt, int reg,
4285 int *mask, int *is_z_check)
4287 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4291 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4295 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4297 fnote(&ops[j], "(first read)\n");
4298 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4301 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4302 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4304 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4305 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4307 *mask = ops[j].operand[1].val;
4308 if (ops[j].operand[0].lmod == OPLM_BYTE
4309 && ops[j].operand[0].name[1] == 'h')
4313 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4316 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4318 *is_z_check = ops[k].pfo == PFO_Z;
4323 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4324 int *pp_i, int *multi_src)
4326 const struct parsed_proto *pp = NULL;
4327 int search_advice = 0;
4337 switch (ops[i].operand[0].type) {
4339 // try to resolve struct member calls
4340 ret = sscanf(ops[i].operand[0].name, "%3s+%x%n",
4341 s_reg, &offset, &len);
4342 if (ret == 2 && len == strlen(ops[i].operand[0].name))
4344 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4346 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, reg);
4348 ret = resolve_origin(i, &opr, i + opcnt * 19, &j, NULL);
4351 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4352 && ops[j].operand[0].lmod == OPLM_DWORD
4353 && ops[j].pp == NULL) // no hint
4355 // allow one simple dereference (directx)
4356 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4357 ops[j].operand[1].name);
4360 struct parsed_opr opr2 = OPR_INIT(OPT_REG, OPLM_DWORD, reg);
4362 ret = resolve_origin(j, &opr2, j + opcnt * 19, &k, NULL);
4367 if (ops[j].op != OP_MOV)
4369 if (ops[j].operand[0].lmod != OPLM_DWORD)
4371 if (ops[j].pp != NULL) {
4375 else if (ops[j].operand[1].type == OPT_REGMEM) {
4376 // allow 'hello[ecx]' - assume array of same type items
4377 ret = sscanf(ops[j].operand[1].name, "%[^[][e%2s]",
4381 pp = proto_parse(g_fhdr, name, g_quiet_pp);
4383 else if (ops[j].operand[1].type == OPT_LABEL)
4384 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4389 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4393 pp = proto_lookup_struct(g_fhdr, pp->type.name, offset);
4400 pp = try_recover_pp(&ops[i], &ops[i].operand[0], &search_advice);
4405 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4413 static struct parsed_proto *process_call_early(int i, int opcnt,
4416 struct parsed_op *po = &ops[i];
4417 struct parsed_proto *pp;
4423 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4427 // look for and make use of esp adjust
4429 if (!pp->is_stdcall && pp->argc_stack > 0)
4430 ret = scan_for_esp_adjust(i + 1, opcnt,
4431 pp->argc_stack * 4, &adj, &multipath, 0);
4433 if (pp->argc_stack > adj / 4)
4437 if (ops[ret].op == OP_POP) {
4438 for (j = 1; j < adj / 4; j++) {
4439 if (ops[ret + j].op != OP_POP
4440 || ops[ret + j].operand[0].reg != xCX)
4452 static struct parsed_proto *process_call(int i, int opcnt)
4454 struct parsed_op *po = &ops[i];
4455 const struct parsed_proto *pp_c;
4456 struct parsed_proto *pp;
4457 const char *tmpname;
4458 int call_i = -1, ref_i = -1;
4459 int adj = 0, multipath = 0;
4462 tmpname = opr_name(po, 0);
4467 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4469 if (!pp_c->is_func && !pp_c->is_fptr)
4470 ferr(po, "call to non-func: %s\n", pp_c->name);
4471 pp = proto_clone(pp_c);
4472 my_assert_not(pp, NULL);
4474 // not resolved just to single func
4477 switch (po->operand[0].type) {
4479 // we resolved this call and no longer need the register
4480 po->regmask_src &= ~(1 << po->operand[0].reg);
4482 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4483 && ops[call_i].operand[1].type == OPT_LABEL)
4485 // no other source users?
4486 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4488 if (ret == 1 && call_i == ref_i) {
4489 // and nothing uses it after us?
4491 find_next_read(i + 1, opcnt, &po->operand[0],
4492 i + opcnt * 11, &ref_i);
4494 // then also don't need the source mov
4495 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4507 pp = calloc(1, sizeof(*pp));
4508 my_assert_not(pp, NULL);
4511 ret = scan_for_esp_adjust(i + 1, opcnt,
4512 -1, &adj, &multipath, 0);
4513 if (ret < 0 || adj < 0) {
4514 if (!g_allow_regfunc)
4515 ferr(po, "non-__cdecl indirect call unhandled yet\n");
4516 pp->is_unresolved = 1;
4520 if (adj > ARRAY_SIZE(pp->arg))
4521 ferr(po, "esp adjust too large: %d\n", adj);
4522 pp->ret_type.name = strdup("int");
4523 pp->argc = pp->argc_stack = adj;
4524 for (arg = 0; arg < pp->argc; arg++)
4525 pp->arg[arg].type.name = strdup("int");
4530 // look for and make use of esp adjust
4533 if (!pp->is_stdcall && pp->argc_stack > 0) {
4534 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
4535 ret = scan_for_esp_adjust(i + 1, opcnt,
4536 adj_expect, &adj, &multipath, 0);
4539 if (pp->is_vararg) {
4540 if (adj / 4 < pp->argc_stack) {
4541 fnote(po, "(this call)\n");
4542 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
4543 adj, pp->argc_stack * 4);
4545 // modify pp to make it have varargs as normal args
4547 pp->argc += adj / 4 - pp->argc_stack;
4548 for (; arg < pp->argc; arg++) {
4549 pp->arg[arg].type.name = strdup("int");
4552 if (pp->argc > ARRAY_SIZE(pp->arg))
4553 ferr(po, "too many args for '%s'\n", tmpname);
4555 if (pp->argc_stack > adj / 4) {
4556 fnote(po, "(this call)\n");
4557 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
4558 tmpname, pp->argc_stack * 4, adj);
4561 scan_for_esp_adjust(i + 1, opcnt,
4562 pp->argc_stack * 4, &adj, &multipath, 1);
4564 else if (pp->is_vararg)
4565 ferr(po, "missing esp_adjust for vararg func '%s'\n",
4571 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
4574 struct parsed_op *po;
4580 for (base_arg = 0; base_arg < pp->argc; base_arg++)
4581 if (pp->arg[base_arg].reg == NULL)
4584 for (j = i; j > 0; )
4586 ferr_assert(&ops[j], g_labels[j] == NULL);
4590 ferr_assert(po, po->op != OP_PUSH);
4591 if (po->op == OP_FST)
4593 if (po->operand[0].type != OPT_REGMEM)
4595 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
4598 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3))
4599 ferr(po, "bad offset %d (%d args)\n", offset, pp->argc_stack);
4601 arg = base_arg + offset / 4;
4603 po->p_argnum = arg + 1;
4604 ferr_assert(po, pp->arg[arg].datap == NULL);
4605 pp->arg[arg].datap = po;
4606 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
4607 if (regmask_ffca != NULL)
4608 *regmask_ffca |= 1 << arg;
4610 else if (po->op == OP_SUB && po->operand[0].reg == xSP
4611 && po->operand[1].type == OPT_CONST)
4613 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4618 for (arg = base_arg; arg < pp->argc; arg++) {
4619 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
4620 po = pp->arg[arg].datap;
4622 ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
4623 if (po->operand[0].lmod == OPLM_QWORD)
4630 static int collect_call_args_early(int i, struct parsed_proto *pp,
4631 int *regmask, int *regmask_ffca)
4633 struct parsed_op *po;
4637 for (arg = 0; arg < pp->argc; arg++)
4638 if (pp->arg[arg].reg == NULL)
4641 // first see if it can be easily done
4642 for (j = i; j > 0 && arg < pp->argc; )
4644 if (g_labels[j] != NULL)
4649 if (po->op == OP_CALL)
4651 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
4653 else if (po->op == OP_POP)
4655 else if (po->flags & OPF_CJMP)
4657 else if (po->op == OP_PUSH) {
4658 if (po->flags & (OPF_FARG|OPF_FARGNR))
4660 if (!g_header_mode) {
4661 ret = scan_for_mod(po, j + 1, i, 1);
4666 if (pp->arg[arg].type.is_va_list)
4670 for (arg++; arg < pp->argc; arg++)
4671 if (pp->arg[arg].reg == NULL)
4674 else if (po->op == OP_SUB && po->operand[0].reg == xSP
4675 && po->operand[1].type == OPT_CONST)
4677 if (po->flags & (OPF_RMD|OPF_DONE))
4679 if (po->operand[1].val != pp->argc_stack * 4)
4680 ferr(po, "unexpected esp adjust: %d\n",
4681 po->operand[1].val * 4);
4682 ferr_assert(po, pp->argc - arg == pp->argc_stack);
4683 return collect_call_args_no_push(i, pp, regmask_ffca);
4691 for (arg = 0; arg < pp->argc; arg++)
4692 if (pp->arg[arg].reg == NULL)
4695 for (j = i; j > 0 && arg < pp->argc; )
4699 if (ops[j].op == OP_PUSH)
4701 ops[j].p_argnext = -1;
4702 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
4703 pp->arg[arg].datap = &ops[j];
4705 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
4706 *regmask |= 1 << ops[j].operand[0].reg;
4708 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4709 ops[j].flags &= ~OPF_RSAVE;
4712 for (arg++; arg < pp->argc; arg++)
4713 if (pp->arg[arg].reg == NULL)
4721 static int collect_call_args_r(struct parsed_op *po, int i,
4722 struct parsed_proto *pp, int *regmask, int *save_arg_vars,
4723 int *arg_grp, int arg, int magic, int need_op_saving, int may_reuse)
4725 struct parsed_proto *pp_tmp;
4726 struct parsed_op *po_tmp;
4727 struct label_ref *lr;
4728 int need_to_save_current;
4729 int arg_grp_current = 0;
4730 int save_args_seen = 0;
4738 ferr(po, "dead label encountered\n");
4742 for (; arg < pp->argc; arg++)
4743 if (pp->arg[arg].reg == NULL)
4745 magic = (magic & 0xffffff) | (arg << 24);
4747 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
4749 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
4750 if (ops[j].cc_scratch != magic) {
4751 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
4755 // ok: have already been here
4758 ops[j].cc_scratch = magic;
4760 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
4761 lr = &g_label_refs[j];
4762 if (lr->next != NULL)
4764 for (; lr->next; lr = lr->next) {
4765 check_i(&ops[j], lr->i);
4766 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4768 ret = collect_call_args_r(po, lr->i, pp, regmask, save_arg_vars,
4769 arg_grp, arg, magic, need_op_saving, may_reuse);
4774 check_i(&ops[j], lr->i);
4775 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4777 if (j > 0 && LAST_OP(j - 1)) {
4778 // follow last branch in reverse
4783 ret = collect_call_args_r(po, lr->i, pp, regmask, save_arg_vars,
4784 arg_grp, arg, magic, need_op_saving, may_reuse);
4790 if (ops[j].op == OP_CALL)
4792 if (pp->is_unresolved)
4797 ferr(po, "arg collect hit unparsed call '%s'\n",
4798 ops[j].operand[0].name);
4799 if (may_reuse && pp_tmp->argc_stack > 0)
4800 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
4801 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
4803 // esp adjust of 0 means we collected it before
4804 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
4805 && (ops[j].operand[1].type != OPT_CONST
4806 || ops[j].operand[1].val != 0))
4808 if (pp->is_unresolved)
4811 fnote(po, "(this call)\n");
4812 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
4813 arg, pp->argc, ops[j].operand[1].val);
4815 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
4817 if (pp->is_unresolved)
4820 fnote(po, "(this call)\n");
4821 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
4823 else if (ops[j].flags & OPF_CJMP)
4825 if (pp->is_unresolved)
4830 else if (ops[j].op == OP_PUSH
4831 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
4833 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
4836 ops[j].p_argnext = -1;
4837 po_tmp = pp->arg[arg].datap;
4839 ops[j].p_argnext = po_tmp - ops;
4840 pp->arg[arg].datap = &ops[j];
4842 need_to_save_current = 0;
4845 if (ops[j].operand[0].type == OPT_REG)
4846 reg = ops[j].operand[0].reg;
4848 if (!need_op_saving) {
4849 ret = scan_for_mod(&ops[j], j + 1, i, 1);
4850 need_to_save_current = (ret >= 0);
4852 if (need_op_saving || need_to_save_current) {
4853 // mark this push as one that needs operand saving
4854 ops[j].flags &= ~OPF_RMD;
4855 if (ops[j].p_argnum == 0) {
4856 ops[j].p_argnum = arg + 1;
4857 save_args |= 1 << arg;
4859 else if (ops[j].p_argnum < arg + 1) {
4860 // XXX: might kill valid var..
4861 //*save_arg_vars &= ~(1 << (ops[j].p_argnum - 1));
4862 ops[j].p_argnum = arg + 1;
4863 save_args |= 1 << arg;
4866 if (save_args_seen & (1 << (ops[j].p_argnum - 1))) {
4869 if (arg_grp_current >= MAX_ARG_GRP)
4870 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
4871 ops[j].p_argnum, pp->name);
4874 else if (ops[j].p_argnum == 0)
4875 ops[j].flags |= OPF_RMD;
4877 // some PUSHes are reused by different calls on other branches,
4878 // but that can't happen if we didn't branch, so they
4879 // can be removed from future searches (handles nested calls)
4881 ops[j].flags |= OPF_FARGNR;
4883 ops[j].flags |= OPF_FARG;
4884 ops[j].flags &= ~OPF_RSAVE;
4886 // check for __VALIST
4887 if (!pp->is_unresolved && g_func_pp != NULL
4888 && pp->arg[arg].type.is_va_list)
4891 ret = resolve_origin(j, &ops[j].operand[0],
4892 magic + 1, &k, NULL);
4893 if (ret == 1 && k >= 0)
4895 if (ops[k].op == OP_LEA) {
4896 if (!g_func_pp->is_vararg)
4897 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
4900 snprintf(buf, sizeof(buf), "arg_%X",
4901 g_func_pp->argc_stack * 4);
4902 if (strstr(ops[k].operand[1].name, buf)
4903 || strstr(ops[k].operand[1].name, "arglist"))
4905 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
4906 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
4907 save_args &= ~(1 << arg);
4911 ferr(&ops[k], "va_list arg detection failed\n");
4913 // check for va_list from g_func_pp arg too
4914 else if (ops[k].op == OP_MOV
4915 && is_stack_access(&ops[k], &ops[k].operand[1]))
4917 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
4918 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
4920 ops[k].flags |= OPF_RMD | OPF_DONE;
4921 ops[j].flags |= OPF_RMD;
4922 ops[j].p_argpass = ret + 1;
4923 save_args &= ~(1 << arg);
4930 *save_arg_vars |= save_args;
4932 // tracking reg usage
4934 *regmask |= 1 << reg;
4937 if (!pp->is_unresolved) {
4939 for (; arg < pp->argc; arg++)
4940 if (pp->arg[arg].reg == NULL)
4943 magic = (magic & 0xffffff) | (arg << 24);
4946 if (ops[j].p_arggrp > arg_grp_current) {
4948 arg_grp_current = ops[j].p_arggrp;
4950 if (ops[j].p_argnum > 0)
4951 save_args_seen |= 1 << (ops[j].p_argnum - 1);
4954 if (arg < pp->argc) {
4955 ferr(po, "arg collect failed for '%s': %d/%d\n",
4956 pp->name, arg, pp->argc);
4960 if (arg_grp_current > *arg_grp)
4961 *arg_grp = arg_grp_current;
4966 static int collect_call_args(struct parsed_op *po, int i,
4967 struct parsed_proto *pp, int *regmask, int *save_arg_vars,
4970 // arg group is for cases when pushes for
4971 // multiple funcs are going on
4972 struct parsed_op *po_tmp;
4973 int save_arg_vars_current = 0;
4978 ret = collect_call_args_r(po, i, pp, regmask,
4979 &save_arg_vars_current, &arg_grp, 0, magic, 0, 0);
4984 // propagate arg_grp
4985 for (a = 0; a < pp->argc; a++) {
4986 if (pp->arg[a].reg != NULL)
4989 po_tmp = pp->arg[a].datap;
4990 while (po_tmp != NULL) {
4991 po_tmp->p_arggrp = arg_grp;
4992 if (po_tmp->p_argnext > 0)
4993 po_tmp = &ops[po_tmp->p_argnext];
4999 save_arg_vars[arg_grp] |= save_arg_vars_current;
5001 if (pp->is_unresolved) {
5003 pp->argc_stack += ret;
5004 for (a = 0; a < pp->argc; a++)
5005 if (pp->arg[a].type.name == NULL)
5006 pp->arg[a].type.name = strdup("int");
5012 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5013 int regmask_now, int *regmask,
5014 int regmask_save_now, int *regmask_save,
5015 int *regmask_init, int regmask_arg)
5017 struct parsed_op *po;
5025 for (; i < opcnt; i++)
5028 if (cbits[i >> 3] & (1 << (i & 7)))
5030 cbits[i >> 3] |= (1 << (i & 7));
5032 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5033 if (po->flags & (OPF_RMD|OPF_DONE))
5035 if (po->btj != NULL) {
5036 for (j = 0; j < po->btj->count; j++) {
5037 check_i(po, po->btj->d[j].bt_i);
5038 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5039 regmask_now, regmask, regmask_save_now, regmask_save,
5040 regmask_init, regmask_arg);
5045 check_i(po, po->bt_i);
5046 if (po->flags & OPF_CJMP)
5047 reg_use_pass(po->bt_i, opcnt, cbits,
5048 regmask_now, regmask, regmask_save_now, regmask_save,
5049 regmask_init, regmask_arg);
5055 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5056 && !g_func_pp->is_userstack
5057 && po->operand[0].type == OPT_REG)
5059 reg = po->operand[0].reg;
5060 ferr_assert(po, reg >= 0);
5063 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5064 if (regmask_now & (1 << reg)) {
5065 already_saved = regmask_save_now & (1 << reg);
5066 flags_set = OPF_RSAVE | OPF_DONE;
5069 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0);
5071 scan_for_pop(i + 1, opcnt, i + opcnt * 4, reg, 0, flags_set);
5074 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5076 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5081 ferr_assert(po, !already_saved);
5082 po->flags |= flags_set;
5084 if (regmask_now & (1 << reg)) {
5085 regmask_save_now |= (1 << reg);
5086 *regmask_save |= regmask_save_now;
5091 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5092 reg = po->operand[0].reg;
5093 ferr_assert(po, reg >= 0);
5095 if (regmask_save_now & (1 << reg))
5096 regmask_save_now &= ~(1 << reg);
5098 regmask_now &= ~(1 << reg);
5101 else if (po->op == OP_CALL) {
5102 if ((po->regmask_dst & (1 << xAX))
5103 && !(po->regmask_dst & (1 << xDX)))
5105 if (po->flags & OPF_TAIL)
5106 // don't need eax, will do "return f();" or "f(); return;"
5107 po->regmask_dst &= ~(1 << xAX);
5109 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
5111 find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
5114 po->regmask_dst &= ~(1 << xAX);
5118 // not "full stack" mode and have something in stack
5119 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5120 ferr(po, "float stack is not empty on func call\n");
5123 if (po->flags & OPF_NOREGS)
5126 // if incomplete register is used, clear it on init to avoid
5127 // later use of uninitialized upper part in some situations
5128 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5129 && po->operand[0].lmod != OPLM_DWORD)
5131 reg = po->operand[0].reg;
5132 ferr_assert(po, reg >= 0);
5134 if (!(regmask_now & (1 << reg)))
5135 *regmask_init |= 1 << reg;
5138 regmask_op = po->regmask_src | po->regmask_dst;
5140 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5141 regmask_new &= ~(1 << xSP);
5142 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5143 regmask_new &= ~(1 << xBP);
5145 if (regmask_new != 0)
5146 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5148 if (regmask_op & (1 << xBP)) {
5149 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5150 if (po->regmask_dst & (1 << xBP))
5151 // compiler decided to drop bp frame and use ebp as scratch
5152 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5154 regmask_op &= ~(1 << xBP);
5158 if (po->flags & OPF_FPUSH) {
5159 if (regmask_now & mxST1)
5160 regmask_now |= mxSTa; // switch to "full stack" mode
5161 if (regmask_now & mxSTa)
5162 po->flags |= OPF_FSHIFT;
5163 if (!(regmask_now & mxST7_2)) {
5165 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5169 regmask_now |= regmask_op;
5170 *regmask |= regmask_now;
5173 if (po->flags & OPF_FPOP) {
5174 if ((regmask_now & mxSTa) == 0)
5175 ferr(po, "float pop on empty stack?\n");
5176 if (regmask_now & (mxST7_2 | mxST1))
5177 po->flags |= OPF_FSHIFT;
5178 if (!(regmask_now & mxST7_2)) {
5180 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5184 if (po->flags & OPF_TAIL) {
5185 if (!(regmask_now & mxST7_2)) {
5186 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5187 if (!(regmask_now & mxST0))
5188 ferr(po, "no st0 on float return, mask: %x\n",
5191 else if (regmask_now & mxST1_0)
5192 ferr(po, "float regs on tail: %x\n", regmask_now);
5195 // there is support for "conditional tailcall", sort of
5196 if (!(po->flags & OPF_CC))
5202 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5206 for (i = 0; i < pp->argc; i++)
5207 if (pp->arg[i].reg == NULL)
5211 memmove(&pp->arg[i + 1], &pp->arg[i],
5212 sizeof(pp->arg[0]) * pp->argc_stack);
5213 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5214 pp->arg[i].reg = strdup(reg);
5215 pp->arg[i].type.name = strdup("int");
5220 static void output_std_flags(FILE *fout, struct parsed_op *po,
5221 int *pfomask, const char *dst_opr_text)
5223 if (*pfomask & (1 << PFO_Z)) {
5224 fprintf(fout, "\n cond_z = (%s%s == 0);",
5225 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5226 *pfomask &= ~(1 << PFO_Z);
5228 if (*pfomask & (1 << PFO_S)) {
5229 fprintf(fout, "\n cond_s = (%s%s < 0);",
5230 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5231 *pfomask &= ~(1 << PFO_S);
5236 OPP_FORCE_NORETURN = (1 << 0),
5237 OPP_SIMPLE_ARGS = (1 << 1),
5238 OPP_ALIGN = (1 << 2),
5241 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
5244 const char *cconv = "";
5246 if (pp->is_fastcall)
5247 cconv = "__fastcall ";
5248 else if (pp->is_stdcall && pp->argc_reg == 0)
5249 cconv = "__stdcall ";
5251 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5253 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
5254 fprintf(fout, "noreturn ");
5257 static void output_pp(FILE *fout, const struct parsed_proto *pp,
5262 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5266 output_pp_attrs(fout, pp, flags);
5269 fprintf(fout, "%s", pp->name);
5274 for (i = 0; i < pp->argc; i++) {
5276 fprintf(fout, ", ");
5277 if (pp->arg[i].fptr != NULL && !(flags & OPP_SIMPLE_ARGS)) {
5279 output_pp(fout, pp->arg[i].fptr, 0);
5281 else if (pp->arg[i].type.is_retreg) {
5282 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
5285 fprintf(fout, "%s", pp->arg[i].type.name);
5287 fprintf(fout, " a%d", i + 1);
5290 if (pp->is_vararg) {
5292 fprintf(fout, ", ");
5293 fprintf(fout, "...");
5298 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
5304 snprintf(buf1, sizeof(buf1), "%d", grp);
5305 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
5310 static void gen_x_cleanup(int opcnt);
5312 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
5314 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
5315 struct parsed_opr *last_arith_dst = NULL;
5316 char buf1[256], buf2[256], buf3[256], cast[64];
5317 struct parsed_proto *pp, *pp_tmp;
5318 struct parsed_data *pd;
5320 int save_arg_vars[MAX_ARG_GRP] = { 0, };
5321 unsigned char cbits[MAX_OPS / 8];
5322 const char *float_type;
5323 const char *float_st0;
5324 const char *float_st1;
5325 int need_float_stack = 0;
5326 int need_float_sw = 0; // status word
5327 int need_tmp_var = 0;
5331 int label_pending = 0;
5332 int need_double = 0;
5333 int regmask_save = 0; // used regs saved/restored in this func
5334 int regmask_arg; // regs from this function args (fastcall, etc)
5335 int regmask_ret; // regs needed on ret
5336 int regmask_now; // temp
5337 int regmask_init = 0; // regs that need zero initialization
5338 int regmask_pp = 0; // regs used in complex push-pop graph
5339 int regmask_ffca = 0; // float function call args
5340 int regmask = 0; // used regs
5350 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
5351 g_stack_frame_used = 0;
5352 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
5353 regmask_init = g_regmask_init;
5355 g_func_pp = proto_parse(fhdr, funcn, 0);
5356 if (g_func_pp == NULL)
5357 ferr(ops, "proto_parse failed for '%s'\n", funcn);
5359 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
5360 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
5363 // - resolve all branches
5364 // - parse calls with labels
5365 resolve_branches_parse_calls(opcnt);
5368 // - handle ebp/esp frame, remove ops related to it
5369 scan_prologue_epilogue(opcnt);
5372 // - remove dead labels
5373 // - set regs needed at ret
5374 for (i = 0; i < opcnt; i++)
5376 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
5381 if (ops[i].op == OP_RET)
5382 ops[i].regmask_src |= regmask_ret;
5386 // - process trivial calls
5387 for (i = 0; i < opcnt; i++)
5390 if (po->flags & (OPF_RMD|OPF_DONE))
5393 if (po->op == OP_CALL)
5395 pp = process_call_early(i, opcnt, &j);
5397 if (!(po->flags & OPF_ATAIL)) {
5398 // since we know the args, try to collect them
5399 ret = collect_call_args_early(i, pp, ®mask, ®mask_ffca);
5407 // commit esp adjust
5408 if (ops[j].op != OP_POP)
5409 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5411 for (l = 0; l < pp->argc_stack; l++)
5412 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
5416 if (strstr(pp->ret_type.name, "int64"))
5419 po->flags |= OPF_DONE;
5425 // - process calls, stage 2
5426 // - handle some push/pop pairs
5427 // - scan for STD/CLD, propagate DF
5428 // - try to resolve needed x87 status word bits
5429 for (i = 0; i < opcnt; i++)
5434 if (po->flags & OPF_RMD)
5437 if (po->op == OP_CALL)
5439 if (!(po->flags & OPF_DONE)) {
5440 pp = process_call(i, opcnt);
5442 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
5443 // since we know the args, collect them
5444 collect_call_args(po, i, pp, ®mask, save_arg_vars,
5447 // for unresolved, collect after other passes
5451 ferr_assert(po, pp != NULL);
5453 po->regmask_src |= get_pp_arg_regmask_src(pp);
5454 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
5456 if (po->regmask_dst & mxST0)
5457 po->flags |= OPF_FPUSH;
5459 if (strstr(pp->ret_type.name, "int64"))
5465 if (po->flags & OPF_DONE)
5470 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
5471 && po->operand[0].type == OPT_CONST)
5473 scan_for_pop_const(i, opcnt, i + opcnt * 12);
5478 scan_pushes_for_pop(i, opcnt, ®mask_pp);
5482 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
5483 scan_propagate_df(i + 1, opcnt);
5488 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
5489 ferr(po, "TODO: fnstsw to mem\n");
5490 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
5492 ferr(po, "fnstsw resolve failed\n");
5493 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
5494 (void *)(long)(mask | (z_check << 16)));
5496 ferr(po, "failed to find fcom: %d\n", ret);
5505 // - find POPs for PUSHes, rm both
5506 // - scan for all used registers
5507 memset(cbits, 0, sizeof(cbits));
5508 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
5509 0, ®mask_save, ®mask_init, regmask_arg);
5512 // - find flag set ops for their users
5513 // - do unresolved calls
5514 // - declare indirect functions
5515 // - other op specific processing
5516 for (i = 0; i < opcnt; i++)
5519 if (po->flags & (OPF_RMD|OPF_DONE))
5522 if (po->flags & OPF_CC)
5524 int setters[16], cnt = 0, branched = 0;
5526 ret = scan_for_flag_set(i, i + opcnt * 6,
5527 &branched, setters, &cnt);
5528 if (ret < 0 || cnt <= 0)
5529 ferr(po, "unable to trace flag setter(s)\n");
5530 if (cnt > ARRAY_SIZE(setters))
5531 ferr(po, "too many flag setters\n");
5533 for (j = 0; j < cnt; j++)
5535 tmp_op = &ops[setters[j]]; // flag setter
5538 // to get nicer code, we try to delay test and cmp;
5539 // if we can't because of operand modification, or if we
5540 // have arith op, or branch, make it calculate flags explicitly
5541 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
5543 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
5544 pfomask = 1 << po->pfo;
5546 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
5547 pfomask = 1 << po->pfo;
5550 // see if we'll be able to handle based on op result
5551 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
5552 && po->pfo != PFO_Z && po->pfo != PFO_S
5553 && po->pfo != PFO_P)
5555 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
5557 pfomask = 1 << po->pfo;
5560 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
5561 propagate_lmod(tmp_op, &tmp_op->operand[0],
5562 &tmp_op->operand[1]);
5563 if (tmp_op->operand[0].lmod == OPLM_DWORD)
5568 tmp_op->pfomask |= pfomask;
5569 cond_vars |= pfomask;
5571 // note: may overwrite, currently not a problem
5575 if (po->op == OP_RCL || po->op == OP_RCR
5576 || po->op == OP_ADC || po->op == OP_SBB)
5577 cond_vars |= 1 << PFO_C;
5583 cond_vars |= 1 << PFO_Z;
5587 if (po->operand[0].lmod == OPLM_DWORD)
5592 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
5597 // note: resolved non-reg calls are OPF_DONE already
5599 ferr_assert(po, pp != NULL);
5601 if (pp->is_unresolved) {
5602 int regmask_stack = 0;
5603 collect_call_args(po, i, pp, ®mask, save_arg_vars,
5606 // this is pretty rough guess:
5607 // see ecx and edx were pushed (and not their saved versions)
5608 for (arg = 0; arg < pp->argc; arg++) {
5609 if (pp->arg[arg].reg != NULL)
5612 tmp_op = pp->arg[arg].datap;
5614 ferr(po, "parsed_op missing for arg%d\n", arg);
5615 if (tmp_op->p_argnum == 0 && tmp_op->operand[0].type == OPT_REG)
5616 regmask_stack |= 1 << tmp_op->operand[0].reg;
5619 if (!((regmask_stack & (1 << xCX))
5620 && (regmask_stack & (1 << xDX))))
5622 if (pp->argc_stack != 0
5623 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
5625 pp_insert_reg_arg(pp, "ecx");
5626 pp->is_fastcall = 1;
5627 regmask_init |= 1 << xCX;
5628 regmask |= 1 << xCX;
5630 if (pp->argc_stack != 0
5631 || ((regmask | regmask_arg) & (1 << xDX)))
5633 pp_insert_reg_arg(pp, "edx");
5634 regmask_init |= 1 << xDX;
5635 regmask |= 1 << xDX;
5639 // note: __cdecl doesn't fall into is_unresolved category
5640 if (pp->argc_stack > 0)
5646 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
5648 // <var> = offset <something>
5649 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
5650 && !IS_START(po->operand[1].name, "off_"))
5652 if (!po->operand[0].pp->is_fptr)
5653 ferr(po, "%s not declared as fptr when it should be\n",
5654 po->operand[0].name);
5655 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
5656 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
5657 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
5658 fnote(po, "var: %s\n", buf1);
5659 fnote(po, "func: %s\n", buf2);
5660 ferr(po, "^ mismatch\n");
5668 if (po->operand[0].lmod == OPLM_DWORD) {
5669 // 32bit division is common, look for it
5670 if (po->op == OP_DIV)
5671 ret = scan_for_reg_clear(i, xDX);
5673 ret = scan_for_cdq_edx(i);
5675 po->flags |= OPF_32BIT;
5684 po->flags |= OPF_RMD | OPF_DONE;
5694 if (po->operand[0].lmod == OPLM_QWORD)
5704 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
5706 find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
5708 po->flags |= OPF_32BIT;
5717 float_type = need_double ? "double" : "float";
5718 need_float_stack = !!(regmask & mxST7_2);
5719 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
5720 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
5722 // output starts here
5724 // define userstack size
5725 if (g_func_pp->is_userstack) {
5726 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
5727 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
5728 fprintf(fout, "#endif\n");
5731 // the function itself
5732 ferr_assert(ops, !g_func_pp->is_fptr);
5733 output_pp(fout, g_func_pp,
5734 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
5735 fprintf(fout, "\n{\n");
5737 // declare indirect functions
5738 for (i = 0; i < opcnt; i++) {
5740 if (po->flags & OPF_RMD)
5743 if (po->op == OP_CALL) {
5746 ferr(po, "NULL pp\n");
5748 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
5749 if (pp->name[0] != 0) {
5750 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
5751 memcpy(pp->name, "i_", 2);
5753 // might be declared already
5755 for (j = 0; j < i; j++) {
5756 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
5757 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
5767 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
5770 output_pp(fout, pp, OPP_SIMPLE_ARGS);
5771 fprintf(fout, ";\n");
5776 // output LUTs/jumptables
5777 for (i = 0; i < g_func_pd_cnt; i++) {
5779 fprintf(fout, " static const ");
5780 if (pd->type == OPT_OFFSET) {
5781 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
5783 for (j = 0; j < pd->count; j++) {
5785 fprintf(fout, ", ");
5786 fprintf(fout, "&&%s", pd->d[j].u.label);
5790 fprintf(fout, "%s %s[] =\n { ",
5791 lmod_type_u(ops, pd->lmod), pd->label);
5793 for (j = 0; j < pd->count; j++) {
5795 fprintf(fout, ", ");
5796 fprintf(fout, "%u", pd->d[j].u.val);
5799 fprintf(fout, " };\n");
5803 // declare stack frame, va_arg
5805 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
5806 if (g_func_lmods & (1 << OPLM_WORD))
5807 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
5808 if (g_func_lmods & (1 << OPLM_BYTE))
5809 fprintf(fout, " u8 b[%d];", g_stack_fsz);
5810 if (g_func_lmods & (1 << OPLM_QWORD))
5811 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
5812 fprintf(fout, " } sf;\n");
5816 if (g_func_pp->is_userstack) {
5817 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
5818 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
5822 if (g_func_pp->is_vararg) {
5823 fprintf(fout, " va_list ap;\n");
5827 // declare arg-registers
5828 for (i = 0; i < g_func_pp->argc; i++) {
5829 if (g_func_pp->arg[i].reg != NULL) {
5830 reg = char_array_i(regs_r32,
5831 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
5832 if (regmask & (1 << reg)) {
5833 if (g_func_pp->arg[i].type.is_retreg)
5834 fprintf(fout, " u32 %s = *r_%s;\n",
5835 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
5837 fprintf(fout, " u32 %s = (u32)a%d;\n",
5838 g_func_pp->arg[i].reg, i + 1);
5841 if (g_func_pp->arg[i].type.is_retreg)
5842 ferr(ops, "retreg '%s' is unused?\n",
5843 g_func_pp->arg[i].reg);
5844 fprintf(fout, " // %s = a%d; // unused\n",
5845 g_func_pp->arg[i].reg, i + 1);
5851 // declare normal registers
5852 regmask_now = regmask & ~regmask_arg;
5853 regmask_now &= ~(1 << xSP);
5854 if (regmask_now & 0x00ff) {
5855 for (reg = 0; reg < 8; reg++) {
5856 if (regmask_now & (1 << reg)) {
5857 fprintf(fout, " u32 %s", regs_r32[reg]);
5858 if (regmask_init & (1 << reg))
5859 fprintf(fout, " = 0");
5860 fprintf(fout, ";\n");
5866 if (regmask_now & 0xff00) {
5867 for (reg = 8; reg < 16; reg++) {
5868 if (regmask_now & (1 << reg)) {
5869 fprintf(fout, " mmxr %s", regs_r32[reg]);
5870 if (regmask_init & (1 << reg))
5871 fprintf(fout, " = { 0, }");
5872 fprintf(fout, ";\n");
5878 if (need_float_stack) {
5879 fprintf(fout, " %s f_st[8];\n", float_type);
5880 fprintf(fout, " int f_stp = 0;\n");
5884 if (regmask_now & 0xff0000) {
5885 for (reg = 16; reg < 24; reg++) {
5886 if (regmask_now & (1 << reg)) {
5887 fprintf(fout, " %s f_st%d", float_type, reg - 16);
5888 if (regmask_init & (1 << reg))
5889 fprintf(fout, " = 0");
5890 fprintf(fout, ";\n");
5897 if (need_float_sw) {
5898 fprintf(fout, " u16 f_sw;\n");
5903 for (reg = 0; reg < 8; reg++) {
5904 if (regmask_save & (1 << reg)) {
5905 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
5911 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
5912 if (save_arg_vars[i] == 0)
5914 for (reg = 0; reg < 32; reg++) {
5915 if (save_arg_vars[i] & (1 << reg)) {
5916 fprintf(fout, " u32 %s;\n",
5917 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
5924 for (reg = 0; reg < 32; reg++) {
5925 if (regmask_ffca & (1 << reg)) {
5926 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
5932 // declare push-pop temporaries
5934 for (reg = 0; reg < 8; reg++) {
5935 if (regmask_pp & (1 << reg)) {
5936 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
5943 for (i = 0; i < 8; i++) {
5944 if (cond_vars & (1 << i)) {
5945 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
5952 fprintf(fout, " u32 tmp;\n");
5957 fprintf(fout, " u64 tmp64;\n");
5962 fprintf(fout, "\n");
5964 // do stack clear, if needed
5965 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
5967 if (g_stack_clear_len != 0) {
5968 if (g_stack_clear_len <= 4) {
5969 for (i = 0; i < g_stack_clear_len; i++)
5970 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
5971 fprintf(fout, "0;\n");
5974 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
5975 g_stack_clear_start, g_stack_clear_len * 4);
5979 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
5982 if (g_func_pp->is_vararg) {
5983 if (g_func_pp->argc_stack == 0)
5984 ferr(ops, "vararg func without stack args?\n");
5985 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
5989 for (i = 0; i < opcnt; i++)
5991 if (g_labels[i] != NULL) {
5992 fprintf(fout, "\n%s:\n", g_labels[i]);
5995 delayed_flag_op = NULL;
5996 last_arith_dst = NULL;
6000 if (po->flags & OPF_RMD)
6005 #define assert_operand_cnt(n_) \
6006 if (po->operand_cnt != n_) \
6007 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6009 // conditional/flag using op?
6010 if (po->flags & OPF_CC)
6016 // we go through all this trouble to avoid using parsed_flag_op,
6017 // which makes generated code much nicer
6018 if (delayed_flag_op != NULL)
6020 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6021 po->pfo, po->pfo_inv);
6024 else if (last_arith_dst != NULL
6025 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6026 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6029 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6030 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6031 last_arith_dst->lmod, buf3);
6034 else if (tmp_op != NULL) {
6035 // use preprocessed flag calc results
6036 if (!(tmp_op->pfomask & (1 << po->pfo)))
6037 ferr(po, "not prepared for pfo %d\n", po->pfo);
6039 // note: pfo_inv was not yet applied
6040 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6041 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6044 ferr(po, "all methods of finding comparison failed\n");
6047 if (po->flags & OPF_JMP) {
6048 fprintf(fout, " if %s", buf1);
6050 else if (po->op == OP_RCL || po->op == OP_RCR
6051 || po->op == OP_ADC || po->op == OP_SBB)
6054 fprintf(fout, " cond_%s = %s;\n",
6055 parsed_flag_op_names[po->pfo], buf1);
6057 else if (po->flags & OPF_DATA) { // SETcc
6058 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6059 fprintf(fout, " %s = %s;", buf2, buf1);
6062 ferr(po, "unhandled conditional op\n");
6066 pfomask = po->pfomask;
6068 if (po->flags & (OPF_REPZ|OPF_REPNZ)) {
6069 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
6070 ret = try_resolve_const(i, &opr, opcnt * 7 + i, &uval);
6072 if (ret != 1 || uval == 0) {
6073 // we need initial flags for ecx=0 case..
6074 if (i > 0 && ops[i - 1].op == OP_XOR
6075 && IS(ops[i - 1].operand[0].name,
6076 ops[i - 1].operand[1].name))
6078 fprintf(fout, " cond_z = ");
6079 if (pfomask & (1 << PFO_C))
6080 fprintf(fout, "cond_c = ");
6081 fprintf(fout, "0;\n");
6083 else if (last_arith_dst != NULL) {
6084 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6085 out_test_for_cc(buf1, sizeof(buf1), po, PFO_Z, 0,
6086 last_arith_dst->lmod, buf3);
6087 fprintf(fout, " cond_z = %s;\n", buf1);
6090 ferr(po, "missing initial ZF\n");
6097 assert_operand_cnt(2);
6098 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6099 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6100 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
6101 fprintf(fout, " %s = %s;", buf1,
6102 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6107 assert_operand_cnt(2);
6108 po->operand[1].lmod = OPLM_DWORD; // always
6109 fprintf(fout, " %s = %s;",
6110 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6111 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6116 assert_operand_cnt(2);
6117 fprintf(fout, " %s = %s;",
6118 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6119 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6123 assert_operand_cnt(2);
6124 switch (po->operand[1].lmod) {
6126 strcpy(buf3, "(s8)");
6129 strcpy(buf3, "(s16)");
6132 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6134 fprintf(fout, " %s = %s;",
6135 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6136 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6141 assert_operand_cnt(2);
6142 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6143 fprintf(fout, " tmp = %s;",
6144 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6145 fprintf(fout, " %s = %s;",
6146 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6147 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6148 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6149 fprintf(fout, " %s = %stmp;",
6150 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6151 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
6152 snprintf(g_comment, sizeof(g_comment), "xchg");
6156 assert_operand_cnt(1);
6157 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6158 fprintf(fout, " %s = ~%s;", buf1, buf1);
6162 assert_operand_cnt(2);
6163 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6164 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6165 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6166 strcpy(g_comment, "xlat");
6170 assert_operand_cnt(2);
6171 fprintf(fout, " %s = (s32)%s >> 31;",
6172 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6173 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6174 strcpy(g_comment, "cdq");
6178 assert_operand_cnt(1);
6179 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6180 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
6184 if (po->flags & OPF_REP) {
6185 assert_operand_cnt(3);
6190 assert_operand_cnt(2);
6191 fprintf(fout, " %s = %sesi; esi %c= %d;",
6192 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6193 lmod_cast_u_ptr(po, po->operand[1].lmod),
6194 (po->flags & OPF_DF) ? '-' : '+',
6195 lmod_bytes(po, po->operand[1].lmod));
6196 strcpy(g_comment, "lods");
6201 if (po->flags & OPF_REP) {
6202 assert_operand_cnt(3);
6203 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
6204 (po->flags & OPF_DF) ? '-' : '+',
6205 lmod_bytes(po, po->operand[1].lmod));
6206 fprintf(fout, " %sedi = eax;",
6207 lmod_cast_u_ptr(po, po->operand[1].lmod));
6208 strcpy(g_comment, "rep stos");
6211 assert_operand_cnt(2);
6212 fprintf(fout, " %sedi = eax; edi %c= %d;",
6213 lmod_cast_u_ptr(po, po->operand[1].lmod),
6214 (po->flags & OPF_DF) ? '-' : '+',
6215 lmod_bytes(po, po->operand[1].lmod));
6216 strcpy(g_comment, "stos");
6221 j = lmod_bytes(po, po->operand[0].lmod);
6222 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6223 l = (po->flags & OPF_DF) ? '-' : '+';
6224 if (po->flags & OPF_REP) {
6225 assert_operand_cnt(3);
6227 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
6230 " %sedi = %sesi;", buf1, buf1);
6231 strcpy(g_comment, "rep movs");
6234 assert_operand_cnt(2);
6235 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
6236 buf1, buf1, l, j, l, j);
6237 strcpy(g_comment, "movs");
6242 // repe ~ repeat while ZF=1
6243 j = lmod_bytes(po, po->operand[0].lmod);
6244 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6245 l = (po->flags & OPF_DF) ? '-' : '+';
6246 if (po->flags & OPF_REP) {
6247 assert_operand_cnt(3);
6249 " for (; ecx != 0; ecx--) {\n");
6250 if (pfomask & (1 << PFO_C)) {
6253 " cond_c = %sesi < %sedi;\n", buf1, buf1);
6254 pfomask &= ~(1 << PFO_C);
6257 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
6258 buf1, buf1, l, j, l, j);
6260 " if (cond_z %s 0) break;\n",
6261 (po->flags & OPF_REPZ) ? "==" : "!=");
6264 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
6265 (po->flags & OPF_REPZ) ? "e" : "ne");
6268 assert_operand_cnt(2);
6270 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
6271 buf1, buf1, l, j, l, j);
6272 strcpy(g_comment, "cmps");
6274 pfomask &= ~(1 << PFO_Z);
6275 last_arith_dst = NULL;
6276 delayed_flag_op = NULL;
6280 // only does ZF (for now)
6281 // repe ~ repeat while ZF=1
6282 j = lmod_bytes(po, po->operand[1].lmod);
6283 l = (po->flags & OPF_DF) ? '-' : '+';
6284 if (po->flags & OPF_REP) {
6285 assert_operand_cnt(3);
6287 " for (; ecx != 0; ecx--) {\n");
6289 " cond_z = (%seax == %sedi); edi %c= %d;\n",
6290 lmod_cast_u(po, po->operand[1].lmod),
6291 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6293 " if (cond_z %s 0) break;\n",
6294 (po->flags & OPF_REPZ) ? "==" : "!=");
6297 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
6298 (po->flags & OPF_REPZ) ? "e" : "ne");
6301 assert_operand_cnt(2);
6302 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
6303 lmod_cast_u(po, po->operand[1].lmod),
6304 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6305 strcpy(g_comment, "scas");
6307 pfomask &= ~(1 << PFO_Z);
6308 last_arith_dst = NULL;
6309 delayed_flag_op = NULL;
6312 // arithmetic w/flags
6314 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
6315 goto dualop_arith_const;
6316 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6320 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6321 if (po->operand[1].type == OPT_CONST) {
6322 j = lmod_bytes(po, po->operand[0].lmod);
6323 if (((1ull << j * 8) - 1) == po->operand[1].val)
6324 goto dualop_arith_const;
6329 assert_operand_cnt(2);
6330 fprintf(fout, " %s %s= %s;",
6331 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6333 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6334 output_std_flags(fout, po, &pfomask, buf1);
6335 last_arith_dst = &po->operand[0];
6336 delayed_flag_op = NULL;
6340 // and 0, or ~0 used instead mov
6341 assert_operand_cnt(2);
6342 fprintf(fout, " %s = %s;",
6343 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6344 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6345 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6346 output_std_flags(fout, po, &pfomask, buf1);
6347 last_arith_dst = &po->operand[0];
6348 delayed_flag_op = NULL;
6353 assert_operand_cnt(2);
6354 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6355 if (pfomask & (1 << PFO_C)) {
6356 if (po->operand[1].type == OPT_CONST) {
6357 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6358 j = po->operand[1].val;
6361 if (po->op == OP_SHL)
6365 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
6369 ferr(po, "zero shift?\n");
6373 pfomask &= ~(1 << PFO_C);
6375 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
6376 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6377 if (po->operand[1].type != OPT_CONST)
6378 fprintf(fout, " & 0x1f");
6380 output_std_flags(fout, po, &pfomask, buf1);
6381 last_arith_dst = &po->operand[0];
6382 delayed_flag_op = NULL;
6386 assert_operand_cnt(2);
6387 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6388 fprintf(fout, " %s = %s%s >> %s;", buf1,
6389 lmod_cast_s(po, po->operand[0].lmod), buf1,
6390 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6391 output_std_flags(fout, po, &pfomask, buf1);
6392 last_arith_dst = &po->operand[0];
6393 delayed_flag_op = NULL;
6398 assert_operand_cnt(3);
6399 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6400 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6401 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
6402 if (po->operand[2].type != OPT_CONST) {
6403 // no handling for "undefined" case, hopefully not needed
6404 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
6407 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6408 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6409 if (po->op == OP_SHLD) {
6410 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
6411 buf1, buf3, buf1, buf2, l, buf3);
6412 strcpy(g_comment, "shld");
6415 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
6416 buf1, buf3, buf1, buf2, l, buf3);
6417 strcpy(g_comment, "shrd");
6419 output_std_flags(fout, po, &pfomask, buf1);
6420 last_arith_dst = &po->operand[0];
6421 delayed_flag_op = NULL;
6426 assert_operand_cnt(2);
6427 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6428 if (po->operand[1].type == OPT_CONST) {
6429 j = po->operand[1].val;
6430 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
6431 fprintf(fout, po->op == OP_ROL ?
6432 " %s = (%s << %d) | (%s >> %d);" :
6433 " %s = (%s >> %d) | (%s << %d);",
6434 buf1, buf1, j, buf1,
6435 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
6439 output_std_flags(fout, po, &pfomask, buf1);
6440 last_arith_dst = &po->operand[0];
6441 delayed_flag_op = NULL;
6446 assert_operand_cnt(2);
6447 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6448 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6449 if (po->operand[1].type == OPT_CONST) {
6450 j = po->operand[1].val % l;
6452 ferr(po, "zero rotate\n");
6453 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
6454 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
6455 if (po->op == OP_RCL) {
6457 " %s = (%s << %d) | (cond_c << %d)",
6458 buf1, buf1, j, j - 1);
6460 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
6464 " %s = (%s >> %d) | (cond_c << %d)",
6465 buf1, buf1, j, l - j);
6467 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
6469 fprintf(fout, ";\n");
6470 fprintf(fout, " cond_c = tmp;");
6474 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
6475 output_std_flags(fout, po, &pfomask, buf1);
6476 last_arith_dst = &po->operand[0];
6477 delayed_flag_op = NULL;
6481 assert_operand_cnt(2);
6482 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6483 if (IS(opr_name(po, 0), opr_name(po, 1))) {
6484 // special case for XOR
6485 if (pfomask & (1 << PFO_BE)) { // weird, but it happens..
6486 fprintf(fout, " cond_be = 1;\n");
6487 pfomask &= ~(1 << PFO_BE);
6489 fprintf(fout, " %s = 0;",
6490 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6491 last_arith_dst = &po->operand[0];
6492 delayed_flag_op = NULL;
6498 assert_operand_cnt(2);
6499 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6500 if (pfomask & (1 << PFO_C)) {
6501 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6502 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6503 if (po->operand[0].lmod == OPLM_DWORD) {
6504 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
6505 fprintf(fout, " cond_c = tmp64 >> 32;\n");
6506 fprintf(fout, " %s = (u32)tmp64;",
6507 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6508 strcat(g_comment, " add64");
6511 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
6512 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
6513 fprintf(fout, " %s += %s;",
6514 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6517 pfomask &= ~(1 << PFO_C);
6518 output_std_flags(fout, po, &pfomask, buf1);
6519 last_arith_dst = &po->operand[0];
6520 delayed_flag_op = NULL;
6523 if (pfomask & (1 << PFO_LE)) {
6524 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
6525 fprintf(fout, " cond_%s = %s;\n",
6526 parsed_flag_op_names[PFO_LE], buf1);
6527 pfomask &= ~(1 << PFO_LE);
6532 assert_operand_cnt(2);
6533 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6534 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
6535 for (j = 0; j <= PFO_LE; j++) {
6536 if (!(pfomask & (1 << j)))
6538 if (j == PFO_Z || j == PFO_S)
6541 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6542 fprintf(fout, " cond_%s = %s;\n",
6543 parsed_flag_op_names[j], buf1);
6544 pfomask &= ~(1 << j);
6551 assert_operand_cnt(2);
6552 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6553 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6554 if (po->op == OP_SBB
6555 && IS(po->operand[0].name, po->operand[1].name))
6557 // avoid use of unitialized var
6558 fprintf(fout, " %s = -cond_c;", buf1);
6559 // carry remains what it was
6560 pfomask &= ~(1 << PFO_C);
6563 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
6564 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6566 output_std_flags(fout, po, &pfomask, buf1);
6567 last_arith_dst = &po->operand[0];
6568 delayed_flag_op = NULL;
6572 assert_operand_cnt(2);
6573 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6574 fprintf(fout, " %s = %s ? __builtin_ffs(%s) - 1 : 0;",
6575 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6577 output_std_flags(fout, po, &pfomask, buf1);
6578 last_arith_dst = &po->operand[0];
6579 delayed_flag_op = NULL;
6580 strcat(g_comment, " bsf");
6584 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
6585 for (j = 0; j <= PFO_LE; j++) {
6586 if (!(pfomask & (1 << j)))
6588 if (j == PFO_Z || j == PFO_S || j == PFO_C)
6591 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6592 fprintf(fout, " cond_%s = %s;\n",
6593 parsed_flag_op_names[j], buf1);
6594 pfomask &= ~(1 << j);
6600 if (pfomask & (1 << PFO_C))
6601 // carry is unaffected by inc/dec.. wtf?
6602 ferr(po, "carry propagation needed\n");
6604 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6605 if (po->operand[0].type == OPT_REG) {
6606 strcpy(buf2, po->op == OP_INC ? "++" : "--");
6607 fprintf(fout, " %s%s;", buf1, buf2);
6610 strcpy(buf2, po->op == OP_INC ? "+" : "-");
6611 fprintf(fout, " %s %s= 1;", buf1, buf2);
6613 output_std_flags(fout, po, &pfomask, buf1);
6614 last_arith_dst = &po->operand[0];
6615 delayed_flag_op = NULL;
6619 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6620 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
6621 fprintf(fout, " %s = -%s%s;", buf1,
6622 lmod_cast_s(po, po->operand[0].lmod), buf2);
6623 last_arith_dst = &po->operand[0];
6624 delayed_flag_op = NULL;
6625 if (pfomask & (1 << PFO_C)) {
6626 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
6627 pfomask &= ~(1 << PFO_C);
6632 if (po->operand_cnt == 2) {
6633 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6636 if (po->operand_cnt == 3)
6637 ferr(po, "TODO imul3\n");
6640 assert_operand_cnt(1);
6641 switch (po->operand[0].lmod) {
6643 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
6644 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
6645 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
6646 fprintf(fout, " edx = tmp64 >> 32;\n");
6647 fprintf(fout, " eax = tmp64;");
6650 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
6651 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
6652 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
6656 ferr(po, "TODO: unhandled mul type\n");
6659 last_arith_dst = NULL;
6660 delayed_flag_op = NULL;
6665 assert_operand_cnt(1);
6666 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6667 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
6668 po->op == OP_IDIV));
6669 switch (po->operand[0].lmod) {
6671 if (po->flags & OPF_32BIT)
6672 snprintf(buf2, sizeof(buf2), "%seax", cast);
6674 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
6675 snprintf(buf2, sizeof(buf2), "%stmp64",
6676 (po->op == OP_IDIV) ? "(s64)" : "");
6678 if (po->operand[0].type == OPT_REG
6679 && po->operand[0].reg == xDX)
6681 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
6682 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
6685 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
6686 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
6690 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
6691 snprintf(buf2, sizeof(buf2), "%stmp",
6692 (po->op == OP_IDIV) ? "(s32)" : "");
6693 if (po->operand[0].type == OPT_REG
6694 && po->operand[0].reg == xDX)
6696 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
6698 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
6702 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
6704 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
6707 strcat(g_comment, " div16");
6710 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
6712 last_arith_dst = NULL;
6713 delayed_flag_op = NULL;
6718 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6720 for (j = 0; j < 8; j++) {
6721 if (pfomask & (1 << j)) {
6722 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
6723 fprintf(fout, " cond_%s = %s;",
6724 parsed_flag_op_names[j], buf1);
6731 last_arith_dst = NULL;
6732 delayed_flag_op = po;
6736 // SETcc - should already be handled
6739 // note: we reuse OP_Jcc for SETcc, only flags differ
6741 fprintf(fout, "\n goto %s;", po->operand[0].name);
6745 fprintf(fout, " if (ecx == 0)\n");
6746 fprintf(fout, " goto %s;", po->operand[0].name);
6747 strcat(g_comment, " jecxz");
6751 fprintf(fout, " if (--ecx != 0)\n");
6752 fprintf(fout, " goto %s;", po->operand[0].name);
6753 strcat(g_comment, " loop");
6757 assert_operand_cnt(1);
6758 last_arith_dst = NULL;
6759 delayed_flag_op = NULL;
6761 if (po->operand[0].type == OPT_REGMEM) {
6762 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
6765 ferr(po, "parse failure for jmp '%s'\n",
6766 po->operand[0].name);
6767 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
6770 else if (po->operand[0].type != OPT_LABEL)
6771 ferr(po, "unhandled jmp type\n");
6773 fprintf(fout, " goto %s;", po->operand[0].name);
6777 assert_operand_cnt(1);
6779 my_assert_not(pp, NULL);
6782 if (po->flags & OPF_CC) {
6783 // we treat conditional branch to another func
6784 // (yes such code exists..) as conditional tailcall
6786 fprintf(fout, " {\n");
6789 if (pp->is_fptr && !pp->is_arg) {
6790 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
6791 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6793 if (pp->is_unresolved)
6794 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
6795 buf3, asmfn, po->asmln, pp->name);
6798 fprintf(fout, "%s", buf3);
6799 if (strstr(pp->ret_type.name, "int64")) {
6800 if (po->flags & OPF_TAIL)
6801 ferr(po, "int64 and tail?\n");
6802 fprintf(fout, "tmp64 = ");
6804 else if (!IS(pp->ret_type.name, "void")) {
6805 if (po->flags & OPF_TAIL) {
6806 if (regmask_ret & mxAX) {
6807 fprintf(fout, "return ");
6808 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
6809 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
6811 else if (regmask_ret & mxST0)
6812 ferr(po, "float tailcall\n");
6814 else if (po->regmask_dst & mxAX) {
6815 fprintf(fout, "eax = ");
6816 if (pp->ret_type.is_ptr)
6817 fprintf(fout, "(u32)");
6819 else if (po->regmask_dst & mxST0) {
6820 ferr_assert(po, po->flags & OPF_FPUSH);
6821 if (need_float_stack)
6822 fprintf(fout, "f_st[--f_stp & 7] = ");
6824 fprintf(fout, "f_st0 = ");
6828 if (pp->name[0] == 0)
6829 ferr(po, "missing pp->name\n");
6830 fprintf(fout, "%s%s(", pp->name,
6831 pp->has_structarg ? "_sa" : "");
6833 if (po->flags & OPF_ATAIL) {
6834 if (pp->argc_stack != g_func_pp->argc_stack
6835 || (pp->argc_stack > 0
6836 && pp->is_stdcall != g_func_pp->is_stdcall))
6837 ferr(po, "incompatible tailcall\n");
6838 if (g_func_pp->has_retreg)
6839 ferr(po, "TODO: retreg+tailcall\n");
6841 for (arg = j = 0; arg < pp->argc; arg++) {
6843 fprintf(fout, ", ");
6846 if (pp->arg[arg].type.is_ptr)
6847 snprintf(cast, sizeof(cast), "(%s)",
6848 pp->arg[arg].type.name);
6850 if (pp->arg[arg].reg != NULL) {
6851 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6855 for (; j < g_func_pp->argc; j++)
6856 if (g_func_pp->arg[j].reg == NULL)
6858 fprintf(fout, "%sa%d", cast, j + 1);
6863 for (arg = 0; arg < pp->argc; arg++) {
6865 fprintf(fout, ", ");
6868 if (pp->arg[arg].type.is_ptr)
6869 snprintf(cast, sizeof(cast), "(%s)",
6870 pp->arg[arg].type.name);
6872 if (pp->arg[arg].reg != NULL) {
6873 if (pp->arg[arg].type.is_retreg)
6874 fprintf(fout, "&%s", pp->arg[arg].reg);
6876 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6881 tmp_op = pp->arg[arg].datap;
6883 ferr(po, "parsed_op missing for arg%d\n", arg);
6885 if (tmp_op->flags & OPF_VAPUSH) {
6886 fprintf(fout, "ap");
6888 else if (tmp_op->op == OP_FST) {
6889 fprintf(fout, "fs_%d", tmp_op->p_argnum);
6890 if (tmp_op->operand[0].lmod == OPLM_QWORD)
6893 else if (tmp_op->p_argpass != 0) {
6894 fprintf(fout, "a%d", tmp_op->p_argpass);
6896 else if (tmp_op->p_argnum != 0) {
6897 fprintf(fout, "%s%s", cast,
6898 saved_arg_name(buf1, sizeof(buf1),
6899 tmp_op->p_arggrp, tmp_op->p_argnum));
6903 out_src_opr(buf1, sizeof(buf1),
6904 tmp_op, &tmp_op->operand[0], cast, 0));
6908 fprintf(fout, ");");
6910 if (strstr(pp->ret_type.name, "int64")) {
6911 fprintf(fout, "\n");
6912 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
6913 fprintf(fout, "%seax = tmp64;", buf3);
6916 if (pp->is_unresolved) {
6917 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
6919 strcat(g_comment, buf2);
6922 if (po->flags & OPF_TAIL) {
6924 if (i == opcnt - 1 || pp->is_noreturn)
6926 else if (IS(pp->ret_type.name, "void"))
6928 else if (!(regmask_ret & (1 << xAX)))
6930 // else already handled as 'return f()'
6933 fprintf(fout, "\n%sreturn;", buf3);
6934 strcat(g_comment, " ^ tailcall");
6937 strcat(g_comment, " tailcall");
6939 if ((regmask_ret & (1 << xAX))
6940 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
6942 ferr(po, "int func -> void func tailcall?\n");
6945 if (pp->is_noreturn)
6946 strcat(g_comment, " noreturn");
6947 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
6948 strcat(g_comment, " argframe");
6949 if (po->flags & OPF_CC)
6950 strcat(g_comment, " cond");
6952 if (po->flags & OPF_CC)
6953 fprintf(fout, "\n }");
6955 delayed_flag_op = NULL;
6956 last_arith_dst = NULL;
6960 if (g_func_pp->is_vararg)
6961 fprintf(fout, " va_end(ap);\n");
6962 if (g_func_pp->has_retreg) {
6963 for (arg = 0; arg < g_func_pp->argc; arg++)
6964 if (g_func_pp->arg[arg].type.is_retreg)
6965 fprintf(fout, " *r_%s = %s;\n",
6966 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
6969 if (regmask_ret & mxST0) {
6970 fprintf(fout, " return %s;", float_st0);
6972 else if (!(regmask_ret & mxAX)) {
6973 if (i != opcnt - 1 || label_pending)
6974 fprintf(fout, " return;");
6976 else if (g_func_pp->ret_type.is_ptr) {
6977 fprintf(fout, " return (%s)eax;",
6978 g_func_pp->ret_type.name);
6980 else if (IS(g_func_pp->ret_type.name, "__int64"))
6981 fprintf(fout, " return ((u64)edx << 32) | eax;");
6983 fprintf(fout, " return eax;");
6985 last_arith_dst = NULL;
6986 delayed_flag_op = NULL;
6990 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6991 if (po->p_argnum != 0) {
6992 // special case - saved func arg
6993 fprintf(fout, " %s = %s;",
6994 saved_arg_name(buf2, sizeof(buf2),
6995 po->p_arggrp, po->p_argnum), buf1);
6998 else if (po->flags & OPF_RSAVE) {
6999 fprintf(fout, " s_%s = %s;", buf1, buf1);
7002 else if (po->flags & OPF_PPUSH) {
7004 ferr_assert(po, tmp_op != NULL);
7005 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7006 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7009 else if (g_func_pp->is_userstack) {
7010 fprintf(fout, " *(--esp) = %s;", buf1);
7013 if (!(g_ida_func_attr & IDAFA_NORETURN))
7014 ferr(po, "stray push encountered\n");
7019 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7020 if (po->flags & OPF_RSAVE) {
7021 fprintf(fout, " %s = s_%s;", buf1, buf1);
7024 else if (po->flags & OPF_PPUSH) {
7025 // push/pop graph / non-const
7026 ferr_assert(po, po->datap == NULL);
7027 fprintf(fout, " %s = pp_%s;", buf1, buf1);
7030 else if (po->datap != NULL) {
7033 fprintf(fout, " %s = %s;", buf1,
7034 out_src_opr(buf2, sizeof(buf2),
7035 tmp_op, &tmp_op->operand[0],
7036 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7039 else if (g_func_pp->is_userstack) {
7040 fprintf(fout, " %s = *esp++;", buf1);
7044 ferr(po, "stray pop encountered\n");
7054 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7055 fprintf(fout, " tmp64 = (s64)tmp64 %s= LOBYTE(ecx);\n",
7056 po->op == OPP_ALLSHL ? "<<" : ">>");
7057 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
7058 strcat(g_comment, po->op == OPP_ALLSHL
7059 ? " allshl" : " allshr");
7064 if (need_float_stack) {
7065 out_src_opr_float(buf1, sizeof(buf1),
7066 po, &po->operand[0], 1);
7067 if (po->regmask_src & mxSTa) {
7068 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7072 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
7075 if (po->flags & OPF_FSHIFT)
7076 fprintf(fout, " f_st1 = f_st0;");
7077 if (po->operand[0].type == OPT_REG
7078 && po->operand[0].reg == xST0)
7080 strcat(g_comment, " fld st");
7083 fprintf(fout, " f_st0 = %s;",
7084 out_src_opr_float(buf1, sizeof(buf1),
7085 po, &po->operand[0], 0));
7087 strcat(g_comment, " fld");
7091 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7092 lmod_cast(po, po->operand[0].lmod, 1), 0);
7093 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7094 if (need_float_stack) {
7095 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
7098 if (po->flags & OPF_FSHIFT)
7099 fprintf(fout, " f_st1 = f_st0;");
7100 fprintf(fout, " f_st0 = %s;", buf2);
7102 strcat(g_comment, " fild");
7106 if (need_float_stack)
7107 fprintf(fout, " f_st[--f_stp & 7] = ");
7109 if (po->flags & OPF_FSHIFT)
7110 fprintf(fout, " f_st1 = f_st0;");
7111 fprintf(fout, " f_st0 = ");
7113 switch (po->operand[0].val) {
7114 case X87_CONST_1: fprintf(fout, "1.0;"); break;
7115 case X87_CONST_LN2: fprintf(fout, "0.693147180559945;"); break;
7116 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
7117 default: ferr(po, "TODO\n"); break;
7122 if (po->flags & OPF_FARG) {
7123 // store to stack as func arg
7124 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7128 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7130 dead_dst = po->operand[0].type == OPT_REG
7131 && po->operand[0].reg == xST0;
7134 fprintf(fout, " %s = %s;", buf1, float_st0);
7135 if (po->flags & OPF_FSHIFT) {
7136 if (need_float_stack)
7137 fprintf(fout, " f_stp++;");
7139 fprintf(fout, " f_st0 = f_st1;");
7141 if (dead_dst && !(po->flags & OPF_FSHIFT))
7144 strcat(g_comment, " fst");
7148 fprintf(fout, " %s = %s%s;",
7149 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7150 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7151 if (po->flags & OPF_FSHIFT) {
7152 if (need_float_stack)
7153 fprintf(fout, " f_stp++;");
7155 fprintf(fout, " f_st0 = f_st1;");
7157 strcat(g_comment, " fist");
7164 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7166 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7168 dead_dst = (po->flags & OPF_FPOP)
7169 && po->operand[0].type == OPT_REG
7170 && po->operand[0].reg == xST0;
7172 case OP_FADD: j = '+'; break;
7173 case OP_FDIV: j = '/'; break;
7174 case OP_FMUL: j = '*'; break;
7175 case OP_FSUB: j = '-'; break;
7176 default: j = 'x'; break;
7178 if (need_float_stack) {
7180 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7181 if (po->flags & OPF_FSHIFT)
7182 fprintf(fout, " f_stp++;");
7185 if (po->flags & OPF_FSHIFT) {
7186 // note: assumes only 2 regs handled
7188 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
7190 fprintf(fout, " f_st0 = f_st1;");
7193 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7195 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7200 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7202 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7204 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
7206 dead_dst = (po->flags & OPF_FPOP)
7207 && po->operand[0].type == OPT_REG
7208 && po->operand[0].reg == xST0;
7209 j = po->op == OP_FDIVR ? '/' : '-';
7210 if (need_float_stack) {
7212 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7213 if (po->flags & OPF_FSHIFT)
7214 fprintf(fout, " f_stp++;");
7217 if (po->flags & OPF_FSHIFT) {
7219 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
7221 fprintf(fout, " f_st0 = f_st1;");
7224 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7226 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7234 case OP_FIADD: j = '+'; break;
7235 case OP_FIDIV: j = '/'; break;
7236 case OP_FIMUL: j = '*'; break;
7237 case OP_FISUB: j = '-'; break;
7238 default: j = 'x'; break;
7240 fprintf(fout, " %s %c= (%s)%s;", float_st0,
7242 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7243 lmod_cast(po, po->operand[0].lmod, 1), 0));
7248 fprintf(fout, " %s = %s %c %s;", float_st0,
7249 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7251 po->op == OP_FIDIVR ? '/' : '-', float_st0);
7256 ferr_assert(po, po->datap != NULL);
7257 mask = (long)po->datap & 0xffff;
7258 z_check = ((long)po->datap >> 16) & 1;
7259 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7261 if (mask == 0x0100) { // C0 -> <
7262 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
7265 else if (mask == 0x4000) { // C3 -> =
7266 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
7269 else if (mask == 0x4100) { // C3, C0
7271 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
7273 strcat(g_comment, " z_chk_det");
7276 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
7277 "(%s < %s ? 0x0100 : 0);",
7278 float_st0, buf1, float_st0, buf1);
7282 ferr(po, "unhandled sw mask: %x\n", mask);
7283 if (po->flags & OPF_FSHIFT) {
7284 if (need_float_stack)
7285 fprintf(fout, " f_stp++;");
7287 fprintf(fout, " f_st0 = f_st1;");
7293 fprintf(fout, " %s = f_sw;",
7294 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7298 fprintf(fout, " %s = -%s;", float_st0, float_st0);
7302 fprintf(fout, " %s = cos%s(%s);", float_st0,
7303 need_double ? "" : "f", float_st0);
7307 if (need_float_stack) {
7308 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
7309 need_double ? "" : "f", float_st1, float_st0);
7310 fprintf(fout, " f_stp++;");
7313 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
7314 need_double ? "" : "f");
7319 if (need_float_stack) {
7320 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
7321 float_st1, need_double ? "" : "f", float_st0);
7322 fprintf(fout, " f_stp++;");
7325 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
7326 need_double ? "" : "f");
7331 fprintf(fout, " %s = sin%s(%s);", float_st0,
7332 need_double ? "" : "f", float_st0);
7336 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
7337 need_double ? "" : "f", float_st0);
7341 dead_dst = po->operand[0].type == OPT_REG
7342 && po->operand[0].reg == xST0;
7344 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7346 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
7347 float_st0, float_st0, buf1, buf1);
7348 strcat(g_comment, " fxch");
7355 ferr_assert(po, po->flags & OPF_32BIT);
7356 fprintf(fout, " eax = (s32)%s;", float_st0);
7357 if (po->flags & OPF_FSHIFT) {
7358 if (need_float_stack)
7359 fprintf(fout, " f_stp++;");
7361 fprintf(fout, " f_st0 = f_st1;");
7363 strcat(g_comment, " ftol");
7368 strcpy(g_comment, " (emms)");
7373 ferr(po, "unhandled op type %d, flags %x\n",
7378 if (g_comment[0] != 0) {
7379 char *p = g_comment;
7380 while (my_isblank(*p))
7382 fprintf(fout, " // %s", p);
7387 fprintf(fout, "\n");
7389 // some sanity checking
7390 if (po->flags & OPF_REP) {
7391 if (po->op != OP_STOS && po->op != OP_MOVS
7392 && po->op != OP_CMPS && po->op != OP_SCAS)
7393 ferr(po, "unexpected rep\n");
7394 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
7395 && (po->op == OP_CMPS || po->op == OP_SCAS))
7396 ferr(po, "cmps/scas with plain rep\n");
7398 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
7399 && po->op != OP_CMPS && po->op != OP_SCAS)
7400 ferr(po, "unexpected repz/repnz\n");
7403 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
7405 // see is delayed flag stuff is still valid
7406 if (delayed_flag_op != NULL && delayed_flag_op != po) {
7407 if (is_any_opr_modified(delayed_flag_op, po, 0))
7408 delayed_flag_op = NULL;
7411 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
7412 if (is_opr_modified(last_arith_dst, po))
7413 last_arith_dst = NULL;
7419 if (g_stack_fsz && !g_stack_frame_used)
7420 fprintf(fout, " (void)sf;\n");
7422 fprintf(fout, "}\n\n");
7424 gen_x_cleanup(opcnt);
7427 static void gen_x_cleanup(int opcnt)
7431 for (i = 0; i < opcnt; i++) {
7432 struct label_ref *lr, *lr_del;
7434 lr = g_label_refs[i].next;
7435 while (lr != NULL) {
7440 g_label_refs[i].i = -1;
7441 g_label_refs[i].next = NULL;
7443 if (ops[i].op == OP_CALL) {
7445 proto_release(ops[i].pp);
7451 struct func_proto_dep;
7453 struct func_prototype {
7458 int has_ret:3; // -1, 0, 1: unresolved, no, yes
7459 unsigned int dep_resolved:1;
7460 unsigned int is_stdcall:1;
7461 struct func_proto_dep *dep_func;
7463 const struct parsed_proto *pp; // seed pp, if any
7466 struct func_proto_dep {
7468 struct func_prototype *proto;
7469 int regmask_live; // .. at the time of call
7470 unsigned int ret_dep:1; // return from this is caller's return
7473 static struct func_prototype *hg_fp;
7474 static int hg_fp_cnt;
7476 static struct scanned_var {
7478 enum opr_lenmod lmod;
7479 unsigned int is_seeded:1;
7480 unsigned int is_c_str:1;
7481 const struct parsed_proto *pp; // seed pp, if any
7483 static int hg_var_cnt;
7485 static char **hg_refs;
7486 static int hg_ref_cnt;
7488 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7491 static struct func_prototype *hg_fp_add(const char *funcn)
7493 struct func_prototype *fp;
7495 if ((hg_fp_cnt & 0xff) == 0) {
7496 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
7497 my_assert_not(hg_fp, NULL);
7498 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
7501 fp = &hg_fp[hg_fp_cnt];
7502 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
7504 fp->argc_stack = -1;
7510 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
7515 for (i = 0; i < fp->dep_func_cnt; i++)
7516 if (IS(fp->dep_func[i].name, name))
7517 return &fp->dep_func[i];
7522 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
7525 if (hg_fp_find_dep(fp, name))
7528 if ((fp->dep_func_cnt & 0xff) == 0) {
7529 fp->dep_func = realloc(fp->dep_func,
7530 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
7531 my_assert_not(fp->dep_func, NULL);
7532 memset(&fp->dep_func[fp->dep_func_cnt], 0,
7533 sizeof(fp->dep_func[0]) * 0x100);
7535 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
7539 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
7541 const struct func_prototype *p1 = p1_, *p2 = p2_;
7542 return strcmp(p1->name, p2->name);
7546 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
7548 const struct func_prototype *p1 = p1_, *p2 = p2_;
7549 return p1->id - p2->id;
7553 static void hg_ref_add(const char *name)
7555 if ((hg_ref_cnt & 0xff) == 0) {
7556 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
7557 my_assert_not(hg_refs, NULL);
7558 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
7561 hg_refs[hg_ref_cnt] = strdup(name);
7562 my_assert_not(hg_refs[hg_ref_cnt], NULL);
7566 // recursive register dep pass
7567 // - track saved regs (part 2)
7568 // - try to figure out arg-regs
7569 // - calculate reg deps
7570 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
7571 struct func_prototype *fp, int regmask_save, int regmask_dst,
7572 int *regmask_dep, int *has_ret)
7574 struct func_proto_dep *dep;
7575 struct parsed_op *po;
7576 int from_caller = 0;
7581 for (; i < opcnt; i++)
7583 if (cbits[i >> 3] & (1 << (i & 7)))
7585 cbits[i >> 3] |= (1 << (i & 7));
7589 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
7590 if (po->flags & OPF_RMD)
7593 if (po->btj != NULL) {
7595 for (j = 0; j < po->btj->count; j++) {
7596 check_i(po, po->btj->d[j].bt_i);
7597 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
7598 regmask_save, regmask_dst, regmask_dep, has_ret);
7603 check_i(po, po->bt_i);
7604 if (po->flags & OPF_CJMP) {
7605 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
7606 regmask_save, regmask_dst, regmask_dep, has_ret);
7614 if (po->flags & OPF_FARG)
7615 /* (just calculate register deps) */;
7616 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
7618 reg = po->operand[0].reg;
7619 ferr_assert(po, reg >= 0);
7621 if (po->flags & OPF_RSAVE) {
7622 regmask_save |= 1 << reg;
7625 if (po->flags & OPF_DONE)
7628 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0);
7630 regmask_save |= 1 << reg;
7631 po->flags |= OPF_RMD;
7632 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, OPF_RMD);
7636 else if (po->flags & OPF_RMD)
7638 else if (po->op == OP_CALL) {
7639 po->regmask_dst |= 1 << xAX;
7641 dep = hg_fp_find_dep(fp, po->operand[0].name);
7643 dep->regmask_live = regmask_save | regmask_dst;
7645 else if (po->op == OP_RET) {
7646 if (po->operand_cnt > 0) {
7648 if (fp->argc_stack >= 0
7649 && fp->argc_stack != po->operand[0].val / 4)
7650 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
7651 fp->argc_stack = po->operand[0].val / 4;
7655 // if has_ret is 0, there is uninitialized eax path,
7656 // which means it's most likely void func
7657 if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
7658 if (po->op == OP_CALL) {
7663 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
7666 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
7669 if (ret != 1 && from_caller) {
7670 // unresolved eax - probably void func
7674 if (j >= 0 && ops[j].op == OP_CALL) {
7675 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
7686 l = regmask_save | regmask_dst;
7687 if (g_bp_frame && !(po->flags & OPF_EBP_S))
7690 l = po->regmask_src & ~l;
7693 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
7694 l, regmask_dst, regmask_save, po->flags);
7697 regmask_dst |= po->regmask_dst;
7699 if (po->flags & OPF_TAIL)
7704 static void gen_hdr(const char *funcn, int opcnt)
7706 int save_arg_vars[MAX_ARG_GRP] = { 0, };
7707 unsigned char cbits[MAX_OPS / 8];
7708 const struct parsed_proto *pp_c;
7709 struct parsed_proto *pp;
7710 struct func_prototype *fp;
7711 struct parsed_op *po;
7712 int regmask_dummy = 0;
7714 int max_bp_offset = 0;
7719 pp_c = proto_parse(g_fhdr, funcn, 1);
7721 // already in seed, will add to hg_fp later
7724 fp = hg_fp_add(funcn);
7726 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
7727 g_stack_frame_used = 0;
7730 // - resolve all branches
7731 // - parse calls with labels
7732 resolve_branches_parse_calls(opcnt);
7735 // - handle ebp/esp frame, remove ops related to it
7736 scan_prologue_epilogue(opcnt);
7739 // - remove dead labels
7741 for (i = 0; i < opcnt; i++)
7743 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7749 if (po->flags & (OPF_RMD|OPF_DONE))
7752 if (po->op == OP_CALL) {
7753 if (po->operand[0].type == OPT_LABEL)
7754 hg_fp_add_dep(fp, opr_name(po, 0));
7755 else if (po->pp != NULL)
7756 hg_fp_add_dep(fp, po->pp->name);
7761 // - remove dead labels
7762 // - handle push <const>/pop pairs
7763 for (i = 0; i < opcnt; i++)
7765 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7771 if (po->flags & (OPF_RMD|OPF_DONE))
7774 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
7775 scan_for_pop_const(i, opcnt, i + opcnt * 13);
7779 // - process trivial calls
7780 for (i = 0; i < opcnt; i++)
7783 if (po->flags & (OPF_RMD|OPF_DONE))
7786 if (po->op == OP_CALL)
7788 pp = process_call_early(i, opcnt, &j);
7790 if (!(po->flags & OPF_ATAIL))
7791 // since we know the args, try to collect them
7792 if (collect_call_args_early(i, pp, NULL, NULL) != 0)
7798 // commit esp adjust
7799 if (ops[j].op != OP_POP)
7800 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
7802 for (l = 0; l < pp->argc_stack; l++)
7803 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
7807 po->flags |= OPF_DONE;
7813 // - track saved regs (simple)
7815 for (i = 0; i < opcnt; i++)
7818 if (po->flags & (OPF_RMD|OPF_DONE))
7821 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
7822 && po->operand[0].reg != xCX)
7824 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
7826 // regmask_save |= 1 << po->operand[0].reg; // do it later
7827 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
7828 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
7831 else if (po->op == OP_CALL)
7833 pp = process_call(i, opcnt);
7835 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
7836 // since we know the args, collect them
7837 ret = collect_call_args(po, i, pp, ®mask_dummy, save_arg_vars,
7844 memset(cbits, 0, sizeof(cbits));
7848 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, ®mask_dep, &has_ret);
7850 // find unreachable code - must be fixed in IDA
7851 for (i = 0; i < opcnt; i++)
7853 if (cbits[i >> 3] & (1 << (i & 7)))
7856 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
7857 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
7859 // the compiler sometimes still generates code after
7860 // noreturn OS functions
7863 if (ops[i].op != OP_NOP)
7864 ferr(&ops[i], "unreachable code\n");
7867 for (i = 0; i < g_eqcnt; i++) {
7868 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
7869 max_bp_offset = g_eqs[i].offset;
7872 if (fp->argc_stack < 0) {
7873 max_bp_offset = (max_bp_offset + 3) & ~3;
7874 fp->argc_stack = max_bp_offset / 4;
7875 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
7879 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
7880 fp->has_ret = has_ret;
7882 printf("// has_ret %d, regmask_dep %x\n",
7883 fp->has_ret, fp->regmask_dep);
7884 output_hdr_fp(stdout, fp, 1);
7885 if (IS(funcn, "sub_10007F72")) exit(1);
7888 gen_x_cleanup(opcnt);
7891 static void hg_fp_resolve_deps(struct func_prototype *fp)
7893 struct func_prototype fp_s;
7897 // this thing is recursive, so mark first..
7898 fp->dep_resolved = 1;
7900 for (i = 0; i < fp->dep_func_cnt; i++) {
7901 strcpy(fp_s.name, fp->dep_func[i].name);
7902 fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
7903 sizeof(hg_fp[0]), hg_fp_cmp_name);
7904 if (fp->dep_func[i].proto != NULL) {
7905 if (!fp->dep_func[i].proto->dep_resolved)
7906 hg_fp_resolve_deps(fp->dep_func[i].proto);
7908 dep = ~fp->dep_func[i].regmask_live
7909 & fp->dep_func[i].proto->regmask_dep;
7910 fp->regmask_dep |= dep;
7911 // printf("dep %s %s |= %x\n", fp->name,
7912 // fp->dep_func[i].name, dep);
7914 if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
7915 fp->has_ret = fp->dep_func[i].proto->has_ret;
7920 // make all thiscall/edx arg functions referenced from .data fastcall
7921 static void do_func_refs_from_data(void)
7923 struct func_prototype *fp, fp_s;
7926 for (i = 0; i < hg_ref_cnt; i++) {
7927 strcpy(fp_s.name, hg_refs[i]);
7928 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
7929 sizeof(hg_fp[0]), hg_fp_cmp_name);
7933 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
7934 fp->regmask_dep |= mxCX | mxDX;
7938 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7941 const struct parsed_proto *pp;
7942 char *p, namebuf[NAMELEN];
7948 for (; count > 0; count--, fp++) {
7949 if (fp->has_ret == -1)
7950 fprintf(fout, "// ret unresolved\n");
7952 fprintf(fout, "// dep:");
7953 for (j = 0; j < fp->dep_func_cnt; j++) {
7954 fprintf(fout, " %s/", fp->dep_func[j].name);
7955 if (fp->dep_func[j].proto != NULL)
7956 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
7957 fp->dep_func[j].proto->has_ret);
7959 fprintf(fout, "\n");
7962 p = strchr(fp->name, '@');
7964 memcpy(namebuf, fp->name, p - fp->name);
7965 namebuf[p - fp->name] = 0;
7973 pp = proto_parse(g_fhdr, name, 1);
7974 if (pp != NULL && pp->is_include)
7977 if (fp->pp != NULL) {
7978 // part of seed, output later
7982 regmask_dep = fp->regmask_dep;
7983 argc_normal = fp->argc_stack;
7985 fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
7986 (fp->has_ret ? "int" : "void"));
7987 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
7988 && (regmask_dep & ~mxCX) == 0)
7990 fprintf(fout, "/*__thiscall*/ ");
7994 else if (regmask_dep && (fp->is_stdcall || fp->argc_stack == 0)
7995 && (regmask_dep & ~(mxCX | mxDX)) == 0)
7997 fprintf(fout, " __fastcall ");
7998 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8004 else if (regmask_dep && !fp->is_stdcall) {
8005 fprintf(fout, "/*__usercall*/ ");
8007 else if (regmask_dep) {
8008 fprintf(fout, "/*__userpurge*/ ");
8010 else if (fp->is_stdcall)
8011 fprintf(fout, " __stdcall ");
8013 fprintf(fout, " __cdecl ");
8015 fprintf(fout, "%s(", name);
8018 for (j = 0; j < xSP; j++) {
8019 if (regmask_dep & (1 << j)) {
8022 fprintf(fout, ", ");
8024 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8026 fprintf(fout, "int");
8027 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
8031 for (j = 0; j < argc_normal; j++) {
8034 fprintf(fout, ", ");
8035 if (fp->pp != NULL) {
8036 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8037 if (!fp->pp->arg[arg - 1].type.is_ptr)
8041 fprintf(fout, "int ");
8042 fprintf(fout, "a%d", arg);
8045 fprintf(fout, ");\n");
8049 static void output_hdr(FILE *fout)
8051 static const char *lmod_c_names[] = {
8052 [OPLM_UNSPEC] = "???",
8053 [OPLM_BYTE] = "uint8_t",
8054 [OPLM_WORD] = "uint16_t",
8055 [OPLM_DWORD] = "uint32_t",
8056 [OPLM_QWORD] = "uint64_t",
8058 const struct scanned_var *var;
8059 struct func_prototype *fp;
8060 char line[256] = { 0, };
8064 // add stuff from headers
8065 for (i = 0; i < pp_cache_size; i++) {
8066 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
8067 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
8069 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
8070 fp = hg_fp_add(name);
8071 fp->pp = &pp_cache[i];
8072 fp->argc_stack = fp->pp->argc_stack;
8073 fp->is_stdcall = fp->pp->is_stdcall;
8074 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
8075 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
8079 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
8080 for (i = 0; i < hg_fp_cnt; i++)
8081 hg_fp_resolve_deps(&hg_fp[i]);
8083 // adjust functions referenced from data segment
8084 do_func_refs_from_data();
8086 // note: messes up .proto ptr, don't use
8087 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
8090 for (i = 0; i < hg_var_cnt; i++) {
8093 if (var->pp != NULL)
8096 else if (var->is_c_str)
8097 fprintf(fout, "extern %-8s %s[];", "char", var->name);
8099 fprintf(fout, "extern %-8s %s;",
8100 lmod_c_names[var->lmod], var->name);
8103 fprintf(fout, " // seeded");
8104 fprintf(fout, "\n");
8107 fprintf(fout, "\n");
8109 // output function prototypes
8110 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
8113 fprintf(fout, "\n// - seed -\n");
8116 while (fgets(line, sizeof(line), g_fhdr))
8117 fwrite(line, 1, strlen(line), fout);
8120 // '=' needs special treatment
8122 static char *next_word_s(char *w, size_t wsize, char *s)
8129 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
8131 for (i = 1; i < wsize - 1; i++) {
8133 printf("warning: missing closing quote: \"%s\"\n", s);
8142 for (; i < wsize - 1; i++) {
8143 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
8149 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
8150 printf("warning: '%s' truncated\n", w);
8155 static int cmpstringp(const void *p1, const void *p2)
8157 return strcmp(*(char * const *)p1, *(char * const *)p2);
8160 static int is_xref_needed(char *p, char **rlist, int rlist_len)
8165 if (strstr(p, "..."))
8166 // unable to determine, assume needed
8169 if (*p == '.') // .text, .data, ...
8170 // ref from other data or non-function -> no
8173 p2 = strpbrk(p, "+:\r\n\x18");
8176 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8177 // referenced from removed code
8183 static int ida_xrefs_show_need(FILE *fasm, char *p,
8184 char **rlist, int rlist_len)
8190 p = strrchr(p, ';');
8191 if (p != NULL && *p == ';' && IS_START(p + 2, "DATA XREF: ")) {
8193 if (is_xref_needed(p, rlist, rlist_len))
8200 if (!my_fgets(line, sizeof(line), fasm))
8202 // non-first line is always indented
8203 if (!my_isblank(line[0]))
8206 // should be no content, just comment
8211 p = strrchr(p, ';');
8213 // it's printed once, but no harm to check again
8214 if (IS_START(p, "DATA XREF: "))
8217 if (is_xref_needed(p, rlist, rlist_len)) {
8222 fseek(fasm, pos, SEEK_SET);
8226 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
8228 struct scanned_var *var;
8229 char line[256] = { 0, };
8238 // skip to next data section
8239 while (my_fgets(line, sizeof(line), fasm))
8244 if (*p == 0 || *p == ';')
8247 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
8248 if (*p == 0 || *p == ';')
8251 if (*p != 's' || !IS_START(p, "segment para public"))
8257 if (p == NULL || !IS_START(p, "segment para public"))
8261 if (!IS_START(p, "'DATA'"))
8265 while (my_fgets(line, sizeof(line), fasm))
8270 no_identifier = my_isblank(*p);
8273 if (*p == 0 || *p == ';')
8276 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8277 words[wordc][0] = 0;
8278 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8279 if (*p == 0 || *p == ';') {
8285 if (wordc == 2 && IS(words[1], "ends"))
8290 if (no_identifier) {
8291 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
8292 hg_ref_add(words[2]);
8296 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
8297 // when this starts, we don't need anything from this section
8301 // check refs comment(s)
8302 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
8305 if ((hg_var_cnt & 0xff) == 0) {
8306 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
8307 * (hg_var_cnt + 0x100));
8308 my_assert_not(hg_vars, NULL);
8309 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
8312 var = &hg_vars[hg_var_cnt++];
8313 snprintf(var->name, sizeof(var->name), "%s", words[0]);
8315 // maybe already in seed header?
8316 var->pp = proto_parse(g_fhdr, var->name, 1);
8317 if (var->pp != NULL) {
8318 if (var->pp->is_fptr) {
8319 var->lmod = OPLM_DWORD;
8322 else if (var->pp->is_func)
8324 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
8325 aerr("unhandled C type '%s' for '%s'\n",
8326 var->pp->type.name, var->name);
8332 if (IS(words[1], "dd")) {
8333 var->lmod = OPLM_DWORD;
8334 if (wordc >= 4 && IS(words[2], "offset"))
8335 hg_ref_add(words[3]);
8337 else if (IS(words[1], "dw"))
8338 var->lmod = OPLM_WORD;
8339 else if (IS(words[1], "db")) {
8340 var->lmod = OPLM_BYTE;
8341 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
8342 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
8346 else if (IS(words[1], "dq"))
8347 var->lmod = OPLM_QWORD;
8348 //else if (IS(words[1], "dt"))
8350 aerr("type '%s' not known\n", words[1]);
8358 static void set_label(int i, const char *name)
8364 p = strchr(name, ':');
8368 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
8369 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
8370 g_labels[i] = realloc(g_labels[i], len + 1);
8371 my_assert_not(g_labels[i], NULL);
8372 memcpy(g_labels[i], name, len);
8373 g_labels[i][len] = 0;
8382 static struct chunk_item *func_chunks;
8383 static int func_chunk_cnt;
8384 static int func_chunk_alloc;
8386 static void add_func_chunk(FILE *fasm, const char *name, int line)
8388 if (func_chunk_cnt >= func_chunk_alloc) {
8389 func_chunk_alloc *= 2;
8390 func_chunks = realloc(func_chunks,
8391 func_chunk_alloc * sizeof(func_chunks[0]));
8392 my_assert_not(func_chunks, NULL);
8394 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
8395 func_chunks[func_chunk_cnt].name = strdup(name);
8396 func_chunks[func_chunk_cnt].asmln = line;
8400 static int cmp_chunks(const void *p1, const void *p2)
8402 const struct chunk_item *c1 = p1, *c2 = p2;
8403 return strcmp(c1->name, c2->name);
8406 static void scan_ahead(FILE *fasm)
8416 oldpos = ftell(fasm);
8419 while (my_fgets(line, sizeof(line), fasm))
8430 // get rid of random tabs
8431 for (i = 0; line[i] != 0; i++)
8432 if (line[i] == '\t')
8435 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8438 next_word(words[0], sizeof(words[0]), p);
8439 if (words[0][0] == 0)
8440 aerr("missing name for func chunk?\n");
8442 add_func_chunk(fasm, words[0], asmln);
8444 else if (IS_START(p, "; sctend"))
8450 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8451 words[wordc][0] = 0;
8452 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8453 if (*p == 0 || *p == ';') {
8459 if (wordc == 2 && IS(words[1], "ends"))
8463 fseek(fasm, oldpos, SEEK_SET);
8467 int main(int argc, char *argv[])
8469 FILE *fout, *fasm, *frlist;
8470 struct parsed_data *pd = NULL;
8472 char **rlist = NULL;
8474 int rlist_alloc = 0;
8475 int func_chunks_used = 0;
8476 int func_chunks_sorted = 0;
8477 int func_chunk_i = -1;
8478 long func_chunk_ret = 0;
8479 int func_chunk_ret_ln = 0;
8480 int scanned_ahead = 0;
8482 char words[20][256];
8483 enum opr_lenmod lmod;
8484 char *sctproto = NULL;
8486 int pending_endp = 0;
8488 int skip_warned = 0;
8501 for (arg = 1; arg < argc; arg++) {
8502 if (IS(argv[arg], "-v"))
8504 else if (IS(argv[arg], "-rf"))
8505 g_allow_regfunc = 1;
8506 else if (IS(argv[arg], "-m"))
8508 else if (IS(argv[arg], "-hdr"))
8509 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
8514 if (argc < arg + 3) {
8515 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
8516 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
8518 " -hdr - header generation mode\n"
8519 " -rf - allow unannotated indirect calls\n"
8520 " -m - allow multiple .text sections\n"
8521 "[rlist] is a file with function names to skip,"
8529 asmfn = argv[arg++];
8530 fasm = fopen(asmfn, "r");
8531 my_assert_not(fasm, NULL);
8533 hdrfn = argv[arg++];
8534 g_fhdr = fopen(hdrfn, "r");
8535 my_assert_not(g_fhdr, NULL);
8538 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
8539 my_assert_not(rlist, NULL);
8540 // needs special handling..
8541 rlist[rlist_len++] = "__alloca_probe";
8543 func_chunk_alloc = 32;
8544 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
8545 my_assert_not(func_chunks, NULL);
8547 memset(words, 0, sizeof(words));
8549 for (; arg < argc; arg++) {
8550 frlist = fopen(argv[arg], "r");
8551 my_assert_not(frlist, NULL);
8553 while (my_fgets(line, sizeof(line), frlist)) {
8555 if (*p == 0 || *p == ';')
8558 if (IS_START(p, "#if 0")
8559 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
8563 else if (IS_START(p, "#endif"))
8570 p = next_word(words[0], sizeof(words[0]), p);
8571 if (words[0][0] == 0)
8574 if (rlist_len >= rlist_alloc) {
8575 rlist_alloc = rlist_alloc * 2 + 64;
8576 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
8577 my_assert_not(rlist, NULL);
8579 rlist[rlist_len++] = strdup(words[0]);
8588 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
8590 fout = fopen(argv[arg_out], "w");
8591 my_assert_not(fout, NULL);
8594 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
8595 my_assert_not(g_eqs, NULL);
8597 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
8598 g_label_refs[i].i = -1;
8599 g_label_refs[i].next = NULL;
8603 scan_variables(fasm, rlist, rlist_len);
8605 while (my_fgets(line, sizeof(line), fasm))
8614 // get rid of random tabs
8615 for (i = 0; line[i] != 0; i++)
8616 if (line[i] == '\t')
8621 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
8622 goto do_pending_endp; // eww..
8624 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
8626 static const char *attrs[] = {
8635 // parse IDA's attribute-list comment
8636 g_ida_func_attr = 0;
8639 for (; *p != 0; p = sskip(p)) {
8640 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8641 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8642 g_ida_func_attr |= 1 << i;
8643 p += strlen(attrs[i]);
8647 if (i == ARRAY_SIZE(attrs)) {
8648 anote("unparsed IDA attr: %s\n", p);
8651 if (IS(attrs[i], "fpd=")) {
8652 p = next_word(words[0], sizeof(words[0]), p);
8657 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
8659 static const char *attrs[] = {
8664 // parse manual attribute-list comment
8665 g_sct_func_attr = 0;
8668 for (; *p != 0; p = sskip(p)) {
8669 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8670 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8671 g_sct_func_attr |= 1 << i;
8672 p += strlen(attrs[i]);
8679 // clear_sf=start,len (in dwords)
8680 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
8681 &g_stack_clear_len, &j);
8683 // clear_regmask=<mask>
8684 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
8686 anote("unparsed attr value: %s\n", p);
8691 else if (i == ARRAY_SIZE(attrs)) {
8692 anote("unparsed sct attr: %s\n", p);
8697 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8700 next_word(words[0], sizeof(words[0]), p);
8701 if (words[0][0] == 0)
8702 aerr("missing name for func chunk?\n");
8704 if (!scanned_ahead) {
8705 add_func_chunk(fasm, words[0], asmln);
8706 func_chunks_sorted = 0;
8709 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
8711 if (func_chunk_i >= 0) {
8712 if (func_chunk_i < func_chunk_cnt
8713 && IS(func_chunks[func_chunk_i].name, g_func))
8715 // move on to next chunk
8716 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
8718 aerr("seek failed for '%s' chunk #%d\n",
8719 g_func, func_chunk_i);
8720 asmln = func_chunks[func_chunk_i].asmln;
8724 if (func_chunk_ret == 0)
8725 aerr("no return from chunk?\n");
8726 fseek(fasm, func_chunk_ret, SEEK_SET);
8727 asmln = func_chunk_ret_ln;
8733 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
8734 func_chunks_used = 1;
8736 if (IS_START(g_func, "sub_")) {
8737 unsigned long addr = strtoul(p, NULL, 16);
8738 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
8739 if (addr > f_addr && !scanned_ahead) {
8740 //anote("scan_ahead caused by '%s', addr %lx\n",
8744 func_chunks_sorted = 0;
8752 for (i = wordc; i < ARRAY_SIZE(words); i++)
8754 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8755 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8756 if (*p == 0 || *p == ';') {
8761 if (*p != 0 && *p != ';')
8762 aerr("too many words\n");
8764 // alow asm patches in comments
8766 if (IS_START(p, "; sctpatch:")) {
8768 if (*p == 0 || *p == ';')
8770 goto parse_words; // lame
8772 if (IS_START(p, "; sctproto:")) {
8773 sctproto = strdup(p + 11);
8775 else if (IS_START(p, "; sctend")) {
8784 awarn("wordc == 0?\n");
8788 // don't care about this:
8789 if (words[0][0] == '.'
8790 || IS(words[0], "include")
8791 || IS(words[0], "assume") || IS(words[1], "segment")
8792 || IS(words[0], "align"))
8798 // do delayed endp processing to collect switch jumptables
8800 if (in_func && !g_skip_func && !end && wordc >= 2
8801 && ((words[0][0] == 'd' && words[0][2] == 0)
8802 || (words[1][0] == 'd' && words[1][2] == 0)))
8805 if (words[1][0] == 'd' && words[1][2] == 0) {
8807 if (g_func_pd_cnt >= pd_alloc) {
8808 pd_alloc = pd_alloc * 2 + 16;
8809 g_func_pd = realloc(g_func_pd,
8810 sizeof(g_func_pd[0]) * pd_alloc);
8811 my_assert_not(g_func_pd, NULL);
8813 pd = &g_func_pd[g_func_pd_cnt];
8815 memset(pd, 0, sizeof(*pd));
8816 strcpy(pd->label, words[0]);
8817 pd->type = OPT_CONST;
8818 pd->lmod = lmod_from_directive(words[1]);
8824 anote("skipping alignment byte?\n");
8827 lmod = lmod_from_directive(words[0]);
8828 if (lmod != pd->lmod)
8829 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
8832 if (pd->count_alloc < pd->count + wordc) {
8833 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
8834 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
8835 my_assert_not(pd->d, NULL);
8837 for (; i < wordc; i++) {
8838 if (IS(words[i], "offset")) {
8839 pd->type = OPT_OFFSET;
8842 p = strchr(words[i], ',');
8845 if (pd->type == OPT_OFFSET)
8846 pd->d[pd->count].u.label = strdup(words[i]);
8848 pd->d[pd->count].u.val = parse_number(words[i]);
8849 pd->d[pd->count].bt_i = -1;
8855 if (in_func && !g_skip_func) {
8857 gen_hdr(g_func, pi);
8859 gen_func(fout, g_fhdr, g_func, pi);
8864 g_ida_func_attr = 0;
8865 g_sct_func_attr = 0;
8866 g_stack_clear_start = 0;
8867 g_stack_clear_len = 0;
8872 func_chunks_used = 0;
8875 memset(&ops, 0, pi * sizeof(ops[0]));
8880 for (i = 0; i < g_func_pd_cnt; i++) {
8882 if (pd->type == OPT_OFFSET) {
8883 for (j = 0; j < pd->count; j++)
8884 free(pd->d[j].u.label);
8899 if (IS(words[1], "proc")) {
8901 aerr("proc '%s' while in_func '%s'?\n",
8904 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8906 strcpy(g_func, words[0]);
8907 set_label(0, words[0]);
8912 if (IS(words[1], "endp"))
8915 aerr("endp '%s' while not in_func?\n", words[0]);
8916 if (!IS(g_func, words[0]))
8917 aerr("endp '%s' while in_func '%s'?\n",
8920 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
8921 && ops[0].op == OP_JMP && ops[0].operand[0].had_ds)
8927 if (!g_skip_func && func_chunks_used) {
8928 // start processing chunks
8929 struct chunk_item *ci, key = { g_func, 0 };
8931 func_chunk_ret = ftell(fasm);
8932 func_chunk_ret_ln = asmln;
8933 if (!func_chunks_sorted) {
8934 qsort(func_chunks, func_chunk_cnt,
8935 sizeof(func_chunks[0]), cmp_chunks);
8936 func_chunks_sorted = 1;
8938 ci = bsearch(&key, func_chunks, func_chunk_cnt,
8939 sizeof(func_chunks[0]), cmp_chunks);
8941 aerr("'%s' needs chunks, but none found\n", g_func);
8942 func_chunk_i = ci - func_chunks;
8943 for (; func_chunk_i > 0; func_chunk_i--)
8944 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
8947 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
8949 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
8950 asmln = func_chunks[func_chunk_i].asmln;
8958 if (wordc == 2 && IS(words[1], "ends")) {
8962 goto do_pending_endp;
8966 // scan for next text segment
8967 while (my_fgets(line, sizeof(line), fasm)) {
8970 if (*p == 0 || *p == ';')
8973 if (strstr(p, "segment para public 'CODE' use32"))
8980 p = strchr(words[0], ':');
8982 set_label(pi, words[0]);
8986 if (!in_func || g_skip_func) {
8987 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
8989 anote("skipping from '%s'\n", g_labels[pi]);
8993 g_labels[pi] = NULL;
8997 if (wordc > 1 && IS(words[1], "="))
9000 aerr("unhandled equ, wc=%d\n", wordc);
9001 if (g_eqcnt >= eq_alloc) {
9003 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
9004 my_assert_not(g_eqs, NULL);
9007 len = strlen(words[0]);
9008 if (len > sizeof(g_eqs[0].name) - 1)
9009 aerr("equ name too long: %d\n", len);
9010 strcpy(g_eqs[g_eqcnt].name, words[0]);
9012 if (!IS(words[3], "ptr"))
9013 aerr("unhandled equ\n");
9014 if (IS(words[2], "dword"))
9015 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
9016 else if (IS(words[2], "word"))
9017 g_eqs[g_eqcnt].lmod = OPLM_WORD;
9018 else if (IS(words[2], "byte"))
9019 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
9020 else if (IS(words[2], "qword"))
9021 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
9023 aerr("bad lmod: '%s'\n", words[2]);
9025 g_eqs[g_eqcnt].offset = parse_number(words[4]);
9030 if (pi >= ARRAY_SIZE(ops))
9031 aerr("too many ops\n");
9033 parse_op(&ops[pi], words, wordc);
9035 ops[pi].datap = sctproto;
9050 // vim:ts=2:shiftwidth=2:expandtab