5 * This work is licensed under the terms of 3-clause BSD license.
6 * See COPYING file in the top-level directory.
8 * recognized asm hint comments:
9 * sctattr - function attributes (see code)
10 * sctend - force end of function/chunk
11 * sctpatch: <p> - replace current asm line with <p>
12 * sctproto: <p> - prototype of ref'd function or struct
13 * sctref - variable is referenced, make global
14 * sctskip_start - start of skipped code chunk (inclusive)
15 * sctskip_end - end of skipped code chunk (inclusive)
25 #include "my_assert.h"
29 #include "protoparse.h"
31 static const char *asmfn;
35 #define anote(fmt, ...) \
36 printf("%s:%d: note: " fmt, asmfn, asmln, ##__VA_ARGS__)
37 #define awarn(fmt, ...) \
38 printf("%s:%d: warning: " fmt, asmfn, asmln, ##__VA_ARGS__)
39 #define aerr(fmt, ...) do { \
40 printf("%s:%d: error: " fmt, asmfn, asmln, ##__VA_ARGS__); \
45 #include "masm_tools.h"
48 OPF_RMD = (1 << 0), /* removed from code generation */
49 OPF_DATA = (1 << 1), /* data processing - writes to dst opr */
50 OPF_FLAGS = (1 << 2), /* sets flags */
51 OPF_JMP = (1 << 3), /* branch, call */
52 OPF_CJMP = (1 << 4), /* cond. branch (cc or jecxz/loop) */
53 OPF_CC = (1 << 5), /* uses flags */
54 OPF_TAIL = (1 << 6), /* ret or tail call */
55 OPF_RSAVE = (1 << 7), /* push/pop is local reg save/load */
56 OPF_REP = (1 << 8), /* prefixed by rep */
57 OPF_REPZ = (1 << 9), /* rep is repe/repz */
58 OPF_REPNZ = (1 << 10), /* rep is repne/repnz */
59 OPF_FARG = (1 << 11), /* push collected as func arg */
60 OPF_FARGNR = (1 << 12), /* push collected as func arg (no reuse) */
61 OPF_EBP_S = (1 << 13), /* ebp used as scratch here, not BP */
62 OPF_DF = (1 << 14), /* DF flag set */
63 OPF_ATAIL = (1 << 15), /* tail call with reused arg frame */
64 OPF_32BIT = (1 << 16), /* enough to do 32bit for this op */
65 OPF_LOCK = (1 << 17), /* op has lock prefix */
66 OPF_VAPUSH = (1 << 18), /* vararg ptr push (as call arg) */
67 OPF_DONE = (1 << 19), /* already fully handled by analysis */
68 OPF_PPUSH = (1 << 20), /* part of complex push-pop graph */
69 OPF_NOREGS = (1 << 21), /* don't track regs of this op */
70 OPF_FPUSH = (1 << 22), /* pushes x87 stack */
71 OPF_FPOP = (1 << 23), /* pops x87 stack */
72 OPF_FPOPP = (1 << 24), /* pops x87 stack twice */
73 OPF_FSHIFT = (1 << 25), /* x87 stack shift is actually needed */
74 OPF_FINT = (1 << 26), /* integer float op arg */
165 // pseudo-ops for lib calls
184 // must be sorted (larger len must be further in enum)
193 #define MAX_EXITS 128
195 #define MAX_OPERANDS 3
198 #define OPR_INIT(type_, lmod_, reg_) \
199 { type_, lmod_, reg_, }
203 enum opr_lenmod lmod;
205 unsigned int is_ptr:1; // pointer in C
206 unsigned int is_array:1; // array in C
207 unsigned int type_from_var:1; // .. in header, sometimes wrong
208 unsigned int size_mismatch:1; // type override differs from C
209 unsigned int size_lt:1; // type override is larger than C
210 unsigned int segment:7; // had segment override (enum segment)
211 const struct parsed_proto *pp; // for OPT_LABEL
218 struct parsed_opr operand[MAX_OPERANDS];
221 unsigned char pfo_inv;
222 unsigned char operand_cnt;
223 unsigned char p_argnum; // arg push: altered before call arg #
224 unsigned char p_arggrp; // arg push: arg group # for above
225 unsigned char p_argpass;// arg push: arg of host func
226 short p_argnext;// arg push: same arg pushed elsewhere or -1
227 int regmask_src; // all referensed regs
229 int pfomask; // flagop: parsed_flag_op that can't be delayed
230 int cc_scratch; // scratch storage during analysis
231 int bt_i; // branch target for branches
232 struct parsed_data *btj;// branch targets for jumptables
233 struct parsed_proto *pp;// parsed_proto for OP_CALL
239 // on start: function/data type hint (sctproto)
241 // (OPF_CC) - points to one of (OPF_FLAGS) that affects cc op
242 // OP_PUSH - points to OP_POP in complex push/pop graph
243 // OP_POP - points to OP_PUSH in simple push/pop pair
244 // OP_FCOM - needed_status_word_bits | (is_z_check << 16)
248 enum opr_lenmod lmod;
255 enum opr_lenmod lmod;
269 struct label_ref *next;
273 IDAFA_BP_FRAME = (1 << 0),
274 IDAFA_LIB_FUNC = (1 << 1),
275 IDAFA_STATIC = (1 << 2),
276 IDAFA_NORETURN = (1 << 3),
277 IDAFA_THUNK = (1 << 4),
278 IDAFA_FPD = (1 << 5),
282 SCTFA_CLEAR_SF = (1 << 0), // clear stack frame
283 SCTFA_CLEAR_REGS = (1 << 1), // clear registers (mask)
305 // note: limited to 32k due to p_argnext
307 #define MAX_ARG_GRP 2
309 static struct parsed_op ops[MAX_OPS];
310 static struct parsed_equ *g_eqs;
312 static char *g_labels[MAX_OPS];
313 static struct label_ref g_label_refs[MAX_OPS];
314 static const struct parsed_proto *g_func_pp;
315 static struct parsed_data *g_func_pd;
316 static int g_func_pd_cnt;
317 static int g_func_lmods;
318 static char g_func[256];
319 static char g_comment[256];
320 static int g_bp_frame;
321 static int g_sp_frame;
322 static int g_stack_frame_used;
323 static int g_stack_fsz;
324 static int g_seh_found;
325 static int g_seh_size;
326 static int g_ida_func_attr;
327 static int g_sct_func_attr;
328 static int g_stack_clear_start; // in dwords
329 static int g_stack_clear_len;
330 static int g_regmask_init;
331 static int g_skip_func;
332 static int g_allow_regfunc;
333 static int g_allow_user_icall;
334 static int g_quiet_pp;
335 static int g_header_mode;
337 #define ferr(op_, fmt, ...) do { \
338 printf("%s:%d: error %u: [%s] '%s': " fmt, asmfn, (op_)->asmln, \
339 __LINE__, g_func, dump_op(op_), ##__VA_ARGS__); \
343 #define fnote(op_, fmt, ...) \
344 printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
345 dump_op(op_), ##__VA_ARGS__)
347 #define ferr_assert(op_, cond) do { \
348 if (!(cond)) ferr(op_, "assertion '%s' failed\n", #cond); \
351 const char *regs_r32[] = {
352 "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
353 // not r32, but list here for easy parsing and printing
354 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
355 "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"
357 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
358 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
359 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
365 xMM0, xMM1, xMM2, xMM3, // mmx
366 xMM4, xMM5, xMM6, xMM7,
367 xST0, xST1, xST2, xST3, // x87
368 xST4, xST5, xST6, xST7,
371 #define mxAX (1 << xAX)
372 #define mxCX (1 << xCX)
373 #define mxDX (1 << xDX)
374 #define mxSP (1 << xSP)
375 #define mxST0 (1 << xST0)
376 #define mxST1 (1 << xST1)
377 #define mxST1_0 (mxST1 | mxST0)
378 #define mxST7_2 (0xfc << xST0)
379 #define mxSTa (0xff << xST0)
381 // possible basic comparison types (without inversion)
382 enum parsed_flag_op {
386 PFO_BE, // 6 CF=1||ZF=1
390 PFO_LE, // e ZF=1||SF!=OF
393 #define PFOB_O (1 << PFO_O)
394 #define PFOB_C (1 << PFO_C)
395 #define PFOB_Z (1 << PFO_Z)
396 #define PFOB_S (1 << PFO_S)
398 static const char *parsed_flag_op_names[] = {
399 "o", "c", "z", "be", "s", "p", "l", "le"
402 static int char_array_i(const char *array[], size_t len, const char *s)
406 for (i = 0; i < len; i++)
413 static void printf_number(char *buf, size_t buf_size,
414 unsigned long number)
416 // output in C-friendly form
417 snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
420 static int check_segment_prefix(const char *s)
422 if (s[0] == 0 || s[1] != 's' || s[2] != ':')
426 case 'c': return SEG_CS;
427 case 'd': return SEG_DS;
428 case 's': return SEG_SS;
429 case 'e': return SEG_ES;
430 case 'f': return SEG_FS;
431 case 'g': return SEG_GS;
436 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
440 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
442 *reg_lmod = OPLM_QWORD;
446 *reg_lmod = OPLM_DWORD;
449 reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
451 *reg_lmod = OPLM_WORD;
454 reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
456 *reg_lmod = OPLM_BYTE;
459 reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
461 *reg_lmod = OPLM_BYTE;
468 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
470 enum opr_lenmod lmod;
483 while (my_isblank(*s))
485 for (; my_issep(*s); d++, s++)
487 while (my_isblank(*s))
491 // skip '?s:' prefixes
492 if (check_segment_prefix(s))
495 s = next_idt(w, sizeof(w), s);
500 reg = parse_reg(&lmod, w);
502 *regmask |= 1 << reg;
506 if ('0' <= w[0] && w[0] <= '9') {
507 number = parse_number(w, 0);
508 printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
512 // probably some label/identifier - pass
515 snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
519 strcpy(name, cvtbuf);
524 static int is_reg_in_str(const char *s)
528 if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
531 for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
532 if (!strncmp(s, regs_r32[i], 3))
538 static const char *parse_stack_el(const char *name, char *extra_reg,
539 int *base_val, int early_try)
541 const char *p, *p2, *s;
547 if (g_bp_frame || early_try)
550 if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
552 if (extra_reg != NULL) {
553 strncpy(extra_reg, name, 3);
558 if (IS_START(p, "ebp+")) {
562 if (p2 != NULL && is_reg_in_str(p)) {
563 if (extra_reg != NULL) {
564 strncpy(extra_reg, p, p2 - p);
565 extra_reg[p2 - p] = 0;
570 if (!('0' <= *p && *p <= '9'))
577 if (!IS_START(name, "esp+"))
583 if (is_reg_in_str(s)) {
584 if (extra_reg != NULL) {
585 strncpy(extra_reg, s, p - s);
586 extra_reg[p - s] = 0;
591 aerr("%s IDA stackvar not set?\n", __func__);
593 if (!('0' <= *s && *s <= '9')) {
594 aerr("%s IDA stackvar offset not set?\n", __func__);
597 if (s[0] == '0' && s[1] == 'x')
600 if (len < sizeof(buf) - 1) {
601 strncpy(buf, s, len);
604 val = strtol(buf, &endp, 16);
605 if (val == 0 || *endp != 0 || errno != 0) {
606 aerr("%s num parse fail for '%s'\n", __func__, buf);
615 if ('0' <= *p && *p <= '9')
618 if (base_val != NULL)
623 static int guess_lmod_from_name(struct parsed_opr *opr)
625 if (IS_START(opr->name, "dword_") || IS_START(opr->name, "off_")) {
626 opr->lmod = OPLM_DWORD;
629 if (IS_START(opr->name, "word_")) {
630 opr->lmod = OPLM_WORD;
633 if (IS_START(opr->name, "byte_")) {
634 opr->lmod = OPLM_BYTE;
637 if (IS_START(opr->name, "qword_")) {
638 opr->lmod = OPLM_QWORD;
644 static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
645 const struct parsed_type *c_type)
647 static const char *qword_types[] = {
648 "uint64_t", "int64_t", "__int64",
650 static const char *dword_types[] = {
651 "uint32_t", "int", "_DWORD", "UINT_PTR", "DWORD",
652 "WPARAM", "LPARAM", "UINT", "__int32",
653 "LONG", "HIMC", "BOOL", "size_t",
656 static const char *word_types[] = {
657 "uint16_t", "int16_t", "_WORD", "WORD",
658 "unsigned __int16", "__int16",
660 static const char *byte_types[] = {
661 "uint8_t", "int8_t", "char",
662 "unsigned __int8", "__int8", "BYTE", "_BYTE",
664 // structures.. deal the same as with _UNKNOWN for now
670 if (c_type->is_ptr) {
675 n = skip_type_mod(c_type->name);
677 for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
678 if (IS(n, dword_types[i])) {
684 for (i = 0; i < ARRAY_SIZE(word_types); i++) {
685 if (IS(n, word_types[i])) {
691 for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
692 if (IS(n, byte_types[i])) {
698 for (i = 0; i < ARRAY_SIZE(qword_types); i++) {
699 if (IS(n, qword_types[i])) {
708 static char *default_cast_to(char *buf, size_t buf_size,
709 struct parsed_opr *opr)
713 if (!opr->is_ptr || strchr(opr->name, '['))
715 if (opr->pp == NULL || opr->pp->type.name == NULL
718 snprintf(buf, buf_size, "%s", "(void *)");
722 snprintf(buf, buf_size, "(%s)", opr->pp->type.name);
726 static enum opr_type lmod_from_directive(const char *d)
730 else if (IS(d, "dw"))
732 else if (IS(d, "db"))
735 aerr("unhandled directive: '%s'\n", d);
739 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
745 *regmask |= 1 << reg;
748 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
751 static int parse_operand(struct parsed_opr *opr,
752 int *regmask, int *regmask_indirect,
753 char words[16][256], int wordc, int w, unsigned int op_flags)
755 const struct parsed_proto *pp = NULL;
756 enum opr_lenmod tmplmod;
757 unsigned long number;
765 aerr("parse_operand w %d, wordc %d\n", w, wordc);
769 for (i = w; i < wordc; i++) {
770 len = strlen(words[i]);
771 if (words[i][len - 1] == ',') {
772 words[i][len - 1] = 0;
778 wordc_in = wordc - w;
780 if ((op_flags & OPF_JMP) && wordc_in > 0
781 && !('0' <= words[w][0] && words[w][0] <= '9'))
783 const char *label = NULL;
785 if (wordc_in == 3 && !strncmp(words[w], "near", 4)
786 && IS(words[w + 1], "ptr"))
787 label = words[w + 2];
788 else if (wordc_in == 2 && IS(words[w], "short"))
789 label = words[w + 1];
790 else if (wordc_in == 1
791 && strchr(words[w], '[') == NULL
792 && parse_reg(&tmplmod, words[w]) < 0)
796 opr->type = OPT_LABEL;
797 ret = check_segment_prefix(label);
802 strcpy(opr->name, label);
808 if (IS(words[w + 1], "ptr")) {
809 if (IS(words[w], "dword"))
810 opr->lmod = OPLM_DWORD;
811 else if (IS(words[w], "word"))
812 opr->lmod = OPLM_WORD;
813 else if (IS(words[w], "byte"))
814 opr->lmod = OPLM_BYTE;
815 else if (IS(words[w], "qword"))
816 opr->lmod = OPLM_QWORD;
818 aerr("type parsing failed\n");
820 wordc_in = wordc - w;
825 if (IS(words[w], "offset")) {
826 opr->type = OPT_OFFSET;
827 opr->lmod = OPLM_DWORD;
828 strcpy(opr->name, words[w + 1]);
829 pp = proto_parse(g_fhdr, opr->name, 1);
832 if (IS(words[w], "(offset")) {
833 p = strchr(words[w + 1], ')');
835 aerr("parse of bracketed offset failed\n");
837 opr->type = OPT_OFFSET;
838 strcpy(opr->name, words[w + 1]);
844 aerr("parse_operand 1 word expected\n");
846 ret = check_segment_prefix(words[w]);
849 memmove(words[w], words[w] + 3, strlen(words[w]) - 2);
850 if (ret == SEG_FS && IS(words[w], "0"))
853 strcpy(opr->name, words[w]);
855 if (words[w][0] == '[') {
856 opr->type = OPT_REGMEM;
857 ret = sscanf(words[w], "[%[^]]]", opr->name);
859 aerr("[] parse failure\n");
861 parse_indmode(opr->name, regmask_indirect, 1);
862 if (opr->lmod == OPLM_UNSPEC
863 && parse_stack_el(opr->name, NULL, NULL, 1))
866 struct parsed_equ *eq =
867 equ_find(NULL, parse_stack_el(opr->name, NULL, NULL, 1), &i);
869 opr->lmod = eq->lmod;
871 // might be unaligned access
872 g_func_lmods |= 1 << OPLM_BYTE;
876 else if (strchr(words[w], '[')) {
878 p = strchr(words[w], '[');
879 opr->type = OPT_REGMEM;
880 parse_indmode(p, regmask_indirect, 0);
881 strncpy(buf, words[w], p - words[w]);
882 buf[p - words[w]] = 0;
883 pp = proto_parse(g_fhdr, buf, 1);
886 else if (('0' <= words[w][0] && words[w][0] <= '9')
887 || words[w][0] == '-')
889 number = parse_number(words[w], 0);
890 opr->type = OPT_CONST;
892 printf_number(opr->name, sizeof(opr->name), number);
896 ret = parse_reg(&tmplmod, opr->name);
898 setup_reg_opr(opr, ret, tmplmod, regmask);
902 // most likely var in data segment
903 opr->type = OPT_LABEL;
904 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
908 if (pp->is_fptr || pp->is_func) {
909 opr->lmod = OPLM_DWORD;
913 tmplmod = OPLM_UNSPEC;
914 if (!guess_lmod_from_c_type(&tmplmod, &pp->type))
915 anote("unhandled C type '%s' for '%s'\n",
916 pp->type.name, opr->name);
918 if (opr->lmod == OPLM_UNSPEC) {
920 opr->type_from_var = 1;
922 else if (opr->lmod != tmplmod) {
923 opr->size_mismatch = 1;
924 if (tmplmod < opr->lmod)
927 opr->is_ptr = pp->type.is_ptr;
929 opr->is_array = pp->type.is_array;
933 if (opr->lmod == OPLM_UNSPEC)
934 guess_lmod_from_name(opr);
938 static const struct {
943 { "repe", OPF_REP|OPF_REPZ },
944 { "repz", OPF_REP|OPF_REPZ },
945 { "repne", OPF_REP|OPF_REPNZ },
946 { "repnz", OPF_REP|OPF_REPNZ },
947 { "lock", OPF_LOCK }, // ignored for now..
950 #define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
952 static const struct {
955 unsigned short minopr;
956 unsigned short maxopr;
959 unsigned char pfo_inv;
961 { "nop", OP_NOP, 0, 0, 0 },
962 { "push", OP_PUSH, 1, 1, 0 },
963 { "pop", OP_POP, 1, 1, OPF_DATA },
964 { "pusha",OP_PUSHA, 0, 0, 0 },
965 { "popa", OP_POPA, 0, 0, OPF_DATA },
966 { "leave",OP_LEAVE, 0, 0, OPF_DATA },
967 { "mov" , OP_MOV, 2, 2, OPF_DATA },
968 { "lea", OP_LEA, 2, 2, OPF_DATA },
969 { "movzx",OP_MOVZX, 2, 2, OPF_DATA },
970 { "movsx",OP_MOVSX, 2, 2, OPF_DATA },
971 { "xchg", OP_XCHG, 2, 2, OPF_DATA },
972 { "not", OP_NOT, 1, 1, OPF_DATA },
973 { "xlat", OP_XLAT, 0, 0, OPF_DATA },
974 { "cdq", OP_CDQ, 0, 0, OPF_DATA },
975 { "bswap",OP_BSWAP, 1, 1, OPF_DATA },
976 { "lodsb",OP_LODS, 0, 0, OPF_DATA },
977 { "lodsw",OP_LODS, 0, 0, OPF_DATA },
978 { "lodsd",OP_LODS, 0, 0, OPF_DATA },
979 { "stosb",OP_STOS, 0, 0, OPF_DATA },
980 { "stosw",OP_STOS, 0, 0, OPF_DATA },
981 { "stosd",OP_STOS, 0, 0, OPF_DATA },
982 { "movsb",OP_MOVS, 0, 0, OPF_DATA },
983 { "movsw",OP_MOVS, 0, 0, OPF_DATA },
984 { "movsd",OP_MOVS, 0, 0, OPF_DATA },
985 { "cmpsb",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
986 { "cmpsw",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
987 { "cmpsd",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
988 { "scasb",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
989 { "scasw",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
990 { "scasd",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
991 { "std", OP_STD, 0, 0, OPF_DATA }, // special flag
992 { "cld", OP_CLD, 0, 0, OPF_DATA },
993 { "add", OP_ADD, 2, 2, OPF_DATA|OPF_FLAGS },
994 { "sub", OP_SUB, 2, 2, OPF_DATA|OPF_FLAGS },
995 { "and", OP_AND, 2, 2, OPF_DATA|OPF_FLAGS },
996 { "or", OP_OR, 2, 2, OPF_DATA|OPF_FLAGS },
997 { "xor", OP_XOR, 2, 2, OPF_DATA|OPF_FLAGS },
998 { "shl", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
999 { "shr", OP_SHR, 2, 2, OPF_DATA|OPF_FLAGS },
1000 { "sal", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
1001 { "sar", OP_SAR, 2, 2, OPF_DATA|OPF_FLAGS },
1002 { "shld", OP_SHLD, 3, 3, OPF_DATA|OPF_FLAGS },
1003 { "shrd", OP_SHRD, 3, 3, OPF_DATA|OPF_FLAGS },
1004 { "rol", OP_ROL, 2, 2, OPF_DATA|OPF_FLAGS },
1005 { "ror", OP_ROR, 2, 2, OPF_DATA|OPF_FLAGS },
1006 { "rcl", OP_RCL, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1007 { "rcr", OP_RCR, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1008 { "adc", OP_ADC, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1009 { "sbb", OP_SBB, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1010 { "bsf", OP_BSF, 2, 2, OPF_DATA|OPF_FLAGS },
1011 { "bsr", OP_BSR, 2, 2, OPF_DATA|OPF_FLAGS },
1012 { "inc", OP_INC, 1, 1, OPF_DATA|OPF_FLAGS },
1013 { "dec", OP_DEC, 1, 1, OPF_DATA|OPF_FLAGS },
1014 { "neg", OP_NEG, 1, 1, OPF_DATA|OPF_FLAGS },
1015 { "mul", OP_MUL, 1, 1, OPF_DATA|OPF_FLAGS },
1016 { "imul", OP_IMUL, 1, 3, OPF_DATA|OPF_FLAGS },
1017 { "div", OP_DIV, 1, 1, OPF_DATA|OPF_FLAGS },
1018 { "idiv", OP_IDIV, 1, 1, OPF_DATA|OPF_FLAGS },
1019 { "test", OP_TEST, 2, 2, OPF_FLAGS },
1020 { "cmp", OP_CMP, 2, 2, OPF_FLAGS },
1021 { "retn", OP_RET, 0, 1, OPF_TAIL },
1022 { "call", OP_CALL, 1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
1023 { "jmp", OP_JMP, 1, 1, OPF_JMP },
1024 { "jecxz",OP_JECXZ, 1, 1, OPF_JMP|OPF_CJMP },
1025 { "loop", OP_LOOP, 1, 1, OPF_JMP|OPF_CJMP|OPF_DATA },
1026 { "jo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 0 }, // 70 OF=1
1027 { "jno", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 1 }, // 71 OF=0
1028 { "jc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72 CF=1
1029 { "jb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72
1030 { "jnc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73 CF=0
1031 { "jnb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1032 { "jae", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1033 { "jz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74 ZF=1
1034 { "je", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74
1035 { "jnz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75 ZF=0
1036 { "jne", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75
1037 { "jbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76 CF=1||ZF=1
1038 { "jna", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76
1039 { "ja", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77 CF=0&&ZF=0
1040 { "jnbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77
1041 { "js", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 0 }, // 78 SF=1
1042 { "jns", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 1 }, // 79 SF=0
1043 { "jp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a PF=1
1044 { "jpe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a
1045 { "jnp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b PF=0
1046 { "jpo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b
1047 { "jl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c SF!=OF
1048 { "jnge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c
1049 { "jge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d SF=OF
1050 { "jnl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d
1051 { "jle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e ZF=1||SF!=OF
1052 { "jng", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e
1053 { "jg", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f ZF=0&&SF=OF
1054 { "jnle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f
1055 { "seto", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 0 },
1056 { "setno", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 1 },
1057 { "setc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1058 { "setb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1059 { "setnc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1060 { "setae", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1061 { "setnb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1062 { "setz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1063 { "sete", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1064 { "setnz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1065 { "setne", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1066 { "setbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1067 { "setna", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1068 { "seta", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1069 { "setnbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1070 { "sets", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 0 },
1071 { "setns", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 1 },
1072 { "setp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1073 { "setpe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1074 { "setnp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1075 { "setpo", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1076 { "setl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1077 { "setnge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1078 { "setge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1079 { "setnl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1080 { "setle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1081 { "setng", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1082 { "setg", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1083 { "setnle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1085 { "fld", OP_FLD, 1, 1, OPF_FPUSH },
1086 { "fild", OP_FILD, 1, 1, OPF_FPUSH|OPF_FINT },
1087 { "fld1", OP_FLDc, 0, 0, OPF_FPUSH },
1088 { "fldl2t", OP_FLDc, 0, 0, OPF_FPUSH },
1089 { "fldl2e", OP_FLDc, 0, 0, OPF_FPUSH },
1090 { "fldpi", OP_FLDc, 0, 0, OPF_FPUSH },
1091 { "fldlg2", OP_FLDc, 0, 0, OPF_FPUSH },
1092 { "fldln2", OP_FLDc, 0, 0, OPF_FPUSH },
1093 { "fldz", OP_FLDc, 0, 0, OPF_FPUSH },
1094 { "fst", OP_FST, 1, 1, 0 },
1095 { "fstp", OP_FST, 1, 1, OPF_FPOP },
1096 { "fist", OP_FIST, 1, 1, OPF_FINT },
1097 { "fistp", OP_FIST, 1, 1, OPF_FPOP|OPF_FINT },
1098 { "fadd", OP_FADD, 0, 2, 0 },
1099 { "faddp", OP_FADD, 0, 2, OPF_FPOP },
1100 { "fdiv", OP_FDIV, 0, 2, 0 },
1101 { "fdivp", OP_FDIV, 0, 2, OPF_FPOP },
1102 { "fmul", OP_FMUL, 0, 2, 0 },
1103 { "fmulp", OP_FMUL, 0, 2, OPF_FPOP },
1104 { "fsub", OP_FSUB, 0, 2, 0 },
1105 { "fsubp", OP_FSUB, 0, 2, OPF_FPOP },
1106 { "fdivr", OP_FDIVR, 0, 2, 0 },
1107 { "fdivrp", OP_FDIVR, 0, 2, OPF_FPOP },
1108 { "fsubr", OP_FSUBR, 0, 2, 0 },
1109 { "fsubrp", OP_FSUBR, 0, 2, OPF_FPOP },
1110 { "fiadd", OP_FIADD, 1, 1, OPF_FINT },
1111 { "fidiv", OP_FIDIV, 1, 1, OPF_FINT },
1112 { "fimul", OP_FIMUL, 1, 1, OPF_FINT },
1113 { "fisub", OP_FISUB, 1, 1, OPF_FINT },
1114 { "fidivr", OP_FIDIVR, 1, 1, OPF_FINT },
1115 { "fisubr", OP_FISUBR, 1, 1, OPF_FINT },
1116 { "fcom", OP_FCOM, 0, 1, 0 },
1117 { "fcomp", OP_FCOM, 0, 1, OPF_FPOP },
1118 { "fcompp", OP_FCOM, 0, 0, OPF_FPOPP },
1119 { "fucom", OP_FCOM, 0, 1, 0 },
1120 { "fucomp", OP_FCOM, 0, 1, OPF_FPOP },
1121 { "fucompp",OP_FCOM, 0, 0, OPF_FPOPP },
1122 { "fnstsw", OP_FNSTSW, 1, 1, OPF_DATA },
1123 { "fchs", OP_FCHS, 0, 0, 0 },
1124 { "fcos", OP_FCOS, 0, 0, 0 },
1125 { "fpatan", OP_FPATAN, 0, 0, OPF_FPOP },
1126 { "fptan", OP_FPTAN, 0, 0, OPF_FPUSH },
1127 { "fsin", OP_FSIN, 0, 0, 0 },
1128 { "fsqrt", OP_FSQRT, 0, 0, 0 },
1129 { "fxch", OP_FXCH, 1, 1, 0 },
1130 { "fyl2x", OP_FYL2X, 0, 0, OPF_FPOP },
1132 { "emms", OP_EMMS, 0, 0, OPF_DATA },
1133 { "movq", OP_MOV, 2, 2, OPF_DATA },
1134 // pseudo-ops for lib calls
1135 { "_allshl",OPP_ALLSHL },
1136 { "_allshr",OPP_ALLSHR },
1137 { "_ftol", OPP_FTOL },
1138 { "_CIpow", OPP_CIPOW },
1139 { "abort", OPP_ABORT },
1144 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
1146 enum opr_lenmod lmod = OPLM_UNSPEC;
1147 int prefix_flags = 0;
1155 for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
1156 if (IS(words[w], pref_table[i].name)) {
1157 prefix_flags = pref_table[i].flags;
1164 aerr("lone prefix: '%s'\n", words[0]);
1169 for (i = 0; i < ARRAY_SIZE(op_table); i++) {
1170 if (IS(words[w], op_table[i].name))
1174 if (i == ARRAY_SIZE(op_table)) {
1176 aerr("unhandled op: '%s'\n", words[0]);
1181 op->op = op_table[i].op;
1182 op->flags = op_table[i].flags | prefix_flags;
1183 op->pfo = op_table[i].pfo;
1184 op->pfo_inv = op_table[i].pfo_inv;
1185 op->regmask_src = op->regmask_dst = 0;
1188 if (op->op == OP_UD2)
1191 for (opr = 0; opr < op_table[i].maxopr; opr++) {
1192 if (opr >= op_table[i].minopr && w >= wordc)
1195 regmask = regmask_ind = 0;
1196 w = parse_operand(&op->operand[opr], ®mask, ®mask_ind,
1197 words, wordc, w, op->flags);
1199 if (opr == 0 && (op->flags & OPF_DATA))
1200 op->regmask_dst = regmask;
1202 op->regmask_src |= regmask;
1203 op->regmask_src |= regmask_ind;
1205 if (op->operand[opr].lmod != OPLM_UNSPEC)
1206 g_func_lmods |= 1 << op->operand[opr].lmod;
1210 aerr("parse_op %s incomplete: %d/%d\n",
1211 words[0], w, wordc);
1214 op->operand_cnt = opr;
1215 if (!strncmp(op_table[i].name, "set", 3))
1216 op->operand[0].lmod = OPLM_BYTE;
1219 // first operand is not dst
1222 op->regmask_src |= op->regmask_dst;
1223 op->regmask_dst = 0;
1226 // first operand is src too
1239 op->regmask_src |= op->regmask_dst;
1244 op->regmask_src |= op->regmask_dst;
1245 op->regmask_dst |= op->regmask_src;
1251 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1252 && op->operand[0].lmod == op->operand[1].lmod
1253 && op->operand[0].reg == op->operand[1].reg
1254 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1256 op->regmask_src = 0;
1259 op->regmask_src |= op->regmask_dst;
1262 // ops with implicit argumets
1264 op->operand_cnt = 2;
1265 setup_reg_opr(&op->operand[0], xAX, OPLM_BYTE, &op->regmask_src);
1266 op->regmask_dst = op->regmask_src;
1267 setup_reg_opr(&op->operand[1], xBX, OPLM_DWORD, &op->regmask_src);
1271 op->operand_cnt = 2;
1272 setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
1273 setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
1279 if (words[op_w][4] == 'b')
1281 else if (words[op_w][4] == 'w')
1283 else if (words[op_w][4] == 'd')
1286 op->regmask_src = 0;
1287 setup_reg_opr(&op->operand[j++], op->op == OP_LODS ? xSI : xDI,
1288 OPLM_DWORD, &op->regmask_src);
1289 op->regmask_dst = op->regmask_src;
1290 setup_reg_opr(&op->operand[j++], xAX, lmod,
1291 op->op == OP_LODS ? &op->regmask_dst : &op->regmask_src);
1292 if (op->flags & OPF_REP) {
1293 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1294 op->regmask_dst |= 1 << xCX;
1296 op->operand_cnt = j;
1301 if (words[op_w][4] == 'b')
1303 else if (words[op_w][4] == 'w')
1305 else if (words[op_w][4] == 'd')
1308 op->regmask_src = 0;
1309 // note: lmod is not correct, don't have where to place it
1310 setup_reg_opr(&op->operand[j++], xDI, lmod, &op->regmask_src);
1311 setup_reg_opr(&op->operand[j++], xSI, OPLM_DWORD, &op->regmask_src);
1312 if (op->flags & OPF_REP)
1313 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1314 op->operand_cnt = j;
1315 op->regmask_dst = op->regmask_src;
1319 op->regmask_dst = 1 << xCX;
1322 op->operand_cnt = 2;
1323 op->regmask_src = 1 << xCX;
1324 op->operand[1].type = OPT_REG;
1325 op->operand[1].reg = xCX;
1326 op->operand[1].lmod = OPLM_DWORD;
1330 if (op->operand_cnt == 2) {
1331 if (op->operand[0].type != OPT_REG)
1332 aerr("reg expected\n");
1333 op->regmask_src |= 1 << op->operand[0].reg;
1335 if (op->operand_cnt != 1)
1340 if (op->operand[0].lmod == OPLM_UNSPEC)
1341 op->operand[0].lmod = OPLM_DWORD;
1342 op->regmask_src = mxAX | op->regmask_dst;
1343 op->regmask_dst = mxAX;
1344 if (op->operand[0].lmod != OPLM_BYTE)
1345 op->regmask_dst |= mxDX;
1350 // we could set up operands for edx:eax, but there is no real need to
1351 // (see is_opr_modified())
1352 if (op->operand[0].lmod == OPLM_UNSPEC)
1353 op->operand[0].lmod = OPLM_DWORD;
1354 op->regmask_src = mxAX | op->regmask_dst;
1355 op->regmask_dst = mxAX;
1356 if (op->operand[0].lmod != OPLM_BYTE) {
1357 op->regmask_src |= mxDX;
1358 op->regmask_dst |= mxDX;
1367 op->regmask_src |= op->regmask_dst;
1368 if (op->operand[1].lmod == OPLM_UNSPEC)
1369 op->operand[1].lmod = OPLM_BYTE;
1374 op->regmask_src |= op->regmask_dst;
1375 if (op->operand[2].lmod == OPLM_UNSPEC)
1376 op->operand[2].lmod = OPLM_BYTE;
1380 op->regmask_src |= op->regmask_dst;
1381 op->regmask_dst = 0;
1382 if (op->operand[0].lmod == OPLM_UNSPEC
1383 && (op->operand[0].type == OPT_CONST
1384 || op->operand[0].type == OPT_OFFSET
1385 || op->operand[0].type == OPT_LABEL))
1386 op->operand[0].lmod = OPLM_DWORD;
1392 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1393 && op->operand[0].lmod == op->operand[1].lmod
1394 && op->operand[0].reg == op->operand[1].reg
1395 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1397 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1398 op->regmask_src = op->regmask_dst = 0;
1403 if (op->operand[0].type == OPT_REG
1404 && op->operand[1].type == OPT_REGMEM)
1407 snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1408 if (IS(buf, op->operand[1].name))
1409 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1414 // needed because of OPF_DATA
1415 op->regmask_src = op->regmask_dst;
1416 // trashed regs must be explicitly detected later
1417 op->regmask_dst = 0;
1421 op->regmask_dst = (1 << xBP) | (1 << xSP);
1422 op->regmask_src = 1 << xBP;
1427 op->regmask_dst |= mxST0;
1431 op->regmask_dst |= mxST0;
1432 if (IS(words[op_w] + 3, "1"))
1433 op->operand[0].val = X87_CONST_1;
1434 else if (IS(words[op_w] + 3, "l2t"))
1435 op->operand[0].val = X87_CONST_L2T;
1436 else if (IS(words[op_w] + 3, "l2e"))
1437 op->operand[0].val = X87_CONST_L2E;
1438 else if (IS(words[op_w] + 3, "pi"))
1439 op->operand[0].val = X87_CONST_PI;
1440 else if (IS(words[op_w] + 3, "lg2"))
1441 op->operand[0].val = X87_CONST_LG2;
1442 else if (IS(words[op_w] + 3, "ln2"))
1443 op->operand[0].val = X87_CONST_LN2;
1444 else if (IS(words[op_w] + 3, "z"))
1445 op->operand[0].val = X87_CONST_Z;
1447 aerr("fld what?\n");
1452 op->regmask_src |= mxST0;
1461 op->regmask_src |= mxST0;
1462 if (op->operand_cnt == 2)
1463 op->regmask_src |= op->regmask_dst;
1464 else if (op->operand_cnt == 1) {
1465 memcpy(&op->operand[1], &op->operand[0], sizeof(op->operand[1]));
1466 op->operand[0].type = OPT_REG;
1467 op->operand[0].lmod = OPLM_QWORD;
1468 op->operand[0].reg = xST0;
1469 op->regmask_dst |= mxST0;
1472 // IDA doesn't use this
1473 aerr("no operands?\n");
1487 op->regmask_src |= mxST0;
1488 op->regmask_dst |= mxST0;
1493 op->regmask_src |= mxST0 | mxST1;
1494 op->regmask_dst |= mxST0;
1502 op->regmask_src |= mxST0;
1503 if (op->operand_cnt == 0) {
1504 op->operand_cnt = 1;
1505 op->operand[0].type = OPT_REG;
1506 op->operand[0].lmod = OPLM_QWORD;
1507 op->operand[0].reg = xST1;
1508 op->regmask_src |= mxST1;
1516 if (op->operand[0].type == OPT_REG
1517 && op->operand[1].type == OPT_CONST)
1519 struct parsed_opr *op1 = &op->operand[1];
1520 if ((op->op == OP_AND && op1->val == 0)
1523 || (op->operand[0].lmod == OPLM_WORD && op1->val == 0xffff)
1524 || (op->operand[0].lmod == OPLM_BYTE && op1->val == 0xff))))
1526 op->regmask_src = 0;
1531 static const char *op_name(struct parsed_op *po)
1533 static char buf[16];
1537 if (po->op == OP_JCC || po->op == OP_SCC) {
1539 *p++ = (po->op == OP_JCC) ? 'j' : 's';
1542 strcpy(p, parsed_flag_op_names[po->pfo]);
1546 for (i = 0; i < ARRAY_SIZE(op_table); i++)
1547 if (op_table[i].op == po->op)
1548 return op_table[i].name;
1554 static const char *dump_op(struct parsed_op *po)
1556 static char out[128];
1563 snprintf(out, sizeof(out), "%s", op_name(po));
1564 for (i = 0; i < po->operand_cnt; i++) {
1568 snprintf(p, sizeof(out) - (p - out),
1569 po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1570 po->operand[i].name);
1576 static const char *lmod_type_u(struct parsed_op *po,
1577 enum opr_lenmod lmod)
1589 ferr(po, "invalid lmod: %d\n", lmod);
1590 return "(_invalid_)";
1594 static const char *lmod_cast_u(struct parsed_op *po,
1595 enum opr_lenmod lmod)
1607 ferr(po, "invalid lmod: %d\n", lmod);
1608 return "(_invalid_)";
1612 static const char *lmod_cast_u_ptr(struct parsed_op *po,
1613 enum opr_lenmod lmod)
1625 ferr(po, "invalid lmod: %d\n", lmod);
1626 return "(_invalid_)";
1630 static const char *lmod_cast_s(struct parsed_op *po,
1631 enum opr_lenmod lmod)
1643 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1644 return "(_invalid_)";
1648 static const char *lmod_cast(struct parsed_op *po,
1649 enum opr_lenmod lmod, int is_signed)
1652 lmod_cast_s(po, lmod) :
1653 lmod_cast_u(po, lmod);
1656 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1668 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1673 static const char *opr_name(struct parsed_op *po, int opr_num)
1675 if (opr_num >= po->operand_cnt)
1676 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1677 return po->operand[opr_num].name;
1680 static unsigned int opr_const(struct parsed_op *po, int opr_num)
1682 if (opr_num >= po->operand_cnt)
1683 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1684 if (po->operand[opr_num].type != OPT_CONST)
1685 ferr(po, "opr %d: const expected\n", opr_num);
1686 return po->operand[opr_num].val;
1689 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1691 if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
1692 ferr(po, "invalid reg: %d\n", popr->reg);
1693 return regs_r32[popr->reg];
1696 static int check_simple_cast(const char *cast, int *bits, int *is_signed)
1698 if (IS_START(cast, "(s8)") || IS_START(cast, "(u8)"))
1700 else if (IS_START(cast, "(s16)") || IS_START(cast, "(u16)"))
1702 else if (IS_START(cast, "(s32)") || IS_START(cast, "(u32)"))
1704 else if (IS_START(cast, "(s64)") || IS_START(cast, "(u64)"))
1709 *is_signed = cast[1] == 's' ? 1 : 0;
1713 static int check_deref_cast(const char *cast, int *bits)
1715 if (IS_START(cast, "*(u8 *)"))
1717 else if (IS_START(cast, "*(u16 *)"))
1719 else if (IS_START(cast, "*(u32 *)"))
1721 else if (IS_START(cast, "*(u64 *)"))
1729 // cast1 is the "final" cast
1730 static const char *simplify_cast(const char *cast1, const char *cast2)
1732 static char buf[256];
1740 if (IS(cast1, cast2))
1743 if (check_simple_cast(cast1, &bits1, &s1) == 0
1744 && check_simple_cast(cast2, &bits2, &s2) == 0)
1749 if (check_simple_cast(cast1, &bits1, &s1) == 0
1750 && check_deref_cast(cast2, &bits2) == 0)
1752 if (bits1 == bits2) {
1753 snprintf(buf, sizeof(buf), "*(%c%d *)", s1 ? 's' : 'u', bits1);
1758 if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1761 snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1765 static const char *simplify_cast_num(const char *cast, unsigned int val)
1767 if (IS(cast, "(u8)") && val < 0x100)
1769 if (IS(cast, "(s8)") && val < 0x80)
1771 if (IS(cast, "(u16)") && val < 0x10000)
1773 if (IS(cast, "(s16)") && val < 0x8000)
1775 if (IS(cast, "(s32)") && val < 0x80000000)
1781 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1790 namelen = strlen(name);
1792 p = strpbrk(name, "+-");
1796 ferr(po, "equ parse failed for '%s'\n", name);
1799 *extra_offs = strtol(p, &endp, 16);
1800 if (*endp != 0 || errno != 0)
1801 ferr(po, "equ parse failed for '%s'\n", name);
1804 for (i = 0; i < g_eqcnt; i++)
1805 if (strncmp(g_eqs[i].name, name, namelen) == 0
1806 && g_eqs[i].name[namelen] == 0)
1810 ferr(po, "unresolved equ name: '%s'\n", name);
1817 static int is_stack_access(struct parsed_op *po,
1818 const struct parsed_opr *popr)
1820 return (parse_stack_el(popr->name, NULL, NULL, 0)
1821 || (g_bp_frame && !(po->flags & OPF_EBP_S)
1822 && IS_START(popr->name, "ebp")));
1825 static void parse_stack_access(struct parsed_op *po,
1826 const char *name, char *ofs_reg, int *offset_out,
1827 int *stack_ra_out, const char **bp_arg_out, int is_lea)
1829 const char *bp_arg = "";
1830 const char *p = NULL;
1831 struct parsed_equ *eq;
1838 if (IS_START(name, "ebp-")
1839 || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1842 if (IS_START(p, "0x"))
1845 offset = strtoul(p, &endp, 16);
1848 if (*endp != 0 || errno != 0)
1849 ferr(po, "ebp- parse of '%s' failed\n", name);
1852 bp_arg = parse_stack_el(name, ofs_reg, NULL, 0);
1853 eq = equ_find(po, bp_arg, &offset);
1855 ferr(po, "detected but missing eq\n");
1856 offset += eq->offset;
1859 if (!strncmp(name, "ebp", 3))
1862 // yes it sometimes LEAs ra for compares..
1863 if (!is_lea && ofs_reg[0] == 0
1864 && stack_ra <= offset && offset < stack_ra + 4)
1866 ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1869 *offset_out = offset;
1871 *stack_ra_out = stack_ra;
1873 *bp_arg_out = bp_arg;
1876 static int parse_stack_esp_offset(struct parsed_op *po,
1877 const char *name, int *offset_out)
1879 char ofs_reg[16] = { 0, };
1880 struct parsed_equ *eq;
1886 if (strstr(name, "esp") == NULL)
1888 bp_arg = parse_stack_el(name, ofs_reg, &base_val, 0);
1889 if (bp_arg == NULL) {
1890 // just plain offset?
1891 if (!IS_START(name, "esp+"))
1894 offset = strtol(name + 4, &endp, 0);
1895 if (endp == NULL || *endp != 0 || errno != 0)
1897 *offset_out = offset;
1901 if (ofs_reg[0] != 0)
1903 eq = equ_find(po, bp_arg, &offset);
1905 ferr(po, "detected but missing eq\n");
1906 offset += eq->offset;
1907 *offset_out = base_val + offset;
1911 static int stack_frame_access(struct parsed_op *po,
1912 struct parsed_opr *popr, char *buf, size_t buf_size,
1913 const char *name, const char *cast, int is_src, int is_lea)
1915 enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1916 const char *prefix = "";
1917 const char *bp_arg = NULL;
1918 char ofs_reg[16] = { 0, };
1919 int i, arg_i, arg_s;
1926 if (g_bp_frame && (po->flags & OPF_EBP_S)
1927 && !(po->regmask_src & mxSP))
1928 ferr(po, "stack_frame_access while ebp is scratch\n");
1930 parse_stack_access(po, name, ofs_reg, &offset,
1931 &stack_ra, &bp_arg, is_lea);
1933 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1935 if (offset > stack_ra)
1937 arg_i = (offset - stack_ra - 4) / 4;
1938 if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1940 if (g_func_pp->is_vararg
1941 && arg_i == g_func_pp->argc_stack && is_lea)
1943 // should be va_list
1946 snprintf(buf, buf_size, "%sap", cast);
1949 ferr(po, "offset %d (%s,%d) doesn't map to any arg\n",
1950 offset, bp_arg, arg_i);
1952 if (ofs_reg[0] != 0)
1953 ferr(po, "offset reg on arg access?\n");
1955 for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1956 if (g_func_pp->arg[i].reg != NULL)
1962 if (i == g_func_pp->argc)
1963 ferr(po, "arg %d not in prototype?\n", arg_i);
1965 popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
1972 ferr(po, "lea/byte to arg?\n");
1973 if (is_src && (offset & 3) == 0)
1974 snprintf(buf, buf_size, "%sa%d",
1975 simplify_cast(cast, "(u8)"), i + 1);
1977 snprintf(buf, buf_size, "%sBYTE%d(a%d)",
1978 cast, offset & 3, i + 1);
1983 ferr(po, "lea/word to arg?\n");
1988 ferr(po, "problematic arg store\n");
1989 snprintf(buf, buf_size, "%s((char *)&a%d + 1)",
1990 simplify_cast(cast, "*(u16 *)"), i + 1);
1993 ferr(po, "unaligned arg word load\n");
1995 else if (is_src && (offset & 2) == 0)
1996 snprintf(buf, buf_size, "%sa%d",
1997 simplify_cast(cast, "(u16)"), i + 1);
1999 snprintf(buf, buf_size, "%s%sWORD(a%d)",
2000 cast, (offset & 2) ? "HI" : "LO", i + 1);
2012 snprintf(buf, buf_size, "(u32)&a%d + %d",
2015 ferr(po, "unaligned arg store\n");
2017 // mov edx, [ebp+arg_4+2]; movsx ecx, dx
2018 snprintf(buf, buf_size, "%s(a%d >> %d)",
2019 prefix, i + 1, (offset & 3) * 8);
2023 snprintf(buf, buf_size, "%s%sa%d",
2024 prefix, is_lea ? "&" : "", i + 1);
2029 ferr_assert(po, !(offset & 7));
2032 snprintf(buf, buf_size, "%s%sa%d",
2033 prefix, is_lea ? "&" : "", i + 1);
2037 ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
2041 strcat(g_comment, " unaligned");
2044 guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
2045 if (tmp_lmod != OPLM_DWORD
2046 && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
2047 < lmod_bytes(po, popr->lmod) + (offset & 3))))
2049 ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
2050 i + 1, offset, g_func_pp->arg[i].type.name);
2052 // can't check this because msvc likes to reuse
2053 // arg space for scratch..
2054 //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
2055 // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
2059 if (g_stack_fsz == 0)
2060 ferr(po, "stack var access without stackframe\n");
2061 g_stack_frame_used = 1;
2063 sf_ofs = g_stack_fsz + offset;
2064 if (ofs_reg[0] == 0 && (offset > 0 || sf_ofs < 0))
2065 ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
2075 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2076 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2080 if ((sf_ofs & 1) || ofs_reg[0] != 0) {
2081 // known unaligned or possibly unaligned
2082 strcat(g_comment, " unaligned");
2084 prefix = "*(u16 *)&";
2085 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2086 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2089 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
2093 if ((sf_ofs & 3) || ofs_reg[0] != 0) {
2094 // known unaligned or possibly unaligned
2095 strcat(g_comment, " unaligned");
2097 prefix = "*(u32 *)&";
2098 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2099 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2102 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
2106 ferr_assert(po, !(sf_ofs & 7));
2107 ferr_assert(po, ofs_reg[0] == 0);
2108 // only used for x87 int64/float, float sets is_lea
2109 if (!is_lea && (po->flags & OPF_FINT))
2110 prefix = "*(s64 *)&";
2111 snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
2115 ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
2122 static void check_func_pp(struct parsed_op *po,
2123 const struct parsed_proto *pp, const char *pfx)
2125 enum opr_lenmod tmp_lmod;
2129 if (pp->argc_reg != 0) {
2130 if (!g_allow_user_icall && !pp->is_fastcall) {
2131 pp_print(buf, sizeof(buf), pp);
2132 ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
2134 if (pp->argc_stack > 0 && pp->argc_reg != 2)
2135 ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
2136 pfx, pp->argc_reg, pp->argc_stack);
2139 // fptrs must use 32bit args, callsite might have no information and
2140 // lack a cast to smaller types, which results in incorrectly masked
2141 // args passed (callee may assume masked args, it does on ARM)
2142 if (!pp->is_osinc) {
2143 for (i = 0; i < pp->argc; i++) {
2144 ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
2145 if (ret && tmp_lmod != OPLM_DWORD)
2146 ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
2147 i + 1, pp->arg[i].type.name);
2152 static const char *check_label_read_ref(struct parsed_op *po,
2153 const char *name, int *is_import)
2155 const struct parsed_proto *pp;
2157 pp = proto_parse(g_fhdr, name, 0);
2159 ferr(po, "proto_parse failed for ref '%s'\n", name);
2162 check_func_pp(po, pp, "ref");
2164 if (is_import != NULL)
2165 *is_import = pp->is_import;
2170 static void check_opr(struct parsed_op *po, struct parsed_opr *popr)
2172 if (popr->segment == SEG_FS)
2173 ferr(po, "fs: used\n");
2174 if (popr->segment == SEG_GS)
2175 ferr(po, "gs: used\n");
2178 static char *out_src_opr(char *buf, size_t buf_size,
2179 struct parsed_op *po, struct parsed_opr *popr, const char *cast,
2182 char tmp1[256], tmp2[256];
2189 check_opr(po, popr);
2194 switch (popr->type) {
2197 ferr(po, "lea from reg?\n");
2199 switch (popr->lmod) {
2201 snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2204 snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2207 snprintf(buf, buf_size, "%s%s",
2208 simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2211 if (popr->name[1] == 'h') // XXX..
2212 snprintf(buf, buf_size, "%s(%s >> 8)",
2213 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2215 snprintf(buf, buf_size, "%s%s",
2216 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2219 ferr(po, "invalid src lmod: %d\n", popr->lmod);
2224 if (is_stack_access(po, popr)) {
2225 stack_frame_access(po, popr, buf, buf_size,
2226 popr->name, cast, 1, is_lea);
2230 strcpy(expr, popr->name);
2231 if (strchr(expr, '[')) {
2232 // special case: '[' can only be left for label[reg] form
2233 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2235 ferr(po, "parse failure for '%s'\n", expr);
2236 if (tmp1[0] == '(') {
2237 // (off_4FFF50+3)[eax]
2238 p = strchr(tmp1 + 1, ')');
2239 if (p == NULL || p[1] != 0)
2240 ferr(po, "parse failure (2) for '%s'\n", expr);
2242 memmove(tmp1, tmp1 + 1, strlen(tmp1));
2244 snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2247 // XXX: do we need more parsing?
2249 snprintf(buf, buf_size, "%s", expr);
2253 snprintf(buf, buf_size, "%s(%s)",
2254 simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2258 name = check_label_read_ref(po, popr->name, &is_import);
2260 // for imported data, asm is loading the offset
2263 if (cast[0] == 0 && popr->is_ptr)
2267 snprintf(buf, buf_size, "(u32)&%s", name);
2268 else if (popr->size_lt)
2269 snprintf(buf, buf_size, "%s%s%s%s", cast,
2270 lmod_cast_u_ptr(po, popr->lmod),
2271 popr->is_array ? "" : "&", name);
2273 snprintf(buf, buf_size, "%s%s%s", cast, name,
2274 popr->is_array ? "[0]" : "");
2279 name = check_label_read_ref(po, popr->name, NULL);
2283 ferr(po, "lea an offset?\n");
2284 snprintf(buf, buf_size, "%s&%s", cast, name);
2289 ferr(po, "lea from const?\n");
2291 printf_number(tmp1, sizeof(tmp1), popr->val);
2292 if (popr->val == 0 && strchr(cast, '*'))
2293 snprintf(buf, buf_size, "NULL");
2295 snprintf(buf, buf_size, "%s%s",
2296 simplify_cast_num(cast, popr->val), tmp1);
2300 ferr(po, "invalid src type: %d\n", popr->type);
2306 // note: may set is_ptr (we find that out late for ebp frame..)
2307 static char *out_dst_opr(char *buf, size_t buf_size,
2308 struct parsed_op *po, struct parsed_opr *popr)
2310 check_opr(po, popr);
2312 switch (popr->type) {
2314 switch (popr->lmod) {
2316 snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2319 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2323 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2327 if (popr->name[1] == 'h') // XXX..
2328 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2330 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2333 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2338 if (is_stack_access(po, popr)) {
2339 stack_frame_access(po, popr, buf, buf_size,
2340 popr->name, "", 0, 0);
2344 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2347 if (popr->size_mismatch)
2348 snprintf(buf, buf_size, "%s%s%s",
2349 lmod_cast_u_ptr(po, popr->lmod),
2350 popr->is_array ? "" : "&", popr->name);
2352 snprintf(buf, buf_size, "%s%s", popr->name,
2353 popr->is_array ? "[0]" : "");
2357 ferr(po, "invalid dst type: %d\n", popr->type);
2363 static char *out_src_opr_u32(char *buf, size_t buf_size,
2364 struct parsed_op *po, struct parsed_opr *popr)
2366 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2369 static char *out_opr_float(char *buf, size_t buf_size,
2370 struct parsed_op *po, struct parsed_opr *popr, int is_src,
2371 int need_float_stack)
2373 const char *cast = NULL;
2380 switch (popr->type) {
2382 if (popr->reg < xST0 || popr->reg > xST7) {
2384 ferr_assert(po, po->op == OP_PUSH);
2385 ferr_assert(po, popr->lmod == OPLM_DWORD);
2386 snprintf(buf, buf_size, "*(float *)&%s", opr_reg_p(po, popr));
2390 if (need_float_stack) {
2391 if (popr->reg == xST0)
2392 snprintf(buf, buf_size, "f_st[f_stp & 7]");
2394 snprintf(buf, buf_size, "f_st[(f_stp + %d) & 7]",
2398 snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2402 if (popr->lmod == OPLM_QWORD && is_stack_access(po, popr)) {
2403 stack_frame_access(po, popr, buf, buf_size,
2404 popr->name, "", is_src, 0);
2410 switch (popr->lmod) {
2418 ferr(po, "unhandled lmod: %d\n", popr->lmod);
2421 out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2422 snprintf(buf, buf_size, "*(%s *)(%s)", cast, tmp);
2426 // only for func float args pushes
2427 ferr_assert(po, po->op == OP_PUSH);
2428 u.i = po->operand[0].val;
2429 if (ceilf(u.f) == u.f)
2430 snprintf(buf, buf_size, "%.1ff", u.f);
2432 snprintf(buf, buf_size, "%.8ff", u.f);
2436 ferr(po, "invalid float type: %d\n", popr->type);
2442 static char *out_src_opr_float(char *buf, size_t buf_size,
2443 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2445 return out_opr_float(buf, buf_size, po, popr, 1, need_float_stack);
2448 static char *out_dst_opr_float(char *buf, size_t buf_size,
2449 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2451 return out_opr_float(buf, buf_size, po, popr, 0, need_float_stack);
2454 static void out_test_for_cc(char *buf, size_t buf_size,
2455 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2456 enum opr_lenmod lmod, const char *expr)
2458 const char *cast, *scast;
2460 cast = lmod_cast_u(po, lmod);
2461 scast = lmod_cast_s(po, lmod);
2465 case PFO_BE: // CF==1||ZF==1; CF=0
2466 snprintf(buf, buf_size, "(%s%s %s 0)",
2467 cast, expr, is_inv ? "!=" : "==");
2471 case PFO_L: // SF!=OF; OF=0
2472 snprintf(buf, buf_size, "(%s%s %s 0)",
2473 scast, expr, is_inv ? ">=" : "<");
2476 case PFO_LE: // ZF==1||SF!=OF; OF=0
2477 snprintf(buf, buf_size, "(%s%s %s 0)",
2478 scast, expr, is_inv ? ">" : "<=");
2483 snprintf(buf, buf_size, "(%d)", !!is_inv);
2486 case PFO_P: // PF==1
2487 snprintf(buf, buf_size, "(%sdo_parity(%s))",
2488 is_inv ? "!" : "", expr);
2492 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2496 static void out_cmp_for_cc(char *buf, size_t buf_size,
2497 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2500 const char *cast, *scast, *cast_use;
2501 char buf1[256], buf2[256];
2502 enum opr_lenmod lmod;
2504 if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2505 ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2506 po->operand[0].lmod, po->operand[1].lmod);
2507 lmod = po->operand[0].lmod;
2509 cast = lmod_cast_u(po, lmod);
2510 scast = lmod_cast_s(po, lmod);
2526 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2529 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2530 if (po->op == OP_DEC)
2531 snprintf(buf2, sizeof(buf2), "1");
2534 snprintf(cast_op2, sizeof(cast_op2) - 1, "%s", cast_use);
2536 strcat(cast_op2, "-");
2537 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_op2, 0);
2542 // note: must be unsigned compare
2543 snprintf(buf, buf_size, "(%s %s %s)",
2544 buf1, is_inv ? ">=" : "<", buf2);
2548 snprintf(buf, buf_size, "(%s %s %s)",
2549 buf1, is_inv ? "!=" : "==", buf2);
2553 // note: must be unsigned compare
2554 snprintf(buf, buf_size, "(%s %s %s)",
2555 buf1, is_inv ? ">" : "<=", buf2);
2558 if (is_inv && lmod == OPLM_BYTE
2559 && po->operand[1].type == OPT_CONST
2560 && po->operand[1].val == 0xff)
2562 snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2563 snprintf(buf, buf_size, "(0)");
2567 // note: must be signed compare
2569 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2570 scast, buf1, buf2, is_inv ? ">=" : "<");
2574 snprintf(buf, buf_size, "(%s %s %s)",
2575 buf1, is_inv ? ">=" : "<", buf2);
2579 snprintf(buf, buf_size, "(%s %s %s)",
2580 buf1, is_inv ? ">" : "<=", buf2);
2588 static void out_cmp_test(char *buf, size_t buf_size,
2589 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2591 char buf1[256], buf2[256], buf3[256];
2593 if (po->op == OP_TEST) {
2594 if (IS(opr_name(po, 0), opr_name(po, 1))) {
2595 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2598 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2599 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2600 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2602 out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2603 po->operand[0].lmod, buf3);
2605 else if (po->op == OP_CMP) {
2606 out_cmp_for_cc(buf, buf_size, po, pfo, is_inv, 0);
2609 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2612 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2613 struct parsed_opr *popr2)
2615 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2616 ferr(po, "missing lmod for both operands\n");
2618 if (popr1->lmod == OPLM_UNSPEC)
2619 popr1->lmod = popr2->lmod;
2620 else if (popr2->lmod == OPLM_UNSPEC)
2621 popr2->lmod = popr1->lmod;
2622 else if (popr1->lmod != popr2->lmod) {
2623 if (popr1->type_from_var) {
2624 popr1->size_mismatch = 1;
2625 if (popr1->lmod < popr2->lmod)
2627 popr1->lmod = popr2->lmod;
2629 else if (popr2->type_from_var) {
2630 popr2->size_mismatch = 1;
2631 if (popr2->lmod < popr1->lmod)
2633 popr2->lmod = popr1->lmod;
2636 ferr(po, "conflicting lmods: %d vs %d\n",
2637 popr1->lmod, popr2->lmod);
2641 static const char *op_to_c(struct parsed_op *po)
2665 ferr(po, "op_to_c was supplied with %d\n", po->op);
2669 // last op in stream - unconditional branch or ret
2670 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2671 || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2672 && ops[_i].op != OP_CALL))
2674 #define check_i(po, i) \
2676 ferr(po, "bad " #i ": %d\n", i)
2678 // note: this skips over calls and rm'd stuff assuming they're handled
2679 // so it's intended to use at one of final passes
2680 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2681 int depth, int seen_noreturn, int flags_set)
2683 struct parsed_op *po;
2688 for (; i < opcnt; i++) {
2690 if (po->cc_scratch == magic)
2691 return ret; // already checked
2692 po->cc_scratch = magic;
2694 if (po->flags & OPF_TAIL) {
2695 if (po->op == OP_CALL) {
2696 if (po->pp != NULL && po->pp->is_noreturn)
2705 if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
2708 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2709 if (po->btj != NULL) {
2711 for (j = 0; j < po->btj->count; j++) {
2712 check_i(po, po->btj->d[j].bt_i);
2713 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2714 depth, seen_noreturn, flags_set);
2716 return ret; // dead end
2721 check_i(po, po->bt_i);
2722 if (po->flags & OPF_CJMP) {
2723 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2724 depth, seen_noreturn, flags_set);
2726 return ret; // dead end
2735 if ((po->op == OP_POP || po->op == OP_PUSH)
2736 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2741 if (po->op == OP_PUSH) {
2744 else if (po->op == OP_POP) {
2745 if (relevant && depth == 0) {
2746 po->flags |= flags_set;
2754 // for noreturn, assume msvc skipped stack cleanup
2755 return seen_noreturn ? 1 : -1;
2758 // scan for 'reg' pop backwards starting from i
2759 // intended to use for register restore search, so other reg
2760 // references are considered an error
2761 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2763 struct parsed_op *po;
2764 struct label_ref *lr;
2767 ops[i].cc_scratch = magic;
2771 if (g_labels[i] != NULL) {
2772 lr = &g_label_refs[i];
2773 for (; lr != NULL; lr = lr->next) {
2774 check_i(&ops[i], lr->i);
2775 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2779 if (i > 0 && LAST_OP(i - 1))
2787 if (ops[i].cc_scratch == magic)
2789 ops[i].cc_scratch = magic;
2792 if (po->op == OP_POP && po->operand[0].reg == reg) {
2793 if (po->flags & (OPF_RMD|OPF_DONE))
2796 po->flags |= set_flags;
2800 // this also covers the case where we reach corresponding push
2801 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2805 // nothing interesting on this path,
2806 // still return ret for something recursive calls could find
2810 static void find_reachable_exits(int i, int opcnt, int magic,
2811 int *exits, int *exit_count)
2813 struct parsed_op *po;
2816 for (; i < opcnt; i++)
2819 if (po->cc_scratch == magic)
2821 po->cc_scratch = magic;
2823 if (po->flags & OPF_TAIL) {
2824 ferr_assert(po, *exit_count < MAX_EXITS);
2825 exits[*exit_count] = i;
2830 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2831 if (po->flags & OPF_RMD)
2834 if (po->btj != NULL) {
2835 for (j = 0; j < po->btj->count; j++) {
2836 check_i(po, po->btj->d[j].bt_i);
2837 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2843 check_i(po, po->bt_i);
2844 if (po->flags & OPF_CJMP)
2845 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2853 // scan for 'reg' pop backwards starting from exits (all paths)
2854 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2856 static int exits[MAX_EXITS];
2857 static int exit_count;
2863 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2865 ferr_assert(&ops[i], exit_count > 0);
2868 for (j = 0; j < exit_count; j++) {
2870 ret = scan_for_rsave_pop_reg(e, i + opcnt * 16 + set_flags,
2876 if (ops[e].op == OP_CALL && ops[e].pp != NULL
2877 && ops[e].pp->is_noreturn)
2879 // assume stack cleanup was skipped
2888 // scan for one or more pop of push <const>
2889 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2890 int push_i, int is_probe)
2892 struct parsed_op *po;
2893 struct label_ref *lr;
2897 for (; i < opcnt; i++)
2900 if (po->cc_scratch == magic)
2901 return ret; // already checked
2902 po->cc_scratch = magic;
2904 if (po->flags & OPF_JMP) {
2905 if (po->flags & OPF_RMD)
2907 if (po->op == OP_CALL)
2910 if (po->btj != NULL) {
2911 for (j = 0; j < po->btj->count; j++) {
2912 check_i(po, po->btj->d[j].bt_i);
2913 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2921 check_i(po, po->bt_i);
2922 if (po->flags & OPF_CJMP) {
2923 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2934 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2937 if (g_labels[i] != NULL) {
2938 // all refs must be visited
2939 lr = &g_label_refs[i];
2940 for (; lr != NULL; lr = lr->next) {
2942 if (ops[lr->i].cc_scratch != magic)
2945 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2949 if (po->op == OP_POP)
2951 if (po->flags & (OPF_RMD|OPF_DONE))
2955 po->flags |= OPF_DONE;
2956 po->datap = &ops[push_i];
2965 static void scan_for_pop_const(int i, int opcnt, int magic)
2969 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
2971 ops[i].flags |= OPF_RMD | OPF_DONE;
2972 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
2976 // check if all branch targets within a marked path are also marked
2977 // note: the path checked must not be empty or end with a branch
2978 static int check_path_branches(int opcnt, int magic)
2980 struct parsed_op *po;
2983 for (i = 0; i < opcnt; i++) {
2985 if (po->cc_scratch != magic)
2988 if (po->flags & OPF_JMP) {
2989 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
2992 if (po->btj != NULL) {
2993 for (j = 0; j < po->btj->count; j++) {
2994 check_i(po, po->btj->d[j].bt_i);
2995 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
3000 check_i(po, po->bt_i);
3001 if (ops[po->bt_i].cc_scratch != magic)
3003 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
3011 // scan for multiple pushes for given pop
3012 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
3015 int reg = ops[pop_i].operand[0].reg;
3016 struct parsed_op *po;
3017 struct label_ref *lr;
3020 ops[i].cc_scratch = magic;
3024 if (g_labels[i] != NULL) {
3025 lr = &g_label_refs[i];
3026 for (; lr != NULL; lr = lr->next) {
3027 check_i(&ops[i], lr->i);
3028 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
3032 if (i > 0 && LAST_OP(i - 1))
3040 if (ops[i].cc_scratch == magic)
3042 ops[i].cc_scratch = magic;
3045 if (po->op == OP_CALL)
3047 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
3050 if (po->op == OP_PUSH)
3052 if (po->datap != NULL)
3054 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
3055 // leave this case for reg save/restore handlers
3059 po->flags |= OPF_PPUSH | OPF_DONE;
3060 po->datap = &ops[pop_i];
3069 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
3071 int magic = i + opcnt * 14;
3074 ret = scan_pushes_for_pop_r(i, magic, i, 1);
3076 ret = check_path_branches(opcnt, magic);
3078 ops[i].flags |= OPF_PPUSH | OPF_DONE;
3079 *regmask_pp |= 1 << ops[i].operand[0].reg;
3080 scan_pushes_for_pop_r(i, magic + 1, i, 0);
3085 static void scan_propagate_df(int i, int opcnt)
3087 struct parsed_op *po = &ops[i];
3090 for (; i < opcnt; i++) {
3092 if (po->flags & OPF_DF)
3093 return; // already resolved
3094 po->flags |= OPF_DF;
3096 if (po->op == OP_CALL)
3097 ferr(po, "call with DF set?\n");
3099 if (po->flags & OPF_JMP) {
3100 if (po->btj != NULL) {
3102 for (j = 0; j < po->btj->count; j++) {
3103 check_i(po, po->btj->d[j].bt_i);
3104 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
3109 if (po->flags & OPF_RMD)
3111 check_i(po, po->bt_i);
3112 if (po->flags & OPF_CJMP)
3113 scan_propagate_df(po->bt_i, opcnt);
3119 if (po->flags & OPF_TAIL)
3122 if (po->op == OP_CLD) {
3123 po->flags |= OPF_RMD | OPF_DONE;
3128 ferr(po, "missing DF clear?\n");
3131 // is operand 'opr' referenced by parsed_op 'po'?
3132 static int is_opr_referenced(const struct parsed_opr *opr,
3133 const struct parsed_op *po)
3137 if (opr->type == OPT_REG) {
3138 mask = po->regmask_dst | po->regmask_src;
3139 if (po->op == OP_CALL)
3140 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
3141 if ((1 << opr->reg) & mask)
3147 for (i = 0; i < po->operand_cnt; i++)
3148 if (IS(po->operand[0].name, opr->name))
3154 // is operand 'opr' read by parsed_op 'po'?
3155 static int is_opr_read(const struct parsed_opr *opr,
3156 const struct parsed_op *po)
3158 if (opr->type == OPT_REG) {
3159 if (po->regmask_src & (1 << opr->reg))
3169 // is operand 'opr' modified by parsed_op 'po'?
3170 static int is_opr_modified(const struct parsed_opr *opr,
3171 const struct parsed_op *po)
3175 if (opr->type == OPT_REG) {
3176 if (po->op == OP_CALL) {
3177 mask = po->regmask_dst;
3178 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
3179 if (mask & (1 << opr->reg))
3185 if (po->regmask_dst & (1 << opr->reg))
3191 return IS(po->operand[0].name, opr->name);
3194 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
3195 static int is_any_opr_modified(const struct parsed_op *po_test,
3196 const struct parsed_op *po, int c_mode)
3201 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
3204 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3207 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
3210 // in reality, it can wreck any register, but in decompiled C
3211 // version it can only overwrite eax or edx:eax
3212 mask = (1 << xAX) | (1 << xDX);
3216 if (po->op == OP_CALL
3217 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
3220 for (i = 0; i < po_test->operand_cnt; i++)
3221 if (IS(po_test->operand[i].name, po->operand[0].name))
3227 // scan for any po_test operand modification in range given
3228 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
3231 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3234 for (; i < opcnt; i++) {
3235 if (is_any_opr_modified(po_test, &ops[i], c_mode))
3242 // scan for po_test operand[0] modification in range given
3243 static int scan_for_mod_opr0(struct parsed_op *po_test,
3246 for (; i < opcnt; i++) {
3247 if (is_opr_modified(&po_test->operand[0], &ops[i]))
3254 static int try_resolve_const(int i, const struct parsed_opr *opr,
3255 int magic, unsigned int *val);
3257 static int scan_for_flag_set(int i, int opcnt, int magic,
3258 int *branched, int *setters, int *setter_cnt)
3260 struct label_ref *lr;
3264 if (ops[i].cc_scratch == magic) {
3265 // is this a problem?
3266 //ferr(&ops[i], "%s looped\n", __func__);
3269 ops[i].cc_scratch = magic;
3271 if (g_labels[i] != NULL) {
3274 lr = &g_label_refs[i];
3275 for (; lr->next; lr = lr->next) {
3276 check_i(&ops[i], lr->i);
3277 ret = scan_for_flag_set(lr->i, opcnt, magic,
3278 branched, setters, setter_cnt);
3283 check_i(&ops[i], lr->i);
3284 if (i > 0 && LAST_OP(i - 1)) {
3288 ret = scan_for_flag_set(lr->i, opcnt, magic,
3289 branched, setters, setter_cnt);
3295 if (ops[i].flags & OPF_FLAGS) {
3296 setters[*setter_cnt] = i;
3299 if (ops[i].flags & OPF_REP) {
3300 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
3303 ret = try_resolve_const(i, &opr, i + opcnt * 7, &uval);
3304 if (ret != 1 || uval == 0) {
3305 // can't treat it as full setter because of ecx=0 case,
3306 // also disallow delayed compare
3315 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3322 // scan back for cdq, if anything modifies edx, fail
3323 static int scan_for_cdq_edx(int i)
3326 if (g_labels[i] != NULL) {
3327 if (g_label_refs[i].next != NULL)
3329 if (i > 0 && LAST_OP(i - 1)) {
3330 i = g_label_refs[i].i;
3337 if (ops[i].op == OP_CDQ)
3340 if (ops[i].regmask_dst & (1 << xDX))
3347 static int scan_for_reg_clear(int i, int reg)
3350 if (g_labels[i] != NULL) {
3351 if (g_label_refs[i].next != NULL)
3353 if (i > 0 && LAST_OP(i - 1)) {
3354 i = g_label_refs[i].i;
3361 if (ops[i].op == OP_XOR
3362 && ops[i].operand[0].lmod == OPLM_DWORD
3363 && ops[i].operand[0].reg == ops[i].operand[1].reg
3364 && ops[i].operand[0].reg == reg)
3367 if (ops[i].regmask_dst & (1 << reg))
3374 static void patch_esp_adjust(struct parsed_op *po, int adj)
3376 ferr_assert(po, po->op == OP_ADD);
3377 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3378 ferr_assert(po, po->operand[1].type == OPT_CONST);
3380 // this is a bit of a hack, but deals with use of
3381 // single adj for multiple calls
3382 po->operand[1].val -= adj;
3383 po->flags |= OPF_RMD;
3384 if (po->operand[1].val == 0)
3385 po->flags |= OPF_DONE;
3386 ferr_assert(po, (int)po->operand[1].val >= 0);
3389 // scan for positive, constant esp adjust
3390 // multipath case is preliminary
3391 static int scan_for_esp_adjust(int i, int opcnt,
3392 int adj_expect, int *adj, int *is_multipath, int do_update)
3394 int adj_expect_unknown = 0;
3395 struct parsed_op *po;
3399 *adj = *is_multipath = 0;
3400 if (adj_expect < 0) {
3401 adj_expect_unknown = 1;
3402 adj_expect = 32 * 4; // enough?
3405 for (; i < opcnt && *adj < adj_expect; i++) {
3406 if (g_labels[i] != NULL)
3410 if (po->flags & OPF_DONE)
3413 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3414 if (po->operand[1].type != OPT_CONST)
3415 ferr(&ops[i], "non-const esp adjust?\n");
3416 *adj += po->operand[1].val;
3418 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3421 patch_esp_adjust(po, adj_expect);
3423 po->flags |= OPF_RMD;
3427 else if (po->op == OP_PUSH) {
3428 //if (first_pop == -1)
3429 // first_pop = -2; // none
3430 *adj -= lmod_bytes(po, po->operand[0].lmod);
3432 else if (po->op == OP_POP) {
3433 if (!(po->flags & OPF_DONE)) {
3434 // seems like msvc only uses 'pop ecx' for stack realignment..
3435 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3437 if (first_pop == -1 && *adj >= 0)
3440 if (do_update && *adj >= 0) {
3441 po->flags |= OPF_RMD;
3443 po->flags |= OPF_DONE | OPF_NOREGS;
3446 *adj += lmod_bytes(po, po->operand[0].lmod);
3447 if (*adj > adj_best)
3450 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3451 if (po->op == OP_JMP && po->btj == NULL) {
3457 if (po->op != OP_CALL)
3459 if (po->operand[0].type != OPT_LABEL)
3461 if (po->pp != NULL && po->pp->is_stdcall)
3463 if (adj_expect_unknown && first_pop >= 0)
3465 // assume it's another cdecl call
3469 if (first_pop >= 0) {
3470 // probably only 'pop ecx' was used
3478 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3480 struct parsed_op *po;
3484 ferr(ops, "%s: followed bad branch?\n", __func__);
3486 for (; i < opcnt; i++) {
3488 if (po->cc_scratch == magic)
3490 po->cc_scratch = magic;
3493 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3494 if (po->btj != NULL) {
3496 for (j = 0; j < po->btj->count; j++)
3497 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3501 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3502 if (!(po->flags & OPF_CJMP))
3505 if (po->flags & OPF_TAIL)
3510 static const struct parsed_proto *try_recover_pp(
3511 struct parsed_op *po, const struct parsed_opr *opr,
3512 int is_call, int *search_instead)
3514 const struct parsed_proto *pp = NULL;
3518 // maybe an arg of g_func?
3519 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3521 char ofs_reg[16] = { 0, };
3522 int arg, arg_s, arg_i;
3529 parse_stack_access(po, opr->name, ofs_reg,
3530 &offset, &stack_ra, NULL, 0);
3531 if (ofs_reg[0] != 0)
3532 ferr(po, "offset reg on arg access?\n");
3533 if (offset <= stack_ra) {
3534 // search who set the stack var instead
3535 if (search_instead != NULL)
3536 *search_instead = 1;
3540 arg_i = (offset - stack_ra - 4) / 4;
3541 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3542 if (g_func_pp->arg[arg].reg != NULL)
3548 if (arg == g_func_pp->argc)
3549 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3551 pp = g_func_pp->arg[arg].pp;
3554 ferr(po, "icall arg: arg%d has no pp\n", arg + 1);
3555 check_func_pp(po, pp, "icall arg");
3558 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3560 p = strchr(opr->name + 1, '[');
3561 memcpy(buf, opr->name, p - opr->name);
3562 buf[p - opr->name] = 0;
3563 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3565 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3566 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3569 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3572 check_func_pp(po, pp, "reg-fptr ref");
3578 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3579 int magic, const struct parsed_proto **pp_found, int *pp_i,
3582 const struct parsed_proto *pp = NULL;
3583 struct parsed_op *po;
3584 struct label_ref *lr;
3586 ops[i].cc_scratch = magic;
3589 if (g_labels[i] != NULL) {
3590 lr = &g_label_refs[i];
3591 for (; lr != NULL; lr = lr->next) {
3592 check_i(&ops[i], lr->i);
3593 scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3595 if (i > 0 && LAST_OP(i - 1))
3603 if (ops[i].cc_scratch == magic)
3605 ops[i].cc_scratch = magic;
3607 if (!(ops[i].flags & OPF_DATA))
3609 if (!is_opr_modified(opr, &ops[i]))
3611 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3612 // most probably trashed by some processing
3617 opr = &ops[i].operand[1];
3618 if (opr->type != OPT_REG)
3622 po = (i >= 0) ? &ops[i] : ops;
3625 // reached the top - can only be an arg-reg
3626 if (opr->type != OPT_REG || g_func_pp == NULL)
3629 for (i = 0; i < g_func_pp->argc; i++) {
3630 if (g_func_pp->arg[i].reg == NULL)
3632 if (IS(opr->name, g_func_pp->arg[i].reg))
3635 if (i == g_func_pp->argc)
3637 pp = g_func_pp->arg[i].pp;
3639 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3640 i + 1, g_func_pp->arg[i].reg);
3641 check_func_pp(po, pp, "icall reg-arg");
3644 pp = try_recover_pp(po, opr, 1, NULL);
3646 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3647 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3648 || (*pp_found)->is_stdcall != pp->is_stdcall
3649 //|| (*pp_found)->is_fptr != pp->is_fptr
3650 || (*pp_found)->argc != pp->argc
3651 || (*pp_found)->argc_reg != pp->argc_reg
3652 || (*pp_found)->argc_stack != pp->argc_stack)
3654 ferr(po, "icall: parsed_proto mismatch\n");
3664 static void add_label_ref(struct label_ref *lr, int op_i)
3666 struct label_ref *lr_new;
3673 lr_new = calloc(1, sizeof(*lr_new));
3675 lr_new->next = lr->next;
3679 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3681 struct parsed_op *po = &ops[i];
3682 struct parsed_data *pd;
3683 char label[NAMELEN], *p;
3686 p = strchr(po->operand[0].name, '[');
3690 len = p - po->operand[0].name;
3691 strncpy(label, po->operand[0].name, len);
3694 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3695 if (IS(g_func_pd[j].label, label)) {
3701 //ferr(po, "label '%s' not parsed?\n", label);
3704 if (pd->type != OPT_OFFSET)
3705 ferr(po, "label '%s' with non-offset data?\n", label);
3707 // find all labels, link
3708 for (j = 0; j < pd->count; j++) {
3709 for (l = 0; l < opcnt; l++) {
3710 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3711 add_label_ref(&g_label_refs[l], i);
3721 static void clear_labels(int count)
3725 for (i = 0; i < count; i++) {
3726 if (g_labels[i] != NULL) {
3733 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3738 for (i = 0; i < pp->argc; i++) {
3739 if (pp->arg[i].reg != NULL) {
3740 reg = char_array_i(regs_r32,
3741 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3743 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3744 pp->arg[i].reg, pp->name);
3745 regmask |= 1 << reg;
3752 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3757 if (pp->has_retreg) {
3758 for (i = 0; i < pp->argc; i++) {
3759 if (pp->arg[i].type.is_retreg) {
3760 reg = char_array_i(regs_r32,
3761 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3762 ferr_assert(ops, reg >= 0);
3763 regmask |= 1 << reg;
3768 if (strstr(pp->ret_type.name, "int64"))
3769 return regmask | (1 << xAX) | (1 << xDX);
3770 if (IS(pp->ret_type.name, "float")
3771 || IS(pp->ret_type.name, "double"))
3773 return regmask | mxST0;
3775 if (strcasecmp(pp->ret_type.name, "void") == 0)
3778 return regmask | mxAX;
3781 static int are_ops_same(struct parsed_op *po1, struct parsed_op *po2)
3783 return po1->op == po2->op && po1->operand_cnt == po2->operand_cnt
3784 && memcmp(po1->operand, po2->operand,
3785 sizeof(po1->operand[0]) * po1->operand_cnt) == 0;
3788 static void resolve_branches_parse_calls(int opcnt)
3790 static const struct {
3794 unsigned int regmask_src;
3795 unsigned int regmask_dst;
3797 { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3798 { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3799 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3800 // more precise? Wine gets away with just __ftol handler
3801 { "__ftol2", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3802 { "__CIpow", OPP_CIPOW, OPF_FPOP, mxST0|mxST1, mxST0 },
3804 const struct parsed_proto *pp_c;
3805 struct parsed_proto *pp;
3806 struct parsed_data *pd;
3807 struct parsed_op *po;
3808 const char *tmpname;
3813 for (i = 0; i < opcnt; i++)
3819 if (po->datap != NULL) {
3820 pp = calloc(1, sizeof(*pp));
3821 my_assert_not(pp, NULL);
3823 ret = parse_protostr(po->datap, pp);
3825 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3831 if (po->op == OP_CALL) {
3836 else if (po->operand[0].type == OPT_LABEL)
3838 tmpname = opr_name(po, 0);
3839 if (IS_START(tmpname, "loc_")) {
3841 ferr(po, "call to loc_*\n");
3842 // eliminate_seh() must take care of it
3845 if (IS(tmpname, "__alloca_probe"))
3847 if (IS(tmpname, "__SEH_prolog")) {
3848 ferr_assert(po, g_seh_found == 0);
3852 if (IS(tmpname, "__SEH_epilog"))
3855 // convert some calls to pseudo-ops
3856 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3857 if (!IS(tmpname, pseudo_ops[l].name))
3860 po->op = pseudo_ops[l].op;
3861 po->operand_cnt = 0;
3862 po->regmask_src = pseudo_ops[l].regmask_src;
3863 po->regmask_dst = pseudo_ops[l].regmask_dst;
3864 po->flags = pseudo_ops[l].flags;
3865 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3868 if (l < ARRAY_SIZE(pseudo_ops))
3871 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3872 if (!g_header_mode && pp_c == NULL)
3873 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3876 pp = proto_clone(pp_c);
3877 my_assert_not(pp, NULL);
3883 check_func_pp(po, pp, "fptr var call");
3884 if (pp->is_noreturn) {
3885 po->flags |= OPF_TAIL;
3886 po->flags &= ~OPF_ATAIL; // most likely...
3893 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3896 if (po->operand[0].type == OPT_REGMEM) {
3897 pd = try_resolve_jumptab(i, opcnt);
3905 for (l = 0; l < opcnt; l++) {
3906 if (g_labels[l] != NULL
3907 && IS(po->operand[0].name, g_labels[l]))
3909 if (l == i + 1 && po->op == OP_JMP) {
3910 // yet another alignment type..
3911 po->flags |= OPF_RMD|OPF_DONE;
3914 add_label_ref(&g_label_refs[l], i);
3920 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3923 if (po->operand[0].type == OPT_LABEL)
3927 ferr(po, "unhandled branch\n");
3931 po->flags |= OPF_TAIL;
3932 prev_op = i > 0 ? ops[i - 1].op : OP_UD2;
3933 if (prev_op == OP_POP)
3934 po->flags |= OPF_ATAIL;
3935 if (g_stack_fsz + g_bp_frame == 0 && prev_op != OP_PUSH
3936 && (g_func_pp == NULL || g_func_pp->argc_stack > 0))
3938 po->flags |= OPF_ATAIL;
3944 static int resolve_origin(int i, const struct parsed_opr *opr,
3945 int magic, int *op_i, int *is_caller);
3946 static void set_label(int i, const char *name);
3948 static void eliminate_seh_writes(int opcnt)
3950 const struct parsed_opr *opr;
3955 // assume all sf writes above g_seh_size to be seh related
3956 // (probably unsafe but oh well)
3957 for (i = 0; i < opcnt; i++) {
3958 if (ops[i].op != OP_MOV)
3960 opr = &ops[i].operand[0];
3961 if (opr->type != OPT_REGMEM)
3963 if (!is_stack_access(&ops[i], opr))
3967 parse_stack_access(&ops[i], opr->name, ofs_reg, &offset,
3969 if (offset < 0 && offset >= -g_seh_size)
3970 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3974 static void eliminate_seh_finally(int opcnt)
3976 const char *target_name = NULL;
3977 const char *return_name = NULL;
3978 int exits[MAX_EXITS];
3986 for (i = 0; i < opcnt; i++) {
3987 if (ops[i].op != OP_CALL)
3989 if (!IS_START(opr_name(&ops[i], 0), "loc_"))
3991 if (target_name != NULL)
3992 ferr(&ops[i], "multiple finally calls? (last was %s)\n",
3994 target_name = opr_name(&ops[i], 0);
3997 if (g_labels[i + 1] == NULL)
3998 set_label(i + 1, "seh_fin_done");
3999 return_name = g_labels[i + 1];
4007 // find finally code (bt_i is not set because it's call)
4008 for (i = 0; i < opcnt; i++) {
4009 if (g_labels[i] == NULL)
4011 if (!IS(g_labels[i], target_name))
4014 ferr_assert(&ops[i], target_i == -1);
4017 ferr_assert(&ops[0], target_i != -1);
4019 find_reachable_exits(target_i, opcnt, target_i + opcnt * 24,
4020 exits, &exit_count);
4021 ferr_assert(&ops[target_i], exit_count == 1);
4022 ferr_assert(&ops[target_i], ops[exits[0]].op == OP_RET);
4025 // convert to jumps, link
4026 ops[call_i].op = OP_JMP;
4027 ops[call_i].bt_i = target_i;
4028 add_label_ref(&g_label_refs[target_i], call_i);
4030 ops[tgend_i].op = OP_JMP;
4031 ops[tgend_i].flags &= ~OPF_TAIL;
4032 ops[tgend_i].flags |= OPF_JMP;
4033 ops[tgend_i].bt_i = return_i;
4034 ops[tgend_i].operand_cnt = 1;
4035 ops[tgend_i].operand[0].type = OPT_LABEL;
4036 snprintf(ops[tgend_i].operand[0].name, NAMELEN, "%s", return_name);
4037 add_label_ref(&g_label_refs[return_i], tgend_i);
4039 // rm seh finally entry code
4040 for (i = target_i - 1; i >= 0; i--) {
4041 if (g_labels[i] != NULL && g_label_refs[i].i != -1)
4043 if (ops[i].flags & OPF_CJMP)
4045 if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4048 for (i = target_i - 1; i >= 0; i--) {
4049 if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4051 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4055 static void eliminate_seh(int opcnt)
4059 for (i = 0; i < opcnt; i++) {
4060 if (ops[i].op != OP_MOV)
4062 if (ops[i].operand[0].segment != SEG_FS)
4064 if (!IS(opr_name(&ops[i], 0), "0"))
4067 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4068 if (ops[i].operand[1].reg == xSP) {
4069 for (j = i - 1; j >= 0; j--) {
4070 if (ops[j].op != OP_PUSH)
4072 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4074 if (ops[j].operand[0].val == ~0)
4076 if (ops[j].operand[0].type == OPT_REG) {
4078 ret = resolve_origin(j, &ops[j].operand[0],
4079 j + opcnt * 22, &k, NULL);
4081 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4085 ferr(ops, "missing seh terminator\n");
4089 ret = resolve_origin(i, &ops[i].operand[1],
4090 i + opcnt * 23, &k, NULL);
4092 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4096 eliminate_seh_writes(opcnt);
4097 eliminate_seh_finally(opcnt);
4100 static void eliminate_seh_calls(int opcnt)
4102 int epilog_found = 0;
4109 ferr_assert(&ops[i], ops[i].op == OP_PUSH
4110 && ops[i].operand[0].type == OPT_CONST);
4111 g_stack_fsz = g_seh_size + ops[i].operand[0].val;
4112 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4115 ferr_assert(&ops[i], ops[i].op == OP_PUSH
4116 && ops[i].operand[0].type == OPT_OFFSET);
4117 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4120 ferr_assert(&ops[i], ops[i].op == OP_CALL
4121 && IS(opr_name(&ops[i], 0), "__SEH_prolog"));
4122 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4124 for (i++; i < opcnt; i++) {
4125 if (ops[i].op != OP_CALL)
4127 if (!IS(opr_name(&ops[i], 0), "__SEH_epilog"))
4130 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4133 ferr_assert(ops, epilog_found);
4135 eliminate_seh_writes(opcnt);
4136 eliminate_seh_finally(opcnt);
4139 static int scan_prologue(int i, int opcnt, int *ecx_push, int *esp_sub)
4143 for (; i < opcnt; i++)
4144 if (!(ops[i].flags & OPF_DONE))
4147 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4148 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4154 for (; i < opcnt; i++) {
4155 if (i > 0 && g_labels[i] != NULL)
4157 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
4159 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
4160 && ops[i].operand[1].type == OPT_CONST)
4162 g_stack_fsz += opr_const(&ops[i], 1);
4163 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4168 if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
4169 && ops[i].operand[1].type == OPT_CONST)
4171 for (j = i + 1; j < opcnt; j++)
4172 if (!(ops[j].flags & OPF_DONE))
4174 if (ops[j].op == OP_CALL
4175 && IS(opr_name(&ops[j], 0), "__alloca_probe"))
4177 g_stack_fsz += opr_const(&ops[i], 1);
4178 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4179 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4190 static void scan_prologue_epilogue(int opcnt, int *stack_align)
4192 int ecx_push = 0, esp_sub = 0, pusha = 0;
4193 int sandard_epilogue;
4197 if (g_seh_found == 2) {
4198 eliminate_seh_calls(opcnt);
4202 eliminate_seh(opcnt);
4203 // ida treats seh as part of sf
4204 g_stack_fsz = g_seh_size;
4208 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
4209 && ops[1].op == OP_MOV
4210 && IS(opr_name(&ops[1], 0), "ebp")
4211 && IS(opr_name(&ops[1], 1), "esp"))
4214 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4215 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4217 for (i = 2; i < opcnt; i++)
4218 if (!(ops[i].flags & OPF_DONE))
4221 if (ops[i].op == OP_PUSHA) {
4222 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4227 if (ops[i].op == OP_AND && ops[i].operand[0].reg == xSP
4228 && ops[i].operand[1].type == OPT_CONST)
4230 l = ops[i].operand[1].val;
4232 if (j == -1 || (l >> j) != -1)
4233 ferr(&ops[i], "unhandled esp align: %x\n", l);
4234 if (stack_align != NULL)
4235 *stack_align = 1 << j;
4236 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4240 i = scan_prologue(i, opcnt, &ecx_push, &esp_sub);
4244 for (; i < opcnt; i++)
4245 if (ops[i].flags & OPF_TAIL)
4248 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4249 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4255 sandard_epilogue = 0;
4256 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
4258 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4259 // the standard epilogue is sometimes even used without a sf
4260 if (ops[j - 1].op == OP_MOV
4261 && IS(opr_name(&ops[j - 1], 0), "esp")
4262 && IS(opr_name(&ops[j - 1], 1), "ebp"))
4263 sandard_epilogue = 1;
4265 else if (ops[j].op == OP_LEAVE)
4267 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4268 sandard_epilogue = 1;
4270 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
4271 && ops[i].pp->is_noreturn)
4273 // on noreturn, msvc sometimes cleans stack, sometimes not
4278 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4279 ferr(&ops[j], "'pop ebp' expected\n");
4281 if (g_stack_fsz != 0 || sandard_epilogue) {
4282 if (ops[j].op == OP_LEAVE)
4284 else if (sandard_epilogue) // mov esp, ebp
4286 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4289 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4291 ferr(&ops[j], "esp restore expected\n");
4294 if (ecx_push && j >= 0 && ops[j].op == OP_POP
4295 && IS(opr_name(&ops[j], 0), "ecx"))
4297 ferr(&ops[j], "unexpected ecx pop\n");
4302 if (ops[j].op == OP_POPA)
4303 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4305 ferr(&ops[j], "popa expected\n");
4310 } while (i < opcnt);
4313 ferr(ops, "missing ebp epilogue\n");
4318 i = scan_prologue(0, opcnt, &ecx_push, &esp_sub);
4320 if (ecx_push && !esp_sub) {
4321 // could actually be args for a call..
4322 for (; i < opcnt; i++)
4323 if (ops[i].op != OP_PUSH)
4326 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
4327 const struct parsed_proto *pp;
4328 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
4329 j = pp ? pp->argc_stack : 0;
4330 while (i > 0 && j > 0) {
4332 if (ops[i].op == OP_PUSH) {
4333 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
4338 ferr(&ops[i], "unhandled prologue\n");
4342 g_stack_fsz = g_seh_size;
4343 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4344 if (!(ops[i].flags & OPF_RMD))
4354 if (ecx_push || esp_sub)
4359 for (; i < opcnt; i++)
4360 if (ops[i].flags & OPF_TAIL)
4364 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4365 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4370 else if (i < opcnt && (ops[i].flags & OPF_ATAIL)) {
4371 // skip arg updates for arg-reuse tailcall
4372 for (; j >= 0; j--) {
4373 if (ops[j].op != OP_MOV)
4375 if (ops[j].operand[0].type != OPT_REGMEM)
4377 if (strstr(ops[j].operand[0].name, "arg_") == NULL)
4382 if (ecx_push > 0 && !esp_sub) {
4383 for (l = 0; l < ecx_push && j >= 0; l++) {
4384 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
4386 else if (ops[j].op == OP_ADD
4387 && IS(opr_name(&ops[j], 0), "esp")
4388 && ops[j].operand[1].type == OPT_CONST)
4391 l += ops[j].operand[1].val / 4 - 1;
4396 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4399 if (l != ecx_push) {
4400 if (i < opcnt && ops[i].op == OP_CALL
4401 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4403 // noreturn tailcall with no epilogue
4408 ferr(&ops[j], "epilogue scan failed\n");
4415 if (ops[j].op != OP_ADD
4416 || !IS(opr_name(&ops[j], 0), "esp")
4417 || ops[j].operand[1].type != OPT_CONST)
4419 if (i < opcnt && ops[i].op == OP_CALL
4420 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4422 // noreturn tailcall with no epilogue
4427 ferr(&ops[j], "'add esp' expected\n");
4430 if (ops[j].operand[1].val < g_stack_fsz)
4431 ferr(&ops[j], "esp adj is too low (need %d)\n", g_stack_fsz);
4433 ops[j].operand[1].val -= g_stack_fsz; // for stack arg scanner
4434 if (ops[j].operand[1].val == 0)
4435 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4440 } while (i < opcnt);
4443 ferr(ops, "missing esp epilogue\n");
4447 // find an instruction that changed opr before i op
4448 // *op_i must be set to -1 by the caller
4449 // *is_caller is set to 1 if one source is determined to be g_func arg
4450 // returns 1 if found, *op_i is then set to origin
4451 // returns -1 if multiple origins are found
4452 static int resolve_origin(int i, const struct parsed_opr *opr,
4453 int magic, int *op_i, int *is_caller)
4455 struct label_ref *lr;
4459 if (g_labels[i] != NULL) {
4460 lr = &g_label_refs[i];
4461 for (; lr != NULL; lr = lr->next) {
4462 check_i(&ops[i], lr->i);
4463 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4465 if (i > 0 && LAST_OP(i - 1))
4471 if (is_caller != NULL)
4476 if (ops[i].cc_scratch == magic)
4478 ops[i].cc_scratch = magic;
4480 if (!(ops[i].flags & OPF_DATA))
4482 if (!is_opr_modified(opr, &ops[i]))
4486 if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4497 // find an instruction that previously referenced opr
4498 // if multiple results are found - fail
4499 // *op_i must be set to -1 by the caller
4500 // returns 1 if found, *op_i is then set to referencer insn
4501 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4502 int magic, int *op_i)
4504 struct label_ref *lr;
4508 if (g_labels[i] != NULL) {
4509 lr = &g_label_refs[i];
4510 for (; lr != NULL; lr = lr->next) {
4511 check_i(&ops[i], lr->i);
4512 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4514 if (i > 0 && LAST_OP(i - 1))
4522 if (ops[i].cc_scratch == magic)
4524 ops[i].cc_scratch = magic;
4526 if (!is_opr_referenced(opr, &ops[i]))
4537 // adjust datap of all reachable 'op' insns when moving back
4538 // returns 1 if at least 1 op was found
4539 // returns -1 if path without an op was found
4540 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4542 struct label_ref *lr;
4545 if (ops[i].cc_scratch == magic)
4547 ops[i].cc_scratch = magic;
4550 if (g_labels[i] != NULL) {
4551 lr = &g_label_refs[i];
4552 for (; lr != NULL; lr = lr->next) {
4553 check_i(&ops[i], lr->i);
4554 ret |= adjust_prev_op(lr->i, op, magic, datap);
4556 if (i > 0 && LAST_OP(i - 1))
4564 if (ops[i].cc_scratch == magic)
4566 ops[i].cc_scratch = magic;
4568 if (ops[i].op != op)
4571 ops[i].datap = datap;
4576 // find next instruction that reads opr
4577 // *op_i must be set to -1 by the caller
4578 // on return, *op_i is set to first referencer insn
4579 // returns 1 if exactly 1 referencer is found
4580 static int find_next_read(int i, int opcnt,
4581 const struct parsed_opr *opr, int magic, int *op_i)
4583 struct parsed_op *po;
4586 for (; i < opcnt; i++)
4588 if (ops[i].cc_scratch == magic)
4590 ops[i].cc_scratch = magic;
4593 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4594 if (po->btj != NULL) {
4596 for (j = 0; j < po->btj->count; j++) {
4597 check_i(po, po->btj->d[j].bt_i);
4598 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4604 if (po->flags & OPF_RMD)
4606 check_i(po, po->bt_i);
4607 if (po->flags & OPF_CJMP) {
4608 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4617 if (!is_opr_read(opr, po)) {
4619 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4620 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4622 full_opr = po->operand[0].lmod >= opr->lmod;
4624 if (is_opr_modified(opr, po) && full_opr) {
4628 if (po->flags & OPF_TAIL)
4643 // find next instruction that reads opr
4644 // *op_i must be set to -1 by the caller
4645 // on return, *op_i is set to first flag user insn
4646 // returns 1 if exactly 1 flag user is found
4647 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4649 struct parsed_op *po;
4652 for (; i < opcnt; i++)
4654 if (ops[i].cc_scratch == magic)
4656 ops[i].cc_scratch = magic;
4659 if (po->op == OP_CALL)
4661 if (po->flags & OPF_JMP) {
4662 if (po->btj != NULL) {
4664 for (j = 0; j < po->btj->count; j++) {
4665 check_i(po, po->btj->d[j].bt_i);
4666 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4672 if (po->flags & OPF_RMD)
4674 check_i(po, po->bt_i);
4675 if (po->flags & OPF_CJMP)
4682 if (!(po->flags & OPF_CC)) {
4683 if (po->flags & OPF_FLAGS)
4686 if (po->flags & OPF_TAIL)
4702 static int try_resolve_const(int i, const struct parsed_opr *opr,
4703 int magic, unsigned int *val)
4708 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4711 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4714 *val = ops[i].operand[1].val;
4721 static int resolve_used_bits(int i, int opcnt, int reg,
4722 int *mask, int *is_z_check)
4724 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4728 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4732 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4734 fnote(&ops[j], "(first read)\n");
4735 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4738 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4739 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4741 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4742 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4744 *mask = ops[j].operand[1].val;
4745 if (ops[j].operand[0].lmod == OPLM_BYTE
4746 && ops[j].operand[0].name[1] == 'h')
4750 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4753 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4755 *is_z_check = ops[k].pfo == PFO_Z;
4760 static const struct parsed_proto *resolve_deref(int i, int magic,
4761 struct parsed_opr *opr, int level)
4763 struct parsed_opr opr_s = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
4764 const struct parsed_proto *pp = NULL;
4765 int from_caller = 0;
4774 ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4775 if (ret != 2 || len != strlen(opr->name)) {
4776 ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4777 if (ret != 1 || len != strlen(opr->name))
4781 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4786 ret = resolve_origin(i, &opr_s, i + magic, &j, NULL);
4790 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4791 && strlen(ops[j].operand[1].name) == 3
4792 && ops[j].operand[0].lmod == OPLM_DWORD
4793 && ops[j].pp == NULL // no hint
4796 // allow one simple dereference (com/directx)
4797 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4798 ops[j].operand[1].name);
4802 ret = resolve_origin(j, &opr_s, j + magic, &k, NULL);
4807 if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
4810 if (ops[j].pp != NULL) {
4814 else if (ops[j].operand[1].type == OPT_REGMEM) {
4815 pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
4817 // maybe structure ptr in structure
4818 pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
4821 else if (ops[j].operand[1].type == OPT_LABEL)
4822 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4823 else if (ops[j].operand[1].type == OPT_REG) {
4826 ret = resolve_origin(j, &ops[j].operand[1], i + magic,
4828 if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
4829 for (k = 0; k < g_func_pp->argc; k++) {
4830 if (g_func_pp->arg[k].reg == NULL)
4832 if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
4833 pp = g_func_pp->arg[k].pp;
4842 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4844 ferr(&ops[j], "expected struct, got '%s %s'\n",
4845 pp->type.name, pp->name);
4849 return proto_lookup_struct(g_fhdr, pp->type.name, offset);
4852 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4853 int *pp_i, int *multi_src)
4855 const struct parsed_proto *pp = NULL;
4856 int search_advice = 0;
4861 switch (ops[i].operand[0].type) {
4863 // try to resolve struct member calls
4864 pp = resolve_deref(i, i + opcnt * 19, &ops[i].operand[0], 0);
4870 pp = try_recover_pp(&ops[i], &ops[i].operand[0],
4876 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4884 static struct parsed_proto *process_call_early(int i, int opcnt,
4887 struct parsed_op *po = &ops[i];
4888 struct parsed_proto *pp;
4894 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4898 // look for and make use of esp adjust
4900 if (!pp->is_stdcall && pp->argc_stack > 0)
4901 ret = scan_for_esp_adjust(i + 1, opcnt,
4902 pp->argc_stack * 4, &adj, &multipath, 0);
4904 if (pp->argc_stack > adj / 4)
4908 if (ops[ret].op == OP_POP) {
4909 for (j = 1; j < adj / 4; j++) {
4910 if (ops[ret + j].op != OP_POP
4911 || ops[ret + j].operand[0].reg != xCX)
4923 static struct parsed_proto *process_call(int i, int opcnt)
4925 struct parsed_op *po = &ops[i];
4926 const struct parsed_proto *pp_c;
4927 struct parsed_proto *pp;
4928 const char *tmpname;
4929 int call_i = -1, ref_i = -1;
4930 int adj = 0, multipath = 0;
4933 tmpname = opr_name(po, 0);
4938 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4940 if (!pp_c->is_func && !pp_c->is_fptr)
4941 ferr(po, "call to non-func: %s\n", pp_c->name);
4942 pp = proto_clone(pp_c);
4943 my_assert_not(pp, NULL);
4945 // not resolved just to single func
4948 switch (po->operand[0].type) {
4950 // we resolved this call and no longer need the register
4951 po->regmask_src &= ~(1 << po->operand[0].reg);
4953 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4954 && ops[call_i].operand[1].type == OPT_LABEL)
4956 // no other source users?
4957 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4959 if (ret == 1 && call_i == ref_i) {
4960 // and nothing uses it after us?
4962 find_next_read(i + 1, opcnt, &po->operand[0],
4963 i + opcnt * 11, &ref_i);
4965 // then also don't need the source mov
4966 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4978 pp = calloc(1, sizeof(*pp));
4979 my_assert_not(pp, NULL);
4982 ret = scan_for_esp_adjust(i + 1, opcnt,
4983 -1, &adj, &multipath, 0);
4984 if (ret < 0 || adj < 0) {
4985 if (!g_allow_regfunc)
4986 ferr(po, "non-__cdecl indirect call unhandled yet\n");
4987 pp->is_unresolved = 1;
4991 if (adj > ARRAY_SIZE(pp->arg))
4992 ferr(po, "esp adjust too large: %d\n", adj);
4993 pp->ret_type.name = strdup("int");
4994 pp->argc = pp->argc_stack = adj;
4995 for (arg = 0; arg < pp->argc; arg++)
4996 pp->arg[arg].type.name = strdup("int");
5001 // look for and make use of esp adjust
5004 if (!pp->is_stdcall && pp->argc_stack > 0) {
5005 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
5006 ret = scan_for_esp_adjust(i + 1, opcnt,
5007 adj_expect, &adj, &multipath, 0);
5010 if (pp->is_vararg) {
5011 if (adj / 4 < pp->argc_stack) {
5012 fnote(po, "(this call)\n");
5013 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
5014 adj, pp->argc_stack * 4);
5016 // modify pp to make it have varargs as normal args
5018 pp->argc += adj / 4 - pp->argc_stack;
5019 for (; arg < pp->argc; arg++) {
5020 pp->arg[arg].type.name = strdup("int");
5023 if (pp->argc > ARRAY_SIZE(pp->arg))
5024 ferr(po, "too many args for '%s'\n", tmpname);
5026 if (pp->argc_stack > adj / 4) {
5027 if (pp->is_noreturn)
5028 // assume no stack adjust was emited
5030 fnote(po, "(this call)\n");
5031 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
5032 tmpname, pp->argc_stack * 4, adj);
5035 scan_for_esp_adjust(i + 1, opcnt,
5036 pp->argc_stack * 4, &adj, &multipath, 1);
5038 else if (pp->is_vararg)
5039 ferr(po, "missing esp_adjust for vararg func '%s'\n",
5046 static void mark_float_arg(struct parsed_op *po,
5047 struct parsed_proto *pp, int arg, int *regmask_ffca)
5050 po->p_argnum = arg + 1;
5051 ferr_assert(po, pp->arg[arg].datap == NULL);
5052 pp->arg[arg].datap = po;
5053 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
5054 if (regmask_ffca != NULL)
5055 *regmask_ffca |= 1 << arg;
5058 static int check_for_stp(int i, int i_to)
5060 struct parsed_op *po;
5062 for (; i < i_to; i++) {
5064 if (po->op == OP_FST)
5066 if (g_labels[i] != NULL || (po->flags & OPF_JMP))
5068 if (po->op == OP_CALL || po->op == OP_PUSH || po->op == OP_POP)
5070 if (po->op == OP_ADD && po->operand[0].reg == xSP)
5077 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
5080 struct parsed_op *po;
5086 for (base_arg = 0; base_arg < pp->argc; base_arg++)
5087 if (pp->arg[base_arg].reg == NULL)
5090 for (j = i; j > 0; )
5092 ferr_assert(&ops[j], g_labels[j] == NULL);
5096 ferr_assert(po, po->op != OP_PUSH);
5097 if (po->op == OP_FST)
5099 if (po->operand[0].type != OPT_REGMEM)
5101 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
5104 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3)) {
5105 //ferr(po, "offset %d, %d args\n", offset, pp->argc_stack);
5109 arg = base_arg + offset / 4;
5110 mark_float_arg(po, pp, arg, regmask_ffca);
5112 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5113 && po->operand[1].type == OPT_CONST)
5115 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5120 for (arg = base_arg; arg < pp->argc; arg++) {
5121 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
5122 po = pp->arg[arg].datap;
5124 ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
5125 if (po->operand[0].lmod == OPLM_QWORD)
5132 static int collect_call_args_early(int i, struct parsed_proto *pp,
5133 int *regmask, int *regmask_ffca)
5135 struct parsed_op *po;
5140 for (arg = 0; arg < pp->argc; arg++)
5141 if (pp->arg[arg].reg == NULL)
5144 // first see if it can be easily done
5145 for (j = i; j > 0 && arg < pp->argc; )
5147 if (g_labels[j] != NULL)
5152 if (po->op == OP_CALL)
5154 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
5156 else if (po->op == OP_POP)
5158 else if (po->flags & OPF_CJMP)
5160 else if (po->op == OP_PUSH) {
5161 if (po->flags & (OPF_FARG|OPF_FARGNR))
5163 if (!g_header_mode) {
5164 ret = scan_for_mod(po, j + 1, i, 1);
5169 if (pp->arg[arg].type.is_va_list)
5173 for (arg++; arg < pp->argc; arg++)
5174 if (pp->arg[arg].reg == NULL)
5177 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5178 && po->operand[1].type == OPT_CONST)
5180 if (po->flags & (OPF_RMD|OPF_DONE))
5182 if (po->operand[1].val != pp->argc_stack * 4)
5183 ferr(po, "unexpected esp adjust: %d\n",
5184 po->operand[1].val * 4);
5185 ferr_assert(po, pp->argc - arg == pp->argc_stack);
5186 return collect_call_args_no_push(i, pp, regmask_ffca);
5194 for (arg = 0; arg < pp->argc; arg++)
5195 if (pp->arg[arg].reg == NULL)
5198 for (j = i; j > 0 && arg < pp->argc; )
5202 if (ops[j].op == OP_PUSH)
5204 ops[j].p_argnext = -1;
5205 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
5207 k = check_for_stp(j + 1, i);
5209 // push ecx; fstp dword ptr [esp]
5210 ret = parse_stack_esp_offset(&ops[k],
5211 ops[k].operand[0].name, &offset);
5212 if (ret == 0 && offset == 0) {
5213 if (!pp->arg[arg].type.is_float)
5214 ferr(&ops[i], "arg %d should be float\n", arg + 1);
5215 mark_float_arg(&ops[k], pp, arg, regmask_ffca);
5219 if (pp->arg[arg].datap == NULL) {
5220 pp->arg[arg].datap = &ops[j];
5221 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
5222 *regmask |= 1 << ops[j].operand[0].reg;
5225 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5226 ops[j].flags &= ~OPF_RSAVE;
5229 for (arg++; arg < pp->argc; arg++)
5230 if (pp->arg[arg].reg == NULL)
5238 static int sync_argnum(struct parsed_op *po, int argnum)
5240 struct parsed_op *po_tmp;
5242 // see if other branches don't have higher argnum
5243 for (po_tmp = po; po_tmp != NULL; ) {
5244 if (argnum < po_tmp->p_argnum)
5245 argnum = po_tmp->p_argnum;
5246 // note: p_argnext is active on current collect_call_args only
5247 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5250 // make all argnums consistent
5251 for (po_tmp = po; po_tmp != NULL; ) {
5252 if (po_tmp->p_argnum != 0)
5253 po_tmp->p_argnum = argnum;
5254 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5260 static int collect_call_args_r(struct parsed_op *po, int i,
5261 struct parsed_proto *pp, int *regmask, int *arg_grp,
5262 int arg, int argnum, int magic, int need_op_saving, int may_reuse)
5264 struct parsed_proto *pp_tmp;
5265 struct parsed_op *po_tmp;
5266 struct label_ref *lr;
5267 int need_to_save_current;
5268 int arg_grp_current = 0;
5269 int save_args_seen = 0;
5276 ferr(po, "dead label encountered\n");
5280 for (; arg < pp->argc; arg++, argnum++)
5281 if (pp->arg[arg].reg == NULL)
5283 magic = (magic & 0xffffff) | (arg << 24);
5285 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
5287 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
5288 if (ops[j].cc_scratch != magic) {
5289 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
5293 // ok: have already been here
5296 ops[j].cc_scratch = magic;
5298 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
5299 lr = &g_label_refs[j];
5300 if (lr->next != NULL)
5302 for (; lr->next; lr = lr->next) {
5303 check_i(&ops[j], lr->i);
5304 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5306 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5307 arg, argnum, magic, need_op_saving, may_reuse);
5312 check_i(&ops[j], lr->i);
5313 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5315 if (j > 0 && LAST_OP(j - 1)) {
5316 // follow last branch in reverse
5321 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5322 arg, argnum, magic, need_op_saving, may_reuse);
5328 if (ops[j].op == OP_CALL)
5330 if (pp->is_unresolved)
5335 ferr(po, "arg collect %d/%d hit unparsed call '%s'\n",
5336 arg, pp->argc, ops[j].operand[0].name);
5337 if (may_reuse && pp_tmp->argc_stack > 0)
5338 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
5339 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
5341 // esp adjust of 0 means we collected it before
5342 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
5343 && (ops[j].operand[1].type != OPT_CONST
5344 || ops[j].operand[1].val != 0))
5346 if (pp->is_unresolved)
5349 fnote(po, "(this call)\n");
5350 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
5351 arg, pp->argc, ops[j].operand[1].val);
5353 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
5355 if (pp->is_unresolved)
5358 fnote(po, "(this call)\n");
5359 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
5361 else if (ops[j].flags & OPF_CJMP)
5363 if (pp->is_unresolved)
5368 else if (ops[j].op == OP_PUSH
5369 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
5371 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
5374 ops[j].p_argnext = -1;
5375 po_tmp = pp->arg[arg].datap;
5377 ops[j].p_argnext = po_tmp - ops;
5378 pp->arg[arg].datap = &ops[j];
5380 argnum = sync_argnum(&ops[j], argnum);
5382 need_to_save_current = 0;
5384 if (ops[j].operand[0].type == OPT_REG)
5385 reg = ops[j].operand[0].reg;
5387 if (!need_op_saving) {
5388 ret = scan_for_mod(&ops[j], j + 1, i, 1);
5389 need_to_save_current = (ret >= 0);
5391 if (need_op_saving || need_to_save_current) {
5392 // mark this arg as one that needs operand saving
5393 pp->arg[arg].is_saved = 1;
5395 if (save_args_seen & (1 << (argnum - 1))) {
5398 if (arg_grp_current >= MAX_ARG_GRP)
5399 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
5403 else if (ops[j].p_argnum == 0)
5404 ops[j].flags |= OPF_RMD;
5406 // some PUSHes are reused by different calls on other branches,
5407 // but that can't happen if we didn't branch, so they
5408 // can be removed from future searches (handles nested calls)
5410 ops[j].flags |= OPF_FARGNR;
5412 ops[j].flags |= OPF_FARG;
5413 ops[j].flags &= ~OPF_RSAVE;
5415 // check for __VALIST
5416 if (!pp->is_unresolved && g_func_pp != NULL
5417 && pp->arg[arg].type.is_va_list)
5420 ret = resolve_origin(j, &ops[j].operand[0],
5421 magic + 1, &k, NULL);
5422 if (ret == 1 && k >= 0)
5424 if (ops[k].op == OP_LEA) {
5425 if (!g_func_pp->is_vararg)
5426 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
5429 snprintf(buf, sizeof(buf), "arg_%X",
5430 g_func_pp->argc_stack * 4);
5431 if (strstr(ops[k].operand[1].name, buf)
5432 || strstr(ops[k].operand[1].name, "arglist"))
5434 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
5435 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
5436 pp->arg[arg].is_saved = 0;
5440 ferr(&ops[k], "va_list arg detection failed\n");
5442 // check for va_list from g_func_pp arg too
5443 else if (ops[k].op == OP_MOV
5444 && is_stack_access(&ops[k], &ops[k].operand[1]))
5446 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5447 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5449 ops[k].flags |= OPF_RMD | OPF_DONE;
5450 ops[j].flags |= OPF_RMD;
5451 ops[j].p_argpass = ret + 1;
5452 pp->arg[arg].is_saved = 0;
5459 if (pp->arg[arg].is_saved) {
5460 ops[j].flags &= ~OPF_RMD;
5461 ops[j].p_argnum = argnum;
5464 // tracking reg usage
5466 *regmask |= 1 << reg;
5470 if (!pp->is_unresolved) {
5472 for (; arg < pp->argc; arg++, argnum++)
5473 if (pp->arg[arg].reg == NULL)
5476 magic = (magic & 0xffffff) | (arg << 24);
5479 if (ops[j].p_arggrp > arg_grp_current) {
5481 arg_grp_current = ops[j].p_arggrp;
5483 if (ops[j].p_argnum > 0)
5484 save_args_seen |= 1 << (ops[j].p_argnum - 1);
5487 if (arg < pp->argc) {
5488 ferr(po, "arg collect failed for '%s': %d/%d\n",
5489 pp->name, arg, pp->argc);
5493 if (arg_grp_current > *arg_grp)
5494 *arg_grp = arg_grp_current;
5499 static int collect_call_args(struct parsed_op *po, int i,
5500 struct parsed_proto *pp, int *regmask, int magic)
5502 // arg group is for cases when pushes for
5503 // multiple funcs are going on
5504 struct parsed_op *po_tmp;
5509 ret = collect_call_args_r(po, i, pp, regmask, &arg_grp,
5515 // propagate arg_grp
5516 for (a = 0; a < pp->argc; a++) {
5517 if (pp->arg[a].reg != NULL)
5520 po_tmp = pp->arg[a].datap;
5521 while (po_tmp != NULL) {
5522 po_tmp->p_arggrp = arg_grp;
5523 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5528 if (pp->is_unresolved) {
5530 pp->argc_stack += ret;
5531 for (a = 0; a < pp->argc; a++)
5532 if (pp->arg[a].type.name == NULL)
5533 pp->arg[a].type.name = strdup("int");
5539 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5540 int regmask_now, int *regmask,
5541 int regmask_save_now, int *regmask_save,
5542 int *regmask_init, int regmask_arg)
5544 struct parsed_op *po;
5552 for (; i < opcnt; i++)
5555 if (cbits[i >> 3] & (1 << (i & 7)))
5557 cbits[i >> 3] |= (1 << (i & 7));
5559 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5560 if (po->flags & (OPF_RMD|OPF_DONE))
5562 if (po->btj != NULL) {
5563 for (j = 0; j < po->btj->count; j++) {
5564 check_i(po, po->btj->d[j].bt_i);
5565 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5566 regmask_now, regmask, regmask_save_now, regmask_save,
5567 regmask_init, regmask_arg);
5572 check_i(po, po->bt_i);
5573 if (po->flags & OPF_CJMP)
5574 reg_use_pass(po->bt_i, opcnt, cbits,
5575 regmask_now, regmask, regmask_save_now, regmask_save,
5576 regmask_init, regmask_arg);
5582 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5583 && !g_func_pp->is_userstack
5584 && po->operand[0].type == OPT_REG)
5586 reg = po->operand[0].reg;
5587 ferr_assert(po, reg >= 0);
5590 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5591 if (regmask_now & (1 << reg)) {
5592 already_saved = regmask_save_now & (1 << reg);
5593 flags_set = OPF_RSAVE | OPF_DONE;
5596 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, 0);
5598 scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5599 reg, 0, 0, flags_set);
5602 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5604 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5609 ferr_assert(po, !already_saved);
5610 po->flags |= flags_set;
5612 if (regmask_now & (1 << reg)) {
5613 regmask_save_now |= (1 << reg);
5614 *regmask_save |= regmask_save_now;
5619 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5620 reg = po->operand[0].reg;
5621 ferr_assert(po, reg >= 0);
5623 if (regmask_save_now & (1 << reg))
5624 regmask_save_now &= ~(1 << reg);
5626 regmask_now &= ~(1 << reg);
5629 else if (po->op == OP_CALL) {
5630 if ((po->regmask_dst & (1 << xAX))
5631 && !(po->regmask_dst & (1 << xDX)))
5633 if (po->flags & OPF_TAIL)
5634 // don't need eax, will do "return f();" or "f(); return;"
5635 po->regmask_dst &= ~(1 << xAX);
5637 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
5639 find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
5642 po->regmask_dst &= ~(1 << xAX);
5646 // not "full stack" mode and have something in stack
5647 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5648 ferr(po, "float stack is not empty on func call\n");
5651 if (po->flags & OPF_NOREGS)
5654 // if incomplete register is used, clear it on init to avoid
5655 // later use of uninitialized upper part in some situations
5656 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5657 && po->operand[0].lmod != OPLM_DWORD)
5659 reg = po->operand[0].reg;
5660 ferr_assert(po, reg >= 0);
5662 if (!(regmask_now & (1 << reg)))
5663 *regmask_init |= 1 << reg;
5666 regmask_op = po->regmask_src | po->regmask_dst;
5668 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5669 regmask_new &= ~(1 << xSP);
5670 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5671 regmask_new &= ~(1 << xBP);
5673 if (regmask_new != 0)
5674 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5676 if (regmask_op & (1 << xBP)) {
5677 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5678 if (po->regmask_dst & (1 << xBP))
5679 // compiler decided to drop bp frame and use ebp as scratch
5680 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5682 regmask_op &= ~(1 << xBP);
5686 if (po->flags & OPF_FPUSH) {
5687 if (regmask_now & mxST1)
5688 regmask_now |= mxSTa; // switch to "full stack" mode
5689 if (regmask_now & mxSTa)
5690 po->flags |= OPF_FSHIFT;
5691 if (!(regmask_now & mxST7_2)) {
5693 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5697 regmask_now |= regmask_op;
5698 *regmask |= regmask_now;
5701 if (po->flags & OPF_FPOPP) {
5702 if ((regmask_now & mxSTa) == 0)
5703 ferr(po, "float pop on empty stack?\n");
5704 if (regmask_now & mxST7_2)
5705 po->flags |= OPF_FSHIFT;
5706 if (!(regmask_now & mxST7_2))
5707 regmask_now &= ~mxST1_0;
5709 else if (po->flags & OPF_FPOP) {
5710 if ((regmask_now & mxSTa) == 0)
5711 ferr(po, "float pop on empty stack?\n");
5712 if (regmask_now & (mxST7_2 | mxST1))
5713 po->flags |= OPF_FSHIFT;
5714 if (!(regmask_now & mxST7_2)) {
5716 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5720 if (po->flags & OPF_TAIL) {
5721 if (!(regmask_now & mxST7_2)) {
5722 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5723 if (!(regmask_now & mxST0))
5724 ferr(po, "no st0 on float return, mask: %x\n",
5727 else if (regmask_now & mxST1_0)
5728 ferr(po, "float regs on tail: %x\n", regmask_now);
5731 // there is support for "conditional tailcall", sort of
5732 if (!(po->flags & OPF_CC))
5738 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5742 for (i = 0; i < pp->argc; i++)
5743 if (pp->arg[i].reg == NULL)
5747 memmove(&pp->arg[i + 1], &pp->arg[i],
5748 sizeof(pp->arg[0]) * pp->argc_stack);
5749 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5750 pp->arg[i].reg = strdup(reg);
5751 pp->arg[i].type.name = strdup("int");
5756 static void output_std_flag_z(FILE *fout, struct parsed_op *po,
5757 int *pfomask, const char *dst_opr_text)
5759 if (*pfomask & (1 << PFO_Z)) {
5760 fprintf(fout, "\n cond_z = (%s%s == 0);",
5761 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5762 *pfomask &= ~(1 << PFO_Z);
5766 static void output_std_flag_s(FILE *fout, struct parsed_op *po,
5767 int *pfomask, const char *dst_opr_text)
5769 if (*pfomask & (1 << PFO_S)) {
5770 fprintf(fout, "\n cond_s = (%s%s < 0);",
5771 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5772 *pfomask &= ~(1 << PFO_S);
5776 static void output_std_flags(FILE *fout, struct parsed_op *po,
5777 int *pfomask, const char *dst_opr_text)
5779 output_std_flag_z(fout, po, pfomask, dst_opr_text);
5780 output_std_flag_s(fout, po, pfomask, dst_opr_text);
5784 OPP_FORCE_NORETURN = (1 << 0),
5785 OPP_SIMPLE_ARGS = (1 << 1),
5786 OPP_ALIGN = (1 << 2),
5789 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
5792 const char *cconv = "";
5794 if (pp->is_fastcall)
5795 cconv = "__fastcall ";
5796 else if (pp->is_stdcall && pp->argc_reg == 0)
5797 cconv = "__stdcall ";
5799 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5801 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
5802 fprintf(fout, "noreturn ");
5805 static void output_pp(FILE *fout, const struct parsed_proto *pp,
5810 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5814 output_pp_attrs(fout, pp, flags);
5817 fprintf(fout, "%s", pp->name);
5822 for (i = 0; i < pp->argc; i++) {
5824 fprintf(fout, ", ");
5825 if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
5826 && !(flags & OPP_SIMPLE_ARGS))
5829 output_pp(fout, pp->arg[i].pp, 0);
5831 else if (pp->arg[i].type.is_retreg) {
5832 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
5835 fprintf(fout, "%s", pp->arg[i].type.name);
5837 fprintf(fout, " a%d", i + 1);
5840 if (pp->arg[i].type.is_64bit)
5843 if (pp->is_vararg) {
5845 fprintf(fout, ", ");
5846 fprintf(fout, "...");
5851 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
5857 snprintf(buf1, sizeof(buf1), "%d", grp);
5858 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
5863 static void gen_x_cleanup(int opcnt);
5865 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
5867 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
5868 struct parsed_opr *last_arith_dst = NULL;
5869 char buf1[256], buf2[256], buf3[256], cast[64];
5870 struct parsed_proto *pp, *pp_tmp;
5871 struct parsed_data *pd;
5872 int save_arg_vars[MAX_ARG_GRP] = { 0, };
5873 unsigned char cbits[MAX_OPS / 8];
5874 const char *float_type;
5875 const char *float_st0;
5876 const char *float_st1;
5877 int need_float_stack = 0;
5878 int need_float_sw = 0; // status word
5879 int need_tmp_var = 0;
5883 int label_pending = 0;
5884 int need_double = 0;
5885 int stack_align = 0;
5886 int stack_fsz_adj = 0;
5887 int regmask_save = 0; // used regs saved/restored in this func
5888 int regmask_arg; // regs from this function args (fastcall, etc)
5889 int regmask_ret; // regs needed on ret
5890 int regmask_now; // temp
5891 int regmask_init = 0; // regs that need zero initialization
5892 int regmask_pp = 0; // regs used in complex push-pop graph
5893 int regmask_ffca = 0; // float function call args
5894 int regmask = 0; // used regs
5904 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
5905 g_stack_frame_used = 0;
5907 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
5908 regmask_init = g_regmask_init;
5910 g_func_pp = proto_parse(fhdr, funcn, 0);
5911 if (g_func_pp == NULL)
5912 ferr(ops, "proto_parse failed for '%s'\n", funcn);
5914 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
5915 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
5918 // - resolve all branches
5919 // - parse calls with labels
5920 resolve_branches_parse_calls(opcnt);
5923 // - handle ebp/esp frame, remove ops related to it
5924 scan_prologue_epilogue(opcnt, &stack_align);
5926 // handle a case where sf size is unalignment, but is
5927 // placed in a way that elements are still aligned
5928 if (g_stack_fsz & 4) {
5929 for (i = 0; i < g_eqcnt; i++) {
5930 if (g_eqs[i].lmod != OPLM_QWORD)
5932 if (!(g_eqs[i].offset & 4)) {
5941 // - remove dead labels
5942 // - set regs needed at ret
5943 for (i = 0; i < opcnt; i++)
5945 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
5950 if (ops[i].op == OP_RET)
5951 ops[i].regmask_src |= regmask_ret;
5955 // - process trivial calls
5956 for (i = 0; i < opcnt; i++)
5959 if (po->flags & (OPF_RMD|OPF_DONE))
5962 if (po->op == OP_CALL)
5964 pp = process_call_early(i, opcnt, &j);
5966 if (!(po->flags & OPF_ATAIL)) {
5967 // since we know the args, try to collect them
5968 ret = collect_call_args_early(i, pp, ®mask, ®mask_ffca);
5976 // commit esp adjust
5977 if (ops[j].op != OP_POP)
5978 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5980 for (l = 0; l < pp->argc_stack; l++)
5981 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
5985 if (strstr(pp->ret_type.name, "int64"))
5988 po->flags |= OPF_DONE;
5994 // - process calls, stage 2
5995 // - handle some push/pop pairs
5996 // - scan for STD/CLD, propagate DF
5997 // - try to resolve needed x87 status word bits
5998 for (i = 0; i < opcnt; i++)
6003 if (po->flags & OPF_RMD)
6006 if (po->op == OP_CALL)
6008 if (!(po->flags & OPF_DONE)) {
6009 pp = process_call(i, opcnt);
6011 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
6012 // since we know the args, collect them
6013 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
6015 // for unresolved, collect after other passes
6019 ferr_assert(po, pp != NULL);
6021 po->regmask_src |= get_pp_arg_regmask_src(pp);
6022 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
6024 if (po->regmask_dst & mxST0)
6025 po->flags |= OPF_FPUSH;
6027 if (strstr(pp->ret_type.name, "int64"))
6033 if (po->flags & OPF_DONE)
6038 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
6039 && po->operand[0].type == OPT_CONST)
6041 scan_for_pop_const(i, opcnt, i + opcnt * 12);
6046 scan_pushes_for_pop(i, opcnt, ®mask_pp);
6050 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
6051 scan_propagate_df(i + 1, opcnt);
6056 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
6057 ferr(po, "TODO: fnstsw to mem\n");
6058 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
6060 ferr(po, "fnstsw resolve failed\n");
6061 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
6062 (void *)(long)(mask | (z_check << 16)));
6064 ferr(po, "failed to find fcom: %d\n", ret);
6073 // - find POPs for PUSHes, rm both
6074 // - scan for all used registers
6075 memset(cbits, 0, sizeof(cbits));
6076 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
6077 0, ®mask_save, ®mask_init, regmask_arg);
6079 need_float_stack = !!(regmask & mxST7_2);
6082 // - find flag set ops for their users
6083 // - do unresolved calls
6084 // - declare indirect functions
6085 // - other op specific processing
6086 for (i = 0; i < opcnt; i++)
6089 if (po->flags & (OPF_RMD|OPF_DONE))
6092 if (po->flags & OPF_CC)
6094 int setters[16], cnt = 0, branched = 0;
6096 ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
6097 &branched, setters, &cnt);
6098 if (ret < 0 || cnt <= 0)
6099 ferr(po, "unable to trace flag setter(s)\n");
6100 if (cnt > ARRAY_SIZE(setters))
6101 ferr(po, "too many flag setters\n");
6103 for (j = 0; j < cnt; j++)
6105 tmp_op = &ops[setters[j]]; // flag setter
6108 // to get nicer code, we try to delay test and cmp;
6109 // if we can't because of operand modification, or if we
6110 // have arith op, or branch, make it calculate flags explicitly
6111 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
6113 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
6114 pfomask = 1 << po->pfo;
6116 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
6117 pfomask = 1 << po->pfo;
6120 // see if we'll be able to handle based on op result
6121 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
6122 && po->pfo != PFO_Z && po->pfo != PFO_S
6123 && po->pfo != PFO_P)
6125 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
6127 pfomask = 1 << po->pfo;
6130 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
6131 propagate_lmod(tmp_op, &tmp_op->operand[0],
6132 &tmp_op->operand[1]);
6133 if (tmp_op->operand[0].lmod == OPLM_DWORD)
6138 tmp_op->pfomask |= pfomask;
6139 cond_vars |= pfomask;
6141 // note: may overwrite, currently not a problem
6145 if (po->op == OP_RCL || po->op == OP_RCR
6146 || po->op == OP_ADC || po->op == OP_SBB)
6147 cond_vars |= 1 << PFO_C;
6153 cond_vars |= 1 << PFO_Z;
6157 if (po->operand[0].lmod == OPLM_DWORD)
6162 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
6167 // note: resolved non-reg calls are OPF_DONE already
6169 ferr_assert(po, pp != NULL);
6171 if (pp->is_unresolved) {
6172 int regmask_stack = 0;
6173 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
6175 // this is pretty rough guess:
6176 // see ecx and edx were pushed (and not their saved versions)
6177 for (arg = 0; arg < pp->argc; arg++) {
6178 if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
6181 tmp_op = pp->arg[arg].datap;
6183 ferr(po, "parsed_op missing for arg%d\n", arg);
6184 if (tmp_op->operand[0].type == OPT_REG)
6185 regmask_stack |= 1 << tmp_op->operand[0].reg;
6188 if (!((regmask_stack & (1 << xCX))
6189 && (regmask_stack & (1 << xDX))))
6191 if (pp->argc_stack != 0
6192 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
6194 pp_insert_reg_arg(pp, "ecx");
6195 pp->is_fastcall = 1;
6196 regmask_init |= 1 << xCX;
6197 regmask |= 1 << xCX;
6199 if (pp->argc_stack != 0
6200 || ((regmask | regmask_arg) & (1 << xDX)))
6202 pp_insert_reg_arg(pp, "edx");
6203 regmask_init |= 1 << xDX;
6204 regmask |= 1 << xDX;
6208 // note: __cdecl doesn't fall into is_unresolved category
6209 if (pp->argc_stack > 0)
6215 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
6217 // <var> = offset <something>
6218 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
6219 && !IS_START(po->operand[1].name, "off_"))
6221 if (!po->operand[0].pp->is_fptr)
6222 ferr(po, "%s not declared as fptr when it should be\n",
6223 po->operand[0].name);
6224 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
6225 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
6226 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
6227 fnote(po, "var: %s\n", buf1);
6228 fnote(po, "func: %s\n", buf2);
6229 ferr(po, "^ mismatch\n");
6237 if (po->operand[0].lmod == OPLM_DWORD) {
6238 // 32bit division is common, look for it
6239 if (po->op == OP_DIV)
6240 ret = scan_for_reg_clear(i, xDX);
6242 ret = scan_for_cdq_edx(i);
6244 po->flags |= OPF_32BIT;
6253 po->flags |= OPF_RMD | OPF_DONE;
6263 if (po->operand[0].lmod == OPLM_QWORD)
6273 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
6275 find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
6277 po->flags |= OPF_32BIT;
6285 // this might need it's own pass...
6286 if (po->op != OP_FST && po->p_argnum > 0)
6287 save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
6289 // correct for "full stack" mode late enable
6290 if ((po->flags & (OPF_PPUSH|OPF_FPOP|OPF_FPOPP))
6291 && need_float_stack)
6292 po->flags |= OPF_FSHIFT;
6295 float_type = need_double ? "double" : "float";
6296 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
6297 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
6299 // output starts here
6302 fprintf(fout, "// had SEH\n");
6304 // define userstack size
6305 if (g_func_pp->is_userstack) {
6306 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
6307 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
6308 fprintf(fout, "#endif\n");
6311 // the function itself
6312 ferr_assert(ops, !g_func_pp->is_fptr);
6313 output_pp(fout, g_func_pp,
6314 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
6315 fprintf(fout, "\n{\n");
6317 // declare indirect functions
6318 for (i = 0; i < opcnt; i++) {
6320 if (po->flags & OPF_RMD)
6323 if (po->op == OP_CALL) {
6326 ferr(po, "NULL pp\n");
6328 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
6329 if (pp->name[0] != 0) {
6330 if (IS_START(pp->name, "guess"))
6333 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
6334 memcpy(pp->name, "i_", 2);
6336 // might be declared already
6338 for (j = 0; j < i; j++) {
6339 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
6340 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
6350 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
6353 output_pp(fout, pp, OPP_SIMPLE_ARGS);
6354 fprintf(fout, ";\n");
6359 // output LUTs/jumptables
6360 for (i = 0; i < g_func_pd_cnt; i++) {
6362 fprintf(fout, " static const ");
6363 if (pd->type == OPT_OFFSET) {
6364 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
6366 for (j = 0; j < pd->count; j++) {
6368 fprintf(fout, ", ");
6369 fprintf(fout, "&&%s", pd->d[j].u.label);
6373 fprintf(fout, "%s %s[] =\n { ",
6374 lmod_type_u(ops, pd->lmod), pd->label);
6376 for (j = 0; j < pd->count; j++) {
6378 fprintf(fout, ", ");
6379 fprintf(fout, "%u", pd->d[j].u.val);
6382 fprintf(fout, " };\n");
6386 // declare stack frame, va_arg
6389 fprintf(fout, " // stack_fsz_adj %d\n", stack_fsz_adj);
6391 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
6392 if (g_func_lmods & (1 << OPLM_WORD))
6393 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
6394 if (g_func_lmods & (1 << OPLM_BYTE))
6395 fprintf(fout, " u8 b[%d];", g_stack_fsz);
6396 if (g_func_lmods & (1 << OPLM_QWORD))
6397 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
6399 if (stack_align > 8)
6400 ferr(ops, "unhandled stack align of %d\n", stack_align);
6401 else if (stack_align == 8)
6402 fprintf(fout, " u64 align;");
6403 fprintf(fout, " } sf;\n");
6407 if (g_func_pp->is_userstack) {
6408 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
6409 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
6413 if (g_func_pp->is_vararg) {
6414 fprintf(fout, " va_list ap;\n");
6418 // declare arg-registers
6419 for (i = 0; i < g_func_pp->argc; i++) {
6420 if (g_func_pp->arg[i].reg != NULL) {
6421 reg = char_array_i(regs_r32,
6422 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
6423 if (regmask & (1 << reg)) {
6424 if (g_func_pp->arg[i].type.is_retreg)
6425 fprintf(fout, " u32 %s = *r_%s;\n",
6426 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
6428 fprintf(fout, " u32 %s = (u32)a%d;\n",
6429 g_func_pp->arg[i].reg, i + 1);
6432 if (g_func_pp->arg[i].type.is_retreg)
6433 ferr(ops, "retreg '%s' is unused?\n",
6434 g_func_pp->arg[i].reg);
6435 fprintf(fout, " // %s = a%d; // unused\n",
6436 g_func_pp->arg[i].reg, i + 1);
6442 // declare normal registers
6443 regmask_now = regmask & ~regmask_arg;
6444 regmask_now &= ~(1 << xSP);
6445 if (regmask_now & 0x00ff) {
6446 for (reg = 0; reg < 8; reg++) {
6447 if (regmask_now & (1 << reg)) {
6448 fprintf(fout, " u32 %s", regs_r32[reg]);
6449 if (regmask_init & (1 << reg))
6450 fprintf(fout, " = 0");
6451 fprintf(fout, ";\n");
6457 if (regmask_now & 0xff00) {
6458 for (reg = 8; reg < 16; reg++) {
6459 if (regmask_now & (1 << reg)) {
6460 fprintf(fout, " mmxr %s", regs_r32[reg]);
6461 if (regmask_init & (1 << reg))
6462 fprintf(fout, " = { 0, }");
6463 fprintf(fout, ";\n");
6469 if (need_float_stack) {
6470 fprintf(fout, " %s f_st[8];\n", float_type);
6471 fprintf(fout, " int f_stp = 0;\n");
6475 if (regmask_now & 0xff0000) {
6476 for (reg = 16; reg < 24; reg++) {
6477 if (regmask_now & (1 << reg)) {
6478 fprintf(fout, " %s f_st%d", float_type, reg - 16);
6479 if (regmask_init & (1 << reg))
6480 fprintf(fout, " = 0");
6481 fprintf(fout, ";\n");
6488 if (need_float_sw) {
6489 fprintf(fout, " u16 f_sw;\n");
6494 for (reg = 0; reg < 8; reg++) {
6495 if (regmask_save & (1 << reg)) {
6496 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
6502 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6503 if (save_arg_vars[i] == 0)
6505 for (reg = 0; reg < 32; reg++) {
6506 if (save_arg_vars[i] & (1 << reg)) {
6507 fprintf(fout, " u32 %s;\n",
6508 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
6515 for (reg = 0; reg < 32; reg++) {
6516 if (regmask_ffca & (1 << reg)) {
6517 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
6523 // declare push-pop temporaries
6525 for (reg = 0; reg < 8; reg++) {
6526 if (regmask_pp & (1 << reg)) {
6527 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
6534 for (i = 0; i < 8; i++) {
6535 if (cond_vars & (1 << i)) {
6536 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
6543 fprintf(fout, " u32 tmp;\n");
6548 fprintf(fout, " u64 tmp64;\n");
6553 fprintf(fout, "\n");
6555 // do stack clear, if needed
6556 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6558 if (g_stack_clear_len != 0) {
6559 if (g_stack_clear_len <= 4) {
6560 for (i = 0; i < g_stack_clear_len; i++)
6561 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6562 fprintf(fout, "0;\n");
6565 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6566 g_stack_clear_start, g_stack_clear_len * 4);
6570 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6573 if (g_func_pp->is_vararg) {
6574 if (g_func_pp->argc_stack == 0)
6575 ferr(ops, "vararg func without stack args?\n");
6576 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
6580 for (i = 0; i < opcnt; i++)
6582 if (g_labels[i] != NULL) {
6583 fprintf(fout, "\n%s:\n", g_labels[i]);
6586 delayed_flag_op = NULL;
6587 last_arith_dst = NULL;
6591 if (po->flags & OPF_RMD)
6596 #define assert_operand_cnt(n_) \
6597 if (po->operand_cnt != n_) \
6598 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6600 // conditional/flag using op?
6601 if (po->flags & OPF_CC)
6607 // we go through all this trouble to avoid using parsed_flag_op,
6608 // which makes generated code much nicer
6609 if (delayed_flag_op != NULL)
6611 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6612 po->pfo, po->pfo_inv);
6615 else if (last_arith_dst != NULL
6616 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6617 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6620 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6621 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6622 last_arith_dst->lmod, buf3);
6625 else if (tmp_op != NULL) {
6626 // use preprocessed flag calc results
6627 if (!(tmp_op->pfomask & (1 << po->pfo)))
6628 ferr(po, "not prepared for pfo %d\n", po->pfo);
6630 // note: pfo_inv was not yet applied
6631 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6632 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6635 ferr(po, "all methods of finding comparison failed\n");
6638 if (po->flags & OPF_JMP) {
6639 fprintf(fout, " if %s", buf1);
6641 else if (po->op == OP_RCL || po->op == OP_RCR
6642 || po->op == OP_ADC || po->op == OP_SBB)
6645 fprintf(fout, " cond_%s = %s;\n",
6646 parsed_flag_op_names[po->pfo], buf1);
6648 else if (po->flags & OPF_DATA) { // SETcc
6649 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6650 fprintf(fout, " %s = %s;", buf2, buf1);
6653 ferr(po, "unhandled conditional op\n");
6657 pfomask = po->pfomask;
6662 assert_operand_cnt(2);
6663 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6664 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6665 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
6666 fprintf(fout, " %s = %s;", buf1,
6667 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6672 assert_operand_cnt(2);
6673 po->operand[1].lmod = OPLM_DWORD; // always
6674 fprintf(fout, " %s = %s;",
6675 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6676 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6681 assert_operand_cnt(2);
6682 fprintf(fout, " %s = %s;",
6683 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6684 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6688 assert_operand_cnt(2);
6689 switch (po->operand[1].lmod) {
6691 strcpy(buf3, "(s8)");
6694 strcpy(buf3, "(s16)");
6697 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6699 fprintf(fout, " %s = %s;",
6700 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6701 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6706 assert_operand_cnt(2);
6707 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6708 fprintf(fout, " tmp = %s;",
6709 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6710 fprintf(fout, " %s = %s;",
6711 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6712 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6713 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6714 fprintf(fout, " %s = %stmp;",
6715 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6716 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
6717 snprintf(g_comment, sizeof(g_comment), "xchg");
6721 assert_operand_cnt(1);
6722 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6723 fprintf(fout, " %s = ~%s;", buf1, buf1);
6727 assert_operand_cnt(2);
6728 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6729 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6730 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6731 strcpy(g_comment, "xlat");
6735 assert_operand_cnt(2);
6736 fprintf(fout, " %s = (s32)%s >> 31;",
6737 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6738 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6739 strcpy(g_comment, "cdq");
6743 assert_operand_cnt(1);
6744 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6745 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
6749 if (po->flags & OPF_REP) {
6750 assert_operand_cnt(3);
6755 assert_operand_cnt(2);
6756 fprintf(fout, " %s = %sesi; esi %c= %d;",
6757 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6758 lmod_cast_u_ptr(po, po->operand[1].lmod),
6759 (po->flags & OPF_DF) ? '-' : '+',
6760 lmod_bytes(po, po->operand[1].lmod));
6761 strcpy(g_comment, "lods");
6766 if (po->flags & OPF_REP) {
6767 assert_operand_cnt(3);
6768 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
6769 (po->flags & OPF_DF) ? '-' : '+',
6770 lmod_bytes(po, po->operand[1].lmod));
6771 fprintf(fout, " %sedi = eax;",
6772 lmod_cast_u_ptr(po, po->operand[1].lmod));
6773 strcpy(g_comment, "rep stos");
6776 assert_operand_cnt(2);
6777 fprintf(fout, " %sedi = eax; edi %c= %d;",
6778 lmod_cast_u_ptr(po, po->operand[1].lmod),
6779 (po->flags & OPF_DF) ? '-' : '+',
6780 lmod_bytes(po, po->operand[1].lmod));
6781 strcpy(g_comment, "stos");
6786 j = lmod_bytes(po, po->operand[0].lmod);
6787 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6788 l = (po->flags & OPF_DF) ? '-' : '+';
6789 if (po->flags & OPF_REP) {
6790 assert_operand_cnt(3);
6792 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
6795 " %sedi = %sesi;", buf1, buf1);
6796 strcpy(g_comment, "rep movs");
6799 assert_operand_cnt(2);
6800 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
6801 buf1, buf1, l, j, l, j);
6802 strcpy(g_comment, "movs");
6807 // repe ~ repeat while ZF=1
6808 j = lmod_bytes(po, po->operand[0].lmod);
6809 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6810 l = (po->flags & OPF_DF) ? '-' : '+';
6811 if (po->flags & OPF_REP) {
6812 assert_operand_cnt(3);
6814 " while (ecx != 0) {\n");
6815 if (pfomask & (1 << PFO_C)) {
6818 " cond_c = %sesi < %sedi;\n", buf1, buf1);
6819 pfomask &= ~(1 << PFO_C);
6822 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
6823 buf1, buf1, l, j, l, j);
6826 " if (cond_z %s 0) break;\n",
6827 (po->flags & OPF_REPZ) ? "==" : "!=");
6830 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
6831 (po->flags & OPF_REPZ) ? "e" : "ne");
6834 assert_operand_cnt(2);
6836 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
6837 buf1, buf1, l, j, l, j);
6838 strcpy(g_comment, "cmps");
6840 pfomask &= ~(1 << PFO_Z);
6841 last_arith_dst = NULL;
6842 delayed_flag_op = NULL;
6846 // only does ZF (for now)
6847 // repe ~ repeat while ZF=1
6848 j = lmod_bytes(po, po->operand[1].lmod);
6849 l = (po->flags & OPF_DF) ? '-' : '+';
6850 if (po->flags & OPF_REP) {
6851 assert_operand_cnt(3);
6853 " while (ecx != 0) {\n");
6855 " cond_z = (%seax == %sedi); edi %c= %d;\n",
6856 lmod_cast_u(po, po->operand[1].lmod),
6857 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6860 " if (cond_z %s 0) break;\n",
6861 (po->flags & OPF_REPZ) ? "==" : "!=");
6864 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
6865 (po->flags & OPF_REPZ) ? "e" : "ne");
6868 assert_operand_cnt(2);
6869 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
6870 lmod_cast_u(po, po->operand[1].lmod),
6871 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6872 strcpy(g_comment, "scas");
6874 pfomask &= ~(1 << PFO_Z);
6875 last_arith_dst = NULL;
6876 delayed_flag_op = NULL;
6879 // arithmetic w/flags
6881 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
6882 goto dualop_arith_const;
6883 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6887 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6888 if (po->operand[1].type == OPT_CONST) {
6889 j = lmod_bytes(po, po->operand[0].lmod);
6890 if (((1ull << j * 8) - 1) == po->operand[1].val)
6891 goto dualop_arith_const;
6896 assert_operand_cnt(2);
6897 fprintf(fout, " %s %s= %s;",
6898 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6900 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6901 output_std_flags(fout, po, &pfomask, buf1);
6902 last_arith_dst = &po->operand[0];
6903 delayed_flag_op = NULL;
6907 // and 0, or ~0 used instead mov
6908 assert_operand_cnt(2);
6909 fprintf(fout, " %s = %s;",
6910 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6911 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6912 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6913 output_std_flags(fout, po, &pfomask, buf1);
6914 last_arith_dst = &po->operand[0];
6915 delayed_flag_op = NULL;
6920 assert_operand_cnt(2);
6921 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6922 if (pfomask & (1 << PFO_C)) {
6923 if (po->operand[1].type == OPT_CONST) {
6924 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6925 j = po->operand[1].val;
6928 if (po->op == OP_SHL)
6932 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
6936 ferr(po, "zero shift?\n");
6940 pfomask &= ~(1 << PFO_C);
6942 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
6943 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6944 if (po->operand[1].type != OPT_CONST)
6945 fprintf(fout, " & 0x1f");
6947 output_std_flags(fout, po, &pfomask, buf1);
6948 last_arith_dst = &po->operand[0];
6949 delayed_flag_op = NULL;
6953 assert_operand_cnt(2);
6954 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6955 fprintf(fout, " %s = %s%s >> %s;", buf1,
6956 lmod_cast_s(po, po->operand[0].lmod), buf1,
6957 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6958 output_std_flags(fout, po, &pfomask, buf1);
6959 last_arith_dst = &po->operand[0];
6960 delayed_flag_op = NULL;
6965 assert_operand_cnt(3);
6966 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6967 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6968 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
6969 if (po->operand[2].type != OPT_CONST) {
6970 // no handling for "undefined" case, hopefully not needed
6971 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
6974 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6975 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6976 if (po->op == OP_SHLD) {
6977 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
6978 buf1, buf3, buf1, buf2, l, buf3);
6979 strcpy(g_comment, "shld");
6982 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
6983 buf1, buf3, buf1, buf2, l, buf3);
6984 strcpy(g_comment, "shrd");
6986 output_std_flags(fout, po, &pfomask, buf1);
6987 last_arith_dst = &po->operand[0];
6988 delayed_flag_op = NULL;
6993 assert_operand_cnt(2);
6994 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6995 if (po->operand[1].type == OPT_CONST) {
6996 j = po->operand[1].val;
6997 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
6998 fprintf(fout, po->op == OP_ROL ?
6999 " %s = (%s << %d) | (%s >> %d);" :
7000 " %s = (%s >> %d) | (%s << %d);",
7001 buf1, buf1, j, buf1,
7002 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
7006 output_std_flags(fout, po, &pfomask, buf1);
7007 last_arith_dst = &po->operand[0];
7008 delayed_flag_op = NULL;
7013 assert_operand_cnt(2);
7014 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7015 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7016 if (po->operand[1].type == OPT_CONST) {
7017 j = po->operand[1].val % l;
7019 ferr(po, "zero rotate\n");
7020 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
7021 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
7022 if (po->op == OP_RCL) {
7024 " %s = (%s << %d) | (cond_c << %d)",
7025 buf1, buf1, j, j - 1);
7027 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
7031 " %s = (%s >> %d) | (cond_c << %d)",
7032 buf1, buf1, j, l - j);
7034 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
7036 fprintf(fout, ";\n");
7037 fprintf(fout, " cond_c = tmp;");
7041 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
7042 output_std_flags(fout, po, &pfomask, buf1);
7043 last_arith_dst = &po->operand[0];
7044 delayed_flag_op = NULL;
7048 assert_operand_cnt(2);
7049 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7050 if (IS(opr_name(po, 0), opr_name(po, 1))) {
7051 // special case for XOR
7052 int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
7053 for (j = 0; j <= PFO_LE; j++) {
7054 if (pfomask & (1 << j)) {
7055 fprintf(fout, " cond_%s = %d;\n",
7056 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
7057 pfomask &= ~(1 << j);
7060 fprintf(fout, " %s = 0;",
7061 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7062 last_arith_dst = &po->operand[0];
7063 delayed_flag_op = NULL;
7069 assert_operand_cnt(2);
7070 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7071 if (pfomask & (1 << PFO_C)) {
7072 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7073 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7074 if (po->operand[0].lmod == OPLM_DWORD) {
7075 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
7076 fprintf(fout, " cond_c = tmp64 >> 32;\n");
7077 fprintf(fout, " %s = (u32)tmp64;",
7078 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7079 strcat(g_comment, " add64");
7082 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
7083 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
7084 fprintf(fout, " %s += %s;",
7085 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7088 pfomask &= ~(1 << PFO_C);
7089 output_std_flags(fout, po, &pfomask, buf1);
7090 last_arith_dst = &po->operand[0];
7091 delayed_flag_op = NULL;
7094 if (pfomask & (1 << PFO_LE)) {
7095 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
7096 fprintf(fout, " cond_%s = %s;\n",
7097 parsed_flag_op_names[PFO_LE], buf1);
7098 pfomask &= ~(1 << PFO_LE);
7103 assert_operand_cnt(2);
7104 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7105 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
7106 for (j = 0; j <= PFO_LE; j++) {
7107 if (!(pfomask & (1 << j)))
7109 if (j == PFO_Z || j == PFO_S)
7112 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7113 fprintf(fout, " cond_%s = %s;\n",
7114 parsed_flag_op_names[j], buf1);
7115 pfomask &= ~(1 << j);
7122 assert_operand_cnt(2);
7123 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7124 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7125 if (po->op == OP_SBB
7126 && IS(po->operand[0].name, po->operand[1].name))
7128 // avoid use of unitialized var
7129 fprintf(fout, " %s = -cond_c;", buf1);
7130 // carry remains what it was
7131 pfomask &= ~(1 << PFO_C);
7134 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
7135 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7137 output_std_flags(fout, po, &pfomask, buf1);
7138 last_arith_dst = &po->operand[0];
7139 delayed_flag_op = NULL;
7144 // on SKL, if src is 0, dst is left unchanged
7145 assert_operand_cnt(2);
7146 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7147 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7148 output_std_flag_z(fout, po, &pfomask, buf2);
7149 if (po->op == OP_BSF)
7150 snprintf(buf3, sizeof(buf3), "__builtin_ffs(%s) - 1", buf2);
7152 snprintf(buf3, sizeof(buf3), "31 - __builtin_clz(%s)", buf2);
7153 fprintf(fout, " if (%s) %s = %s;", buf2, buf1, buf3);
7154 last_arith_dst = &po->operand[0];
7155 delayed_flag_op = NULL;
7156 strcat(g_comment, po->op == OP_BSF ? " bsf" : " bsr");
7160 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
7161 for (j = 0; j <= PFO_LE; j++) {
7162 if (!(pfomask & (1 << j)))
7164 if (j == PFO_Z || j == PFO_S || j == PFO_C)
7167 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7168 fprintf(fout, " cond_%s = %s;\n",
7169 parsed_flag_op_names[j], buf1);
7170 pfomask &= ~(1 << j);
7176 if (pfomask & (1 << PFO_C))
7177 // carry is unaffected by inc/dec.. wtf?
7178 ferr(po, "carry propagation needed\n");
7180 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7181 if (po->operand[0].type == OPT_REG) {
7182 strcpy(buf2, po->op == OP_INC ? "++" : "--");
7183 fprintf(fout, " %s%s;", buf1, buf2);
7186 strcpy(buf2, po->op == OP_INC ? "+" : "-");
7187 fprintf(fout, " %s %s= 1;", buf1, buf2);
7189 output_std_flags(fout, po, &pfomask, buf1);
7190 last_arith_dst = &po->operand[0];
7191 delayed_flag_op = NULL;
7195 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7196 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
7197 fprintf(fout, " %s = -%s%s;", buf1,
7198 lmod_cast_s(po, po->operand[0].lmod), buf2);
7199 last_arith_dst = &po->operand[0];
7200 delayed_flag_op = NULL;
7201 if (pfomask & PFOB_C) {
7202 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
7205 output_std_flags(fout, po, &pfomask, buf1);
7209 if (po->operand_cnt == 2) {
7210 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7213 if (po->operand_cnt == 3)
7214 ferr(po, "TODO imul3\n");
7217 assert_operand_cnt(1);
7218 switch (po->operand[0].lmod) {
7220 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
7221 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
7222 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
7223 fprintf(fout, " edx = tmp64 >> 32;\n");
7224 fprintf(fout, " eax = tmp64;");
7227 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
7228 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
7229 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
7233 ferr(po, "TODO: unhandled mul type\n");
7236 last_arith_dst = NULL;
7237 delayed_flag_op = NULL;
7242 assert_operand_cnt(1);
7243 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7244 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
7245 po->op == OP_IDIV));
7246 switch (po->operand[0].lmod) {
7248 if (po->flags & OPF_32BIT)
7249 snprintf(buf2, sizeof(buf2), "%seax", cast);
7251 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7252 snprintf(buf2, sizeof(buf2), "%stmp64",
7253 (po->op == OP_IDIV) ? "(s64)" : "");
7255 if (po->operand[0].type == OPT_REG
7256 && po->operand[0].reg == xDX)
7258 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
7259 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
7262 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
7263 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
7267 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
7268 snprintf(buf2, sizeof(buf2), "%stmp",
7269 (po->op == OP_IDIV) ? "(s32)" : "");
7270 if (po->operand[0].type == OPT_REG
7271 && po->operand[0].reg == xDX)
7273 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
7275 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
7279 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
7281 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
7284 strcat(g_comment, " div16");
7287 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
7289 last_arith_dst = NULL;
7290 delayed_flag_op = NULL;
7295 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7297 for (j = 0; j < 8; j++) {
7298 if (pfomask & (1 << j)) {
7299 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
7300 fprintf(fout, " cond_%s = %s;",
7301 parsed_flag_op_names[j], buf1);
7308 last_arith_dst = NULL;
7309 delayed_flag_op = po;
7313 // SETcc - should already be handled
7316 // note: we reuse OP_Jcc for SETcc, only flags differ
7318 fprintf(fout, "\n goto %s;", po->operand[0].name);
7322 fprintf(fout, " if (ecx == 0)\n");
7323 fprintf(fout, " goto %s;", po->operand[0].name);
7324 strcat(g_comment, " jecxz");
7328 fprintf(fout, " if (--ecx != 0)\n");
7329 fprintf(fout, " goto %s;", po->operand[0].name);
7330 strcat(g_comment, " loop");
7334 assert_operand_cnt(1);
7335 last_arith_dst = NULL;
7336 delayed_flag_op = NULL;
7338 if (po->operand[0].type == OPT_REGMEM) {
7339 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
7342 ferr(po, "parse failure for jmp '%s'\n",
7343 po->operand[0].name);
7344 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
7347 else if (po->operand[0].type != OPT_LABEL)
7348 ferr(po, "unhandled jmp type\n");
7350 fprintf(fout, " goto %s;", po->operand[0].name);
7354 assert_operand_cnt(1);
7356 my_assert_not(pp, NULL);
7359 if (po->flags & OPF_CC) {
7360 // we treat conditional branch to another func
7361 // (yes such code exists..) as conditional tailcall
7363 fprintf(fout, " {\n");
7366 if (pp->is_fptr && !pp->is_arg) {
7367 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
7368 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7371 if (pp->is_fptr && (pp->is_unresolved || pp->is_guessed)) {
7372 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
7373 buf3, asmfn, po->asmln, pp->name);
7376 fprintf(fout, "%s", buf3);
7377 if (strstr(pp->ret_type.name, "int64")) {
7378 if (po->flags & OPF_TAIL)
7379 ferr(po, "int64 and tail?\n");
7380 fprintf(fout, "tmp64 = ");
7382 else if (!IS(pp->ret_type.name, "void")) {
7383 if (po->flags & OPF_TAIL) {
7384 if (regmask_ret & mxAX) {
7385 fprintf(fout, "return ");
7386 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
7387 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
7389 else if (regmask_ret & mxST0)
7390 ferr(po, "float tailcall\n");
7392 else if (po->regmask_dst & mxAX) {
7393 fprintf(fout, "eax = ");
7394 if (pp->ret_type.is_ptr)
7395 fprintf(fout, "(u32)");
7397 else if (po->regmask_dst & mxST0) {
7398 ferr_assert(po, po->flags & OPF_FPUSH);
7399 if (need_float_stack)
7400 fprintf(fout, "f_st[--f_stp & 7] = ");
7402 fprintf(fout, "f_st0 = ");
7406 if (pp->name[0] == 0)
7407 ferr(po, "missing pp->name\n");
7408 fprintf(fout, "%s%s(", pp->name,
7409 pp->has_structarg ? "_sa" : "");
7411 if (po->flags & OPF_ATAIL) {
7413 g_func_pp->is_stdcall && g_func_pp->argc_stack > 0;
7414 check_compat |= pp->argc_stack > 0;
7416 && (pp->argc_stack != g_func_pp->argc_stack
7417 || pp->is_stdcall != g_func_pp->is_stdcall))
7418 ferr(po, "incompatible arg-reuse tailcall\n");
7419 if (g_func_pp->has_retreg)
7420 ferr(po, "TODO: retreg+tailcall\n");
7422 for (arg = j = 0; arg < pp->argc; arg++) {
7424 fprintf(fout, ", ");
7427 if (pp->arg[arg].type.is_ptr)
7428 snprintf(cast, sizeof(cast), "(%s)",
7429 pp->arg[arg].type.name);
7431 if (pp->arg[arg].reg != NULL) {
7432 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7436 for (; j < g_func_pp->argc; j++)
7437 if (g_func_pp->arg[j].reg == NULL)
7439 fprintf(fout, "%sa%d", cast, j + 1);
7444 for (arg = 0; arg < pp->argc; arg++) {
7446 fprintf(fout, ", ");
7449 if (pp->arg[arg].type.is_ptr)
7450 snprintf(cast, sizeof(cast), "(%s)",
7451 pp->arg[arg].type.name);
7453 if (pp->arg[arg].reg != NULL) {
7454 if (pp->arg[arg].type.is_retreg)
7455 fprintf(fout, "&%s", pp->arg[arg].reg);
7456 else if (IS(pp->arg[arg].reg, "ebp")
7457 && g_bp_frame && !(po->flags & OPF_EBP_S))
7459 // rare special case
7460 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
7461 strcat(g_comment, " bp_ref");
7464 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7469 tmp_op = pp->arg[arg].datap;
7471 ferr(po, "parsed_op missing for arg%d\n", arg);
7473 if (tmp_op->flags & OPF_VAPUSH) {
7474 fprintf(fout, "ap");
7476 else if (tmp_op->op == OP_FST) {
7477 fprintf(fout, "fs_%d", tmp_op->p_argnum);
7478 if (tmp_op->operand[0].lmod == OPLM_QWORD)
7481 else if (pp->arg[arg].type.is_64bit) {
7482 ferr_assert(po, tmp_op->p_argpass == 0);
7483 ferr_assert(po, !pp->arg[arg].is_saved);
7484 ferr_assert(po, !pp->arg[arg].type.is_float);
7485 ferr_assert(po, cast[0] == 0);
7486 out_src_opr(buf1, sizeof(buf1),
7487 tmp_op, &tmp_op->operand[0], cast, 0);
7488 tmp_op = pp->arg[++arg].datap;
7489 ferr_assert(po, tmp_op != NULL);
7490 out_src_opr(buf2, sizeof(buf2),
7491 tmp_op, &tmp_op->operand[0], cast, 0);
7492 fprintf(fout, "((u64)(%s) << 32) | (%s)",
7495 else if (tmp_op->p_argpass != 0) {
7496 ferr_assert(po, !pp->arg[arg].type.is_float);
7497 fprintf(fout, "a%d", tmp_op->p_argpass);
7499 else if (pp->arg[arg].is_saved) {
7500 ferr_assert(po, tmp_op->p_argnum > 0);
7501 ferr_assert(po, !pp->arg[arg].type.is_float);
7502 fprintf(fout, "%s%s", cast,
7503 saved_arg_name(buf1, sizeof(buf1),
7504 tmp_op->p_arggrp, tmp_op->p_argnum));
7506 else if (pp->arg[arg].type.is_float) {
7507 ferr_assert(po, !pp->arg[arg].type.is_64bit);
7509 out_src_opr_float(buf1, sizeof(buf1),
7510 tmp_op, &tmp_op->operand[0], need_float_stack));
7514 out_src_opr(buf1, sizeof(buf1),
7515 tmp_op, &tmp_op->operand[0], cast, 0));
7519 fprintf(fout, ");");
7521 if (strstr(pp->ret_type.name, "int64")) {
7522 fprintf(fout, "\n");
7523 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7524 fprintf(fout, "%seax = tmp64;", buf3);
7527 if (pp->is_unresolved) {
7528 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
7530 strcat(g_comment, buf2);
7533 if (po->flags & OPF_TAIL) {
7535 if (i == opcnt - 1 || pp->is_noreturn)
7537 else if (IS(pp->ret_type.name, "void"))
7539 else if (!(regmask_ret & (1 << xAX)))
7541 // else already handled as 'return f()'
7544 fprintf(fout, "\n%sreturn;", buf3);
7545 strcat(g_comment, " ^ tailcall");
7548 strcat(g_comment, " tailcall");
7550 if ((regmask_ret & (1 << xAX))
7551 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7553 ferr(po, "int func -> void func tailcall?\n");
7556 if (pp->is_noreturn)
7557 strcat(g_comment, " noreturn");
7558 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7559 strcat(g_comment, " argframe");
7560 if (po->flags & OPF_CC)
7561 strcat(g_comment, " cond");
7563 if (po->flags & OPF_CC)
7564 fprintf(fout, "\n }");
7566 delayed_flag_op = NULL;
7567 last_arith_dst = NULL;
7571 if (g_func_pp->is_vararg)
7572 fprintf(fout, " va_end(ap);\n");
7573 if (g_func_pp->has_retreg) {
7574 for (arg = 0; arg < g_func_pp->argc; arg++)
7575 if (g_func_pp->arg[arg].type.is_retreg)
7576 fprintf(fout, " *r_%s = %s;\n",
7577 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7580 if (regmask_ret & mxST0) {
7581 fprintf(fout, " return %s;", float_st0);
7583 else if (!(regmask_ret & mxAX)) {
7584 if (i != opcnt - 1 || label_pending)
7585 fprintf(fout, " return;");
7587 else if (g_func_pp->ret_type.is_ptr) {
7588 fprintf(fout, " return (%s)eax;",
7589 g_func_pp->ret_type.name);
7591 else if (IS(g_func_pp->ret_type.name, "__int64"))
7592 fprintf(fout, " return ((u64)edx << 32) | eax;");
7594 fprintf(fout, " return eax;");
7596 last_arith_dst = NULL;
7597 delayed_flag_op = NULL;
7601 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7602 if (po->p_argnum != 0) {
7603 // special case - saved func arg
7604 fprintf(fout, " %s = %s;",
7605 saved_arg_name(buf2, sizeof(buf2),
7606 po->p_arggrp, po->p_argnum), buf1);
7609 else if (po->flags & OPF_RSAVE) {
7610 fprintf(fout, " s_%s = %s;", buf1, buf1);
7613 else if (po->flags & OPF_PPUSH) {
7615 ferr_assert(po, tmp_op != NULL);
7616 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7617 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7620 else if (g_func_pp->is_userstack) {
7621 fprintf(fout, " *(--esp) = %s;", buf1);
7624 if (!(g_ida_func_attr & IDAFA_NORETURN))
7625 ferr(po, "stray push encountered\n");
7630 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7631 if (po->flags & OPF_RSAVE) {
7632 fprintf(fout, " %s = s_%s;", buf1, buf1);
7635 else if (po->flags & OPF_PPUSH) {
7636 // push/pop graph / non-const
7637 ferr_assert(po, po->datap == NULL);
7638 fprintf(fout, " %s = pp_%s;", buf1, buf1);
7641 else if (po->datap != NULL) {
7644 fprintf(fout, " %s = %s;", buf1,
7645 out_src_opr(buf2, sizeof(buf2),
7646 tmp_op, &tmp_op->operand[0],
7647 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7650 else if (g_func_pp->is_userstack) {
7651 fprintf(fout, " %s = *esp++;", buf1);
7655 ferr(po, "stray pop encountered\n");
7665 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7666 fprintf(fout, " tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
7667 po->op == OPP_ALLSHL ? "<<" : ">>");
7668 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
7669 strcat(g_comment, po->op == OPP_ALLSHL
7670 ? " allshl" : " allshr");
7675 if (need_float_stack) {
7676 out_src_opr_float(buf1, sizeof(buf1),
7677 po, &po->operand[0], 1);
7678 if (po->regmask_src & mxSTa) {
7679 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7683 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
7686 if (po->flags & OPF_FSHIFT)
7687 fprintf(fout, " f_st1 = f_st0;");
7688 if (po->operand[0].type == OPT_REG
7689 && po->operand[0].reg == xST0)
7691 strcat(g_comment, " fld st");
7694 fprintf(fout, " f_st0 = %s;",
7695 out_src_opr_float(buf1, sizeof(buf1),
7696 po, &po->operand[0], 0));
7698 strcat(g_comment, " fld");
7702 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7703 lmod_cast(po, po->operand[0].lmod, 1), 0);
7704 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7705 if (need_float_stack) {
7706 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
7709 if (po->flags & OPF_FSHIFT)
7710 fprintf(fout, " f_st1 = f_st0;");
7711 fprintf(fout, " f_st0 = %s;", buf2);
7713 strcat(g_comment, " fild");
7717 if (need_float_stack)
7718 fprintf(fout, " f_st[--f_stp & 7] = ");
7720 if (po->flags & OPF_FSHIFT)
7721 fprintf(fout, " f_st1 = f_st0;");
7722 fprintf(fout, " f_st0 = ");
7724 switch (po->operand[0].val) {
7725 case X87_CONST_1: fprintf(fout, "1.0;"); break;
7726 case X87_CONST_L2T: fprintf(fout, "3.321928094887362;"); break;
7727 case X87_CONST_L2E: fprintf(fout, "M_LOG2E;"); break;
7728 case X87_CONST_PI: fprintf(fout, "M_PI;"); break;
7729 case X87_CONST_LG2: fprintf(fout, "0.301029995663981;"); break;
7730 case X87_CONST_LN2: fprintf(fout, "M_LN2;"); break;
7731 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
7732 default: ferr_assert(po, 0); break;
7737 if (po->flags & OPF_FARG) {
7738 // store to stack as func arg
7739 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7743 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7745 dead_dst = po->operand[0].type == OPT_REG
7746 && po->operand[0].reg == xST0;
7749 fprintf(fout, " %s = %s;", buf1, float_st0);
7750 if (po->flags & OPF_FSHIFT) {
7751 if (need_float_stack)
7752 fprintf(fout, " f_stp++;");
7754 fprintf(fout, " f_st0 = f_st1;");
7756 if (dead_dst && !(po->flags & OPF_FSHIFT))
7759 strcat(g_comment, " fst");
7763 fprintf(fout, " %s = %s%s;",
7764 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7765 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7766 if (po->flags & OPF_FSHIFT) {
7767 if (need_float_stack)
7768 fprintf(fout, " f_stp++;");
7770 fprintf(fout, " f_st0 = f_st1;");
7772 strcat(g_comment, " fist");
7779 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7781 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7783 dead_dst = (po->flags & OPF_FPOP)
7784 && po->operand[0].type == OPT_REG
7785 && po->operand[0].reg == xST0;
7787 case OP_FADD: j = '+'; break;
7788 case OP_FDIV: j = '/'; break;
7789 case OP_FMUL: j = '*'; break;
7790 case OP_FSUB: j = '-'; break;
7791 default: j = 'x'; break;
7793 if (need_float_stack) {
7795 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7796 if (po->flags & OPF_FSHIFT)
7797 fprintf(fout, " f_stp++;");
7800 if (po->flags & OPF_FSHIFT) {
7801 // note: assumes only 2 regs handled
7803 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
7805 fprintf(fout, " f_st0 = f_st1;");
7808 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7810 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7815 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7817 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7819 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
7821 dead_dst = (po->flags & OPF_FPOP)
7822 && po->operand[0].type == OPT_REG
7823 && po->operand[0].reg == xST0;
7824 j = po->op == OP_FDIVR ? '/' : '-';
7825 if (need_float_stack) {
7827 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7828 if (po->flags & OPF_FSHIFT)
7829 fprintf(fout, " f_stp++;");
7832 if (po->flags & OPF_FSHIFT) {
7834 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
7836 fprintf(fout, " f_st0 = f_st1;");
7839 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7841 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7849 case OP_FIADD: j = '+'; break;
7850 case OP_FIDIV: j = '/'; break;
7851 case OP_FIMUL: j = '*'; break;
7852 case OP_FISUB: j = '-'; break;
7853 default: j = 'x'; break;
7855 fprintf(fout, " %s %c= (%s)%s;", float_st0,
7857 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7858 lmod_cast(po, po->operand[0].lmod, 1), 0));
7863 fprintf(fout, " %s = %s %c %s;", float_st0,
7864 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7866 po->op == OP_FIDIVR ? '/' : '-', float_st0);
7871 ferr_assert(po, po->datap != NULL);
7872 mask = (long)po->datap & 0xffff;
7873 z_check = ((long)po->datap >> 16) & 1;
7874 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7876 if (mask == 0x0100 || mask == 0x0500) { // C0 -> <
7877 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
7880 else if (mask == 0x4000 || mask == 0x4400) { // C3 -> =
7881 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
7884 else if (mask == 0x4100) { // C3, C0
7886 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
7888 strcat(g_comment, " z_chk_det");
7891 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
7892 "(%s < %s ? 0x0100 : 0);",
7893 float_st0, buf1, float_st0, buf1);
7897 ferr(po, "unhandled sw mask: %x\n", mask);
7898 if (po->flags & OPF_FSHIFT) {
7899 if (need_float_stack) {
7900 if (po->flags & OPF_FPOPP)
7901 fprintf(fout, " f_stp += 2;");
7903 fprintf(fout, " f_stp++;");
7906 ferr_assert(po, !(po->flags & OPF_FPOPP));
7907 fprintf(fout, " f_st0 = f_st1;");
7914 fprintf(fout, " %s = f_sw;",
7915 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7919 fprintf(fout, " %s = -%s;", float_st0, float_st0);
7923 fprintf(fout, " %s = cos%s(%s);", float_st0,
7924 need_double ? "" : "f", float_st0);
7928 if (need_float_stack) {
7929 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
7930 need_double ? "" : "f", float_st1, float_st0);
7931 fprintf(fout, " f_stp++;");
7934 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
7935 need_double ? "" : "f");
7940 if (need_float_stack) {
7941 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
7942 float_st1, need_double ? "" : "f", float_st0);
7943 fprintf(fout, " f_stp++;");
7946 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
7947 need_double ? "" : "f");
7949 strcat(g_comment, " fyl2x");
7953 fprintf(fout, " %s = sin%s(%s);", float_st0,
7954 need_double ? "" : "f", float_st0);
7958 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
7959 need_double ? "" : "f", float_st0);
7963 dead_dst = po->operand[0].type == OPT_REG
7964 && po->operand[0].reg == xST0;
7966 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7968 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
7969 float_st0, float_st0, buf1, buf1);
7970 strcat(g_comment, " fxch");
7977 ferr_assert(po, po->flags & OPF_32BIT);
7978 fprintf(fout, " eax = (s32)%s;", float_st0);
7979 if (po->flags & OPF_FSHIFT) {
7980 if (need_float_stack)
7981 fprintf(fout, " f_stp++;");
7983 fprintf(fout, " f_st0 = f_st1;");
7985 strcat(g_comment, " ftol");
7989 if (need_float_stack) {
7990 fprintf(fout, " %s = pow%s(%s, %s);", float_st1,
7991 need_double ? "" : "f", float_st1, float_st0);
7992 fprintf(fout, " f_stp++;");
7995 fprintf(fout, " f_st0 = pow%s(f_st1, f_st0);",
7996 need_double ? "" : "f");
7998 strcat(g_comment, " CIpow");
8002 fprintf(fout, " do_skip_code_abort();");
8007 fprintf(fout, " do_emms();");
8012 ferr(po, "unhandled op type %d, flags %x\n",
8017 if (g_comment[0] != 0) {
8018 char *p = g_comment;
8019 while (my_isblank(*p))
8021 fprintf(fout, " // %s", p);
8026 fprintf(fout, "\n");
8028 // some sanity checking
8029 if (po->flags & OPF_REP) {
8030 if (po->op != OP_STOS && po->op != OP_MOVS
8031 && po->op != OP_CMPS && po->op != OP_SCAS)
8032 ferr(po, "unexpected rep\n");
8033 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
8034 && (po->op == OP_CMPS || po->op == OP_SCAS))
8035 ferr(po, "cmps/scas with plain rep\n");
8037 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
8038 && po->op != OP_CMPS && po->op != OP_SCAS)
8039 ferr(po, "unexpected repz/repnz\n");
8042 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
8044 // see is delayed flag stuff is still valid
8045 if (delayed_flag_op != NULL && delayed_flag_op != po) {
8046 if (is_any_opr_modified(delayed_flag_op, po, 0))
8047 delayed_flag_op = NULL;
8050 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
8051 if (is_opr_modified(last_arith_dst, po))
8052 last_arith_dst = NULL;
8059 if (g_stack_fsz && !g_stack_frame_used)
8060 fprintf(fout, " (void)sf;\n");
8062 fprintf(fout, "}\n\n");
8064 gen_x_cleanup(opcnt);
8067 static void gen_x_cleanup(int opcnt)
8071 for (i = 0; i < opcnt; i++) {
8072 struct label_ref *lr, *lr_del;
8074 lr = g_label_refs[i].next;
8075 while (lr != NULL) {
8080 g_label_refs[i].i = -1;
8081 g_label_refs[i].next = NULL;
8083 if (ops[i].op == OP_CALL) {
8085 proto_release(ops[i].pp);
8091 struct func_proto_dep;
8093 struct func_prototype {
8098 int has_ret:3; // -1, 0, 1: unresolved, no, yes
8099 unsigned int dep_resolved:1;
8100 unsigned int is_stdcall:1;
8101 unsigned int eax_pass:1; // returns without touching eax
8102 struct func_proto_dep *dep_func;
8104 const struct parsed_proto *pp; // seed pp, if any
8107 struct func_proto_dep {
8109 struct func_prototype *proto;
8110 int regmask_live; // .. at the time of call
8111 unsigned int ret_dep:1; // return from this is caller's return
8114 static struct func_prototype *hg_fp;
8115 static int hg_fp_cnt;
8117 static struct scanned_var {
8119 enum opr_lenmod lmod;
8120 unsigned int is_seeded:1;
8121 unsigned int is_c_str:1;
8122 const struct parsed_proto *pp; // seed pp, if any
8124 static int hg_var_cnt;
8126 static char **hg_refs;
8127 static int hg_ref_cnt;
8129 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8132 static struct func_prototype *hg_fp_add(const char *funcn)
8134 struct func_prototype *fp;
8136 if ((hg_fp_cnt & 0xff) == 0) {
8137 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
8138 my_assert_not(hg_fp, NULL);
8139 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
8142 fp = &hg_fp[hg_fp_cnt];
8143 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
8145 fp->argc_stack = -1;
8151 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
8156 for (i = 0; i < fp->dep_func_cnt; i++)
8157 if (IS(fp->dep_func[i].name, name))
8158 return &fp->dep_func[i];
8163 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
8166 if (hg_fp_find_dep(fp, name))
8169 if ((fp->dep_func_cnt & 0xff) == 0) {
8170 fp->dep_func = realloc(fp->dep_func,
8171 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
8172 my_assert_not(fp->dep_func, NULL);
8173 memset(&fp->dep_func[fp->dep_func_cnt], 0,
8174 sizeof(fp->dep_func[0]) * 0x100);
8176 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
8180 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
8182 const struct func_prototype *p1 = p1_, *p2 = p2_;
8183 return strcmp(p1->name, p2->name);
8187 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
8189 const struct func_prototype *p1 = p1_, *p2 = p2_;
8190 return p1->id - p2->id;
8194 static void hg_ref_add(const char *name)
8196 if ((hg_ref_cnt & 0xff) == 0) {
8197 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
8198 my_assert_not(hg_refs, NULL);
8199 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
8202 hg_refs[hg_ref_cnt] = strdup(name);
8203 my_assert_not(hg_refs[hg_ref_cnt], NULL);
8207 // recursive register dep pass
8208 // - track saved regs (part 2)
8209 // - try to figure out arg-regs
8210 // - calculate reg deps
8211 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
8212 struct func_prototype *fp, int regmask_save, int regmask_dst,
8213 int *regmask_dep, int *has_ret)
8215 struct func_proto_dep *dep;
8216 struct parsed_op *po;
8217 int from_caller = 0;
8222 for (; i < opcnt; i++)
8224 if (cbits[i >> 3] & (1 << (i & 7)))
8226 cbits[i >> 3] |= (1 << (i & 7));
8230 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
8231 if (po->flags & OPF_RMD)
8234 if (po->btj != NULL) {
8236 for (j = 0; j < po->btj->count; j++) {
8237 check_i(po, po->btj->d[j].bt_i);
8238 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
8239 regmask_save, regmask_dst, regmask_dep, has_ret);
8244 check_i(po, po->bt_i);
8245 if (po->flags & OPF_CJMP) {
8246 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
8247 regmask_save, regmask_dst, regmask_dep, has_ret);
8255 if (po->flags & OPF_FARG)
8256 /* (just calculate register deps) */;
8257 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
8259 reg = po->operand[0].reg;
8260 ferr_assert(po, reg >= 0);
8262 if (po->flags & OPF_RSAVE) {
8263 regmask_save |= 1 << reg;
8266 if (po->flags & OPF_DONE)
8269 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0, 0);
8271 regmask_save |= 1 << reg;
8272 po->flags |= OPF_RMD;
8273 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, OPF_RMD);
8277 else if (po->flags & OPF_RMD)
8279 else if (po->op == OP_CALL) {
8280 po->regmask_dst |= 1 << xAX;
8282 dep = hg_fp_find_dep(fp, po->operand[0].name);
8284 dep->regmask_live = regmask_save | regmask_dst;
8285 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8286 dep->regmask_live |= 1 << xBP;
8289 else if (po->op == OP_RET) {
8290 if (po->operand_cnt > 0) {
8292 if (fp->argc_stack >= 0
8293 && fp->argc_stack != po->operand[0].val / 4)
8294 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
8295 fp->argc_stack = po->operand[0].val / 4;
8299 // if has_ret is 0, there is uninitialized eax path,
8300 // which means it's most likely void func
8301 if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
8302 if (po->op == OP_CALL) {
8307 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
8310 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
8313 if (ret != 1 && from_caller) {
8314 // unresolved eax - probably void func
8319 if (j >= 0 && ops[j].op == OP_CALL) {
8320 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
8331 l = regmask_save | regmask_dst;
8332 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8335 l = po->regmask_src & ~l;
8338 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
8339 l, regmask_dst, regmask_save, po->flags);
8342 regmask_dst |= po->regmask_dst;
8344 if (po->flags & OPF_TAIL)
8349 static void gen_hdr(const char *funcn, int opcnt)
8351 unsigned char cbits[MAX_OPS / 8];
8352 const struct parsed_proto *pp_c;
8353 struct parsed_proto *pp;
8354 struct func_prototype *fp;
8355 struct parsed_op *po;
8356 int regmask_dummy = 0;
8358 int max_bp_offset = 0;
8363 pp_c = proto_parse(g_fhdr, funcn, 1);
8365 // already in seed, will add to hg_fp later
8368 fp = hg_fp_add(funcn);
8370 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
8371 g_stack_frame_used = 0;
8375 // - resolve all branches
8376 // - parse calls with labels
8377 resolve_branches_parse_calls(opcnt);
8380 // - handle ebp/esp frame, remove ops related to it
8381 scan_prologue_epilogue(opcnt, NULL);
8384 // - remove dead labels
8386 for (i = 0; i < opcnt; i++)
8388 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8394 if (po->flags & (OPF_RMD|OPF_DONE))
8397 if (po->op == OP_CALL) {
8398 if (po->operand[0].type == OPT_LABEL)
8399 hg_fp_add_dep(fp, opr_name(po, 0));
8400 else if (po->pp != NULL)
8401 hg_fp_add_dep(fp, po->pp->name);
8406 // - remove dead labels
8407 // - handle push <const>/pop pairs
8408 for (i = 0; i < opcnt; i++)
8410 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8416 if (po->flags & (OPF_RMD|OPF_DONE))
8419 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
8420 scan_for_pop_const(i, opcnt, i + opcnt * 13);
8424 // - process trivial calls
8425 for (i = 0; i < opcnt; i++)
8428 if (po->flags & (OPF_RMD|OPF_DONE))
8431 if (po->op == OP_CALL)
8433 pp = process_call_early(i, opcnt, &j);
8435 if (!(po->flags & OPF_ATAIL))
8436 // since we know the args, try to collect them
8437 if (collect_call_args_early(i, pp, NULL, NULL) != 0)
8443 // commit esp adjust
8444 if (ops[j].op != OP_POP)
8445 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
8447 for (l = 0; l < pp->argc_stack; l++)
8448 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
8452 po->flags |= OPF_DONE;
8458 // - track saved regs (simple)
8460 for (i = 0; i < opcnt; i++)
8463 if (po->flags & (OPF_RMD|OPF_DONE))
8466 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
8467 && po->operand[0].reg != xCX)
8469 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
8471 // regmask_save |= 1 << po->operand[0].reg; // do it later
8472 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
8473 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
8476 else if (po->op == OP_CALL)
8478 pp = process_call(i, opcnt);
8480 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
8481 // since we know the args, collect them
8482 ret = collect_call_args(po, i, pp, ®mask_dummy,
8489 memset(cbits, 0, sizeof(cbits));
8493 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, ®mask_dep, &has_ret);
8495 // find unreachable code - must be fixed in IDA
8496 for (i = 0; i < opcnt; i++)
8498 if (cbits[i >> 3] & (1 << (i & 7)))
8501 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
8502 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
8504 // the compiler sometimes still generates code after
8505 // noreturn OS functions
8508 if (!(ops[i].flags & OPF_RMD)
8509 && ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
8511 ferr(&ops[i], "unreachable code\n");
8515 for (i = 0; i < g_eqcnt; i++) {
8516 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
8517 max_bp_offset = g_eqs[i].offset;
8520 if (fp->argc_stack < 0) {
8521 max_bp_offset = (max_bp_offset + 3) & ~3;
8522 fp->argc_stack = max_bp_offset / 4;
8523 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
8527 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
8528 fp->has_ret = has_ret;
8530 printf("// has_ret %d, regmask_dep %x\n",
8531 fp->has_ret, fp->regmask_dep);
8532 output_hdr_fp(stdout, fp, 1);
8533 if (IS(funcn, "sub_10007F72")) exit(1);
8536 gen_x_cleanup(opcnt);
8539 static void hg_fp_resolve_deps(struct func_prototype *fp)
8541 struct func_prototype fp_s;
8545 // this thing is recursive, so mark first..
8546 fp->dep_resolved = 1;
8548 for (i = 0; i < fp->dep_func_cnt; i++) {
8549 strcpy(fp_s.name, fp->dep_func[i].name);
8550 fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8551 sizeof(hg_fp[0]), hg_fp_cmp_name);
8552 if (fp->dep_func[i].proto != NULL) {
8553 if (!fp->dep_func[i].proto->dep_resolved)
8554 hg_fp_resolve_deps(fp->dep_func[i].proto);
8556 dep = ~fp->dep_func[i].regmask_live
8557 & fp->dep_func[i].proto->regmask_dep;
8558 fp->regmask_dep |= dep;
8559 // printf("dep %s %s |= %x\n", fp->name,
8560 // fp->dep_func[i].name, dep);
8562 if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
8563 fp->has_ret = fp->dep_func[i].proto->has_ret;
8568 // make all thiscall/edx arg functions referenced from .data fastcall
8569 static void do_func_refs_from_data(void)
8571 struct func_prototype *fp, fp_s;
8574 for (i = 0; i < hg_ref_cnt; i++) {
8575 strcpy(fp_s.name, hg_refs[i]);
8576 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8577 sizeof(hg_fp[0]), hg_fp_cmp_name);
8581 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
8582 fp->regmask_dep |= mxCX | mxDX;
8586 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8589 const struct parsed_proto *pp;
8590 char *p, namebuf[NAMELEN];
8596 for (; count > 0; count--, fp++) {
8597 if (fp->has_ret == -1)
8598 fprintf(fout, "// ret unresolved\n");
8600 fprintf(fout, "// dep:");
8601 for (j = 0; j < fp->dep_func_cnt; j++) {
8602 fprintf(fout, " %s/", fp->dep_func[j].name);
8603 if (fp->dep_func[j].proto != NULL)
8604 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8605 fp->dep_func[j].proto->has_ret);
8607 fprintf(fout, "\n");
8610 p = strchr(fp->name, '@');
8612 memcpy(namebuf, fp->name, p - fp->name);
8613 namebuf[p - fp->name] = 0;
8621 pp = proto_parse(g_fhdr, name, 1);
8622 if (pp != NULL && pp->is_include)
8625 if (fp->pp != NULL) {
8626 // part of seed, output later
8630 regmask_dep = fp->regmask_dep;
8631 argc_normal = fp->argc_stack;
8633 fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
8634 (fp->has_ret ? "int" : "void"));
8635 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
8636 && (regmask_dep & ~mxCX) == 0)
8638 fprintf(fout, "/*__thiscall*/ ");
8642 else if (regmask_dep && (fp->is_stdcall || fp->argc_stack == 0)
8643 && (regmask_dep & ~(mxCX | mxDX)) == 0)
8645 fprintf(fout, " __fastcall ");
8646 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8652 else if (regmask_dep && !fp->is_stdcall) {
8653 fprintf(fout, "/*__usercall*/ ");
8655 else if (regmask_dep) {
8656 fprintf(fout, "/*__userpurge*/ ");
8658 else if (fp->is_stdcall)
8659 fprintf(fout, " __stdcall ");
8661 fprintf(fout, " __cdecl ");
8663 fprintf(fout, "%s(", name);
8666 for (j = 0; j < xSP; j++) {
8667 if (regmask_dep & (1 << j)) {
8670 fprintf(fout, ", ");
8672 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8674 fprintf(fout, "int");
8675 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
8679 for (j = 0; j < argc_normal; j++) {
8682 fprintf(fout, ", ");
8683 if (fp->pp != NULL) {
8684 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8685 if (!fp->pp->arg[arg - 1].type.is_ptr)
8689 fprintf(fout, "int ");
8690 fprintf(fout, "a%d", arg);
8693 fprintf(fout, ");\n");
8697 static void output_hdr(FILE *fout)
8699 static const char *lmod_c_names[] = {
8700 [OPLM_UNSPEC] = "???",
8701 [OPLM_BYTE] = "uint8_t",
8702 [OPLM_WORD] = "uint16_t",
8703 [OPLM_DWORD] = "uint32_t",
8704 [OPLM_QWORD] = "uint64_t",
8706 const struct scanned_var *var;
8707 struct func_prototype *fp;
8708 char line[256] = { 0, };
8712 // add stuff from headers
8713 for (i = 0; i < pp_cache_size; i++) {
8714 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
8715 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
8717 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
8718 fp = hg_fp_add(name);
8719 fp->pp = &pp_cache[i];
8720 fp->argc_stack = fp->pp->argc_stack;
8721 fp->is_stdcall = fp->pp->is_stdcall;
8722 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
8723 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
8727 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
8728 for (i = 0; i < hg_fp_cnt; i++)
8729 hg_fp_resolve_deps(&hg_fp[i]);
8731 // adjust functions referenced from data segment
8732 do_func_refs_from_data();
8734 // final adjustments
8735 for (i = 0; i < hg_fp_cnt; i++) {
8736 if (hg_fp[i].eax_pass && (hg_fp[i].regmask_dep & mxAX))
8737 hg_fp[i].has_ret = 1;
8740 // note: messes up .proto ptr, don't use
8741 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
8744 for (i = 0; i < hg_var_cnt; i++) {
8747 if (var->pp != NULL)
8750 else if (var->is_c_str)
8751 fprintf(fout, "extern %-8s %s[];", "char", var->name);
8753 fprintf(fout, "extern %-8s %s;",
8754 lmod_c_names[var->lmod], var->name);
8757 fprintf(fout, " // seeded");
8758 fprintf(fout, "\n");
8761 fprintf(fout, "\n");
8763 // output function prototypes
8764 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
8767 fprintf(fout, "\n// - seed -\n");
8770 while (fgets(line, sizeof(line), g_fhdr))
8771 fwrite(line, 1, strlen(line), fout);
8774 // '=' needs special treatment
8776 static char *next_word_s(char *w, size_t wsize, char *s)
8783 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
8785 for (i = 1; i < wsize - 1; i++) {
8787 printf("warning: missing closing quote: \"%s\"\n", s);
8796 for (; i < wsize - 1; i++) {
8797 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
8803 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
8804 printf("warning: '%s' truncated\n", w);
8809 static int cmpstringp(const void *p1, const void *p2)
8811 return strcmp(*(char * const *)p1, *(char * const *)p2);
8814 static int is_xref_needed(char *p, char **rlist, int rlist_len)
8819 if (strstr(p, "..."))
8820 // unable to determine, assume needed
8823 if (*p == '.') // .text, .data, ...
8824 // ref from other data or non-function -> no
8827 p2 = strpbrk(p, "+:\r\n\x18");
8830 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8831 // referenced from removed code
8837 static int ida_xrefs_show_need(FILE *fasm, char *p,
8838 char **rlist, int rlist_len)
8844 p = strrchr(p, ';');
8845 if (p != NULL && *p == ';') {
8846 if (IS_START(p + 2, "sctref"))
8848 if (IS_START(p + 2, "DATA XREF: ")) {
8850 if (is_xref_needed(p, rlist, rlist_len))
8858 if (!my_fgets(line, sizeof(line), fasm))
8860 // non-first line is always indented
8861 if (!my_isblank(line[0]))
8864 // should be no content, just comment
8869 p = strrchr(p, ';');
8872 if (IS_START(p, "sctref")) {
8877 // it's printed once, but no harm to check again
8878 if (IS_START(p, "DATA XREF: "))
8881 if (is_xref_needed(p, rlist, rlist_len)) {
8886 fseek(fasm, pos, SEEK_SET);
8890 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
8892 struct scanned_var *var;
8893 char line[256] = { 0, };
8902 // skip to next data section
8903 while (my_fgets(line, sizeof(line), fasm))
8908 if (*p == 0 || *p == ';')
8911 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
8912 if (*p == 0 || *p == ';')
8915 if (*p != 's' || !IS_START(p, "segment para public"))
8921 if (p == NULL || !IS_START(p, "segment para public"))
8925 if (!IS_START(p, "'DATA'"))
8929 while (my_fgets(line, sizeof(line), fasm))
8934 no_identifier = my_isblank(*p);
8937 if (*p == 0 || *p == ';')
8940 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8941 words[wordc][0] = 0;
8942 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8943 if (*p == 0 || *p == ';') {
8949 if (wordc == 2 && IS(words[1], "ends"))
8954 if (no_identifier) {
8955 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
8956 hg_ref_add(words[2]);
8960 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
8961 // when this starts, we don't need anything from this section
8965 // check refs comment(s)
8966 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
8969 if ((hg_var_cnt & 0xff) == 0) {
8970 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
8971 * (hg_var_cnt + 0x100));
8972 my_assert_not(hg_vars, NULL);
8973 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
8976 var = &hg_vars[hg_var_cnt++];
8977 snprintf(var->name, sizeof(var->name), "%s", words[0]);
8979 // maybe already in seed header?
8980 var->pp = proto_parse(g_fhdr, var->name, 1);
8981 if (var->pp != NULL) {
8982 if (var->pp->is_fptr) {
8983 var->lmod = OPLM_DWORD;
8986 else if (var->pp->is_func)
8988 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
8989 aerr("unhandled C type '%s' for '%s'\n",
8990 var->pp->type.name, var->name);
8996 if (IS(words[1], "dd")) {
8997 var->lmod = OPLM_DWORD;
8998 if (wordc >= 4 && IS(words[2], "offset"))
8999 hg_ref_add(words[3]);
9001 else if (IS(words[1], "dw"))
9002 var->lmod = OPLM_WORD;
9003 else if (IS(words[1], "db")) {
9004 var->lmod = OPLM_BYTE;
9005 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
9006 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
9010 else if (IS(words[1], "dq"))
9011 var->lmod = OPLM_QWORD;
9012 //else if (IS(words[1], "dt"))
9014 aerr("type '%s' not known\n", words[1]);
9022 static void set_label(int i, const char *name)
9028 p = strchr(name, ':');
9032 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
9033 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
9034 g_labels[i] = realloc(g_labels[i], len + 1);
9035 my_assert_not(g_labels[i], NULL);
9036 memcpy(g_labels[i], name, len);
9037 g_labels[i][len] = 0;
9046 static struct chunk_item *func_chunks;
9047 static int func_chunk_cnt;
9048 static int func_chunk_alloc;
9050 static void add_func_chunk(FILE *fasm, const char *name, int line)
9052 if (func_chunk_cnt >= func_chunk_alloc) {
9053 func_chunk_alloc *= 2;
9054 func_chunks = realloc(func_chunks,
9055 func_chunk_alloc * sizeof(func_chunks[0]));
9056 my_assert_not(func_chunks, NULL);
9058 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
9059 func_chunks[func_chunk_cnt].name = strdup(name);
9060 func_chunks[func_chunk_cnt].asmln = line;
9064 static int cmp_chunks(const void *p1, const void *p2)
9066 const struct chunk_item *c1 = p1, *c2 = p2;
9067 return strcmp(c1->name, c2->name);
9070 static void scan_ahead_for_chunks(FILE *fasm)
9080 oldpos = ftell(fasm);
9083 while (my_fgets(line, sizeof(line), fasm))
9094 // get rid of random tabs
9095 for (i = 0; line[i] != 0; i++)
9096 if (line[i] == '\t')
9099 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9102 next_word(words[0], sizeof(words[0]), p);
9103 if (words[0][0] == 0)
9104 aerr("missing name for func chunk?\n");
9106 add_func_chunk(fasm, words[0], asmln);
9108 else if (IS_START(p, "; sctend"))
9114 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9115 words[wordc][0] = 0;
9116 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9117 if (*p == 0 || *p == ';') {
9123 if (wordc == 2 && IS(words[1], "ends"))
9127 fseek(fasm, oldpos, SEEK_SET);
9131 int main(int argc, char *argv[])
9133 FILE *fout, *fasm, *frlist;
9134 struct parsed_data *pd = NULL;
9136 char **rlist = NULL;
9138 int rlist_alloc = 0;
9139 int func_chunks_used = 0;
9140 int func_chunks_sorted = 0;
9141 int func_chunk_i = -1;
9142 long func_chunk_ret = 0;
9143 int func_chunk_ret_ln = 0;
9144 int scanned_ahead = 0;
9146 char words[20][256];
9147 enum opr_lenmod lmod;
9148 char *sctproto = NULL;
9150 int pending_endp = 0;
9152 int skip_code_end = 0;
9153 int skip_warned = 0;
9166 for (arg = 1; arg < argc; arg++) {
9167 if (IS(argv[arg], "-v"))
9169 else if (IS(argv[arg], "-rf"))
9170 g_allow_regfunc = 1;
9171 else if (IS(argv[arg], "-uc"))
9172 g_allow_user_icall = 1;
9173 else if (IS(argv[arg], "-m"))
9175 else if (IS(argv[arg], "-hdr"))
9176 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
9181 if (argc < arg + 3) {
9182 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
9183 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
9185 " -hdr - header generation mode\n"
9186 " -rf - allow unannotated indirect calls\n"
9187 " -uc - allow ind. calls/refs to __usercall\n"
9188 " -m - allow multiple .text sections\n"
9189 "[rlist] is a file with function names to skip,"
9197 asmfn = argv[arg++];
9198 fasm = fopen(asmfn, "r");
9199 my_assert_not(fasm, NULL);
9201 hdrfn = argv[arg++];
9202 g_fhdr = fopen(hdrfn, "r");
9203 my_assert_not(g_fhdr, NULL);
9206 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
9207 my_assert_not(rlist, NULL);
9208 // needs special handling..
9209 rlist[rlist_len++] = "__alloca_probe";
9211 func_chunk_alloc = 32;
9212 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
9213 my_assert_not(func_chunks, NULL);
9215 memset(words, 0, sizeof(words));
9217 for (; arg < argc; arg++) {
9220 frlist = fopen(argv[arg], "r");
9221 my_assert_not(frlist, NULL);
9223 while (my_fgets(line, sizeof(line), frlist)) {
9225 if (*p == 0 || *p == ';')
9228 if (IS_START(p, "#if 0")
9229 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
9233 else if (IS_START(p, "#endif"))
9240 p = next_word(words[0], sizeof(words[0]), p);
9241 if (words[0][0] == 0)
9244 if (rlist_len >= rlist_alloc) {
9245 rlist_alloc = rlist_alloc * 2 + 64;
9246 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
9247 my_assert_not(rlist, NULL);
9249 rlist[rlist_len++] = strdup(words[0]);
9257 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
9259 fout = fopen(argv[arg_out], "w");
9260 my_assert_not(fout, NULL);
9263 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
9264 my_assert_not(g_eqs, NULL);
9266 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
9267 g_label_refs[i].i = -1;
9268 g_label_refs[i].next = NULL;
9272 scan_variables(fasm, rlist, rlist_len);
9274 while (my_fgets(line, sizeof(line), fasm))
9283 // get rid of random tabs
9284 for (i = 0; line[i] != 0; i++)
9285 if (line[i] == '\t')
9290 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
9291 goto do_pending_endp; // eww..
9293 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
9295 static const char *attrs[] = {
9304 // parse IDA's attribute-list comment
9305 g_ida_func_attr = 0;
9308 for (; *p != 0; p = sskip(p)) {
9309 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9310 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9311 g_ida_func_attr |= 1 << i;
9312 p += strlen(attrs[i]);
9316 if (i == ARRAY_SIZE(attrs)) {
9317 anote("unparsed IDA attr: %s\n", p);
9320 if (IS(attrs[i], "fpd=")) {
9321 p = next_word(words[0], sizeof(words[0]), p);
9326 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
9328 static const char *attrs[] = {
9333 // parse manual attribute-list comment
9334 g_sct_func_attr = 0;
9337 for (; *p != 0; p = sskip(p)) {
9338 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9339 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9340 g_sct_func_attr |= 1 << i;
9341 p += strlen(attrs[i]);
9348 // clear_sf=start,len (in dwords)
9349 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
9350 &g_stack_clear_len, &j);
9352 // clear_regmask=<mask>
9353 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
9355 anote("unparsed attr value: %s\n", p);
9360 else if (i == ARRAY_SIZE(attrs)) {
9361 anote("unparsed sct attr: %s\n", p);
9366 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9369 next_word(words[0], sizeof(words[0]), p);
9370 if (words[0][0] == 0)
9371 aerr("missing name for func chunk?\n");
9373 if (!scanned_ahead) {
9374 add_func_chunk(fasm, words[0], asmln);
9375 func_chunks_sorted = 0;
9378 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
9380 if (func_chunk_i >= 0) {
9381 if (func_chunk_i < func_chunk_cnt
9382 && IS(func_chunks[func_chunk_i].name, g_func))
9384 // move on to next chunk
9385 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9387 aerr("seek failed for '%s' chunk #%d\n",
9388 g_func, func_chunk_i);
9389 asmln = func_chunks[func_chunk_i].asmln;
9393 if (func_chunk_ret == 0)
9394 aerr("no return from chunk?\n");
9395 fseek(fasm, func_chunk_ret, SEEK_SET);
9396 asmln = func_chunk_ret_ln;
9402 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
9403 func_chunks_used = 1;
9405 if (IS_START(g_func, "sub_")) {
9406 unsigned long addr = strtoul(p, NULL, 16);
9407 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
9408 if (addr > f_addr && !scanned_ahead) {
9409 //anote("scan_ahead caused by '%s', addr %lx\n",
9411 scan_ahead_for_chunks(fasm);
9413 func_chunks_sorted = 0;
9421 for (i = wordc; i < ARRAY_SIZE(words); i++)
9423 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9424 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9425 if (*p == 0 || *p == ';') {
9430 if (*p != 0 && *p != ';')
9431 aerr("too many words\n");
9433 if (skip_code_end) {
9438 // allow asm patches in comments
9440 // skip IDA's forced non-removable comment
9441 if (!IS_START(p, "; sct") && (p2 = strchr(p + 1, ';')))
9444 if (*p == ';' && IS_START(p, "; sct")) {
9445 if (IS_START(p, "; sctpatch:")) {
9447 if (*p == 0 || *p == ';')
9449 goto parse_words; // lame
9451 if (IS_START(p, "; sctproto:")) {
9452 sctproto = strdup(p + 11);
9454 else if (IS_START(p, "; sctend")) {
9459 else if (IS_START(p, "; sctskip_start")) {
9460 if (in_func && !g_skip_func) {
9462 ops[pi].op = OPP_ABORT;
9463 ops[pi].asmln = asmln;
9469 else if (IS_START(p, "; sctskip_end")) {
9477 awarn("wordc == 0?\n");
9481 // don't care about this:
9482 if (words[0][0] == '.'
9483 || IS(words[0], "include")
9484 || IS(words[0], "assume") || IS(words[1], "segment")
9485 || IS(words[0], "align"))
9491 // do delayed endp processing to collect switch jumptables
9493 if (in_func && !g_skip_func && !end && wordc >= 2
9494 && ((words[0][0] == 'd' && words[0][2] == 0)
9495 || (words[1][0] == 'd' && words[1][2] == 0)))
9498 if (words[1][0] == 'd' && words[1][2] == 0) {
9500 if (g_func_pd_cnt >= pd_alloc) {
9501 pd_alloc = pd_alloc * 2 + 16;
9502 g_func_pd = realloc(g_func_pd,
9503 sizeof(g_func_pd[0]) * pd_alloc);
9504 my_assert_not(g_func_pd, NULL);
9506 pd = &g_func_pd[g_func_pd_cnt];
9508 memset(pd, 0, sizeof(*pd));
9509 strcpy(pd->label, words[0]);
9510 pd->type = OPT_CONST;
9511 pd->lmod = lmod_from_directive(words[1]);
9517 anote("skipping alignment byte?\n");
9520 lmod = lmod_from_directive(words[0]);
9521 if (lmod != pd->lmod)
9522 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
9525 if (pd->count_alloc < pd->count + wordc) {
9526 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
9527 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
9528 my_assert_not(pd->d, NULL);
9530 for (; i < wordc; i++) {
9531 if (IS(words[i], "offset")) {
9532 pd->type = OPT_OFFSET;
9535 p = strchr(words[i], ',');
9538 if (pd->type == OPT_OFFSET)
9539 pd->d[pd->count].u.label = strdup(words[i]);
9541 pd->d[pd->count].u.val = parse_number(words[i], 0);
9542 pd->d[pd->count].bt_i = -1;
9548 if (in_func && !g_skip_func) {
9550 gen_hdr(g_func, pi);
9552 gen_func(fout, g_fhdr, g_func, pi);
9557 g_ida_func_attr = 0;
9558 g_sct_func_attr = 0;
9559 g_stack_clear_start = 0;
9560 g_stack_clear_len = 0;
9566 func_chunks_used = 0;
9569 memset(&ops, 0, pi * sizeof(ops[0]));
9574 for (i = 0; i < g_func_pd_cnt; i++) {
9576 if (pd->type == OPT_OFFSET) {
9577 for (j = 0; j < pd->count; j++)
9578 free(pd->d[j].u.label);
9593 if (IS(words[1], "proc")) {
9595 aerr("proc '%s' while in_func '%s'?\n",
9598 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9600 strcpy(g_func, words[0]);
9601 set_label(0, words[0]);
9606 if (IS(words[1], "endp"))
9609 aerr("endp '%s' while not in_func?\n", words[0]);
9610 if (!IS(g_func, words[0]))
9611 aerr("endp '%s' while in_func '%s'?\n",
9614 aerr("endp '%s' while skipping code\n", words[0]);
9616 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
9617 && ops[0].op == OP_JMP && ops[0].operand[0].segment)
9623 if (!g_skip_func && func_chunks_used) {
9624 // start processing chunks
9625 struct chunk_item *ci, key = { g_func, 0 };
9627 func_chunk_ret = ftell(fasm);
9628 func_chunk_ret_ln = asmln;
9629 if (!func_chunks_sorted) {
9630 qsort(func_chunks, func_chunk_cnt,
9631 sizeof(func_chunks[0]), cmp_chunks);
9632 func_chunks_sorted = 1;
9634 ci = bsearch(&key, func_chunks, func_chunk_cnt,
9635 sizeof(func_chunks[0]), cmp_chunks);
9637 aerr("'%s' needs chunks, but none found\n", g_func);
9638 func_chunk_i = ci - func_chunks;
9639 for (; func_chunk_i > 0; func_chunk_i--)
9640 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
9643 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9645 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
9646 asmln = func_chunks[func_chunk_i].asmln;
9654 if (wordc == 2 && IS(words[1], "ends")) {
9658 goto do_pending_endp;
9662 // scan for next text segment
9663 while (my_fgets(line, sizeof(line), fasm)) {
9666 if (*p == 0 || *p == ';')
9669 if (strstr(p, "segment para public 'CODE' use32"))
9676 p = strchr(words[0], ':');
9678 set_label(pi, words[0]);
9682 if (!in_func || g_skip_func || skip_code) {
9683 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
9685 anote("skipping from '%s'\n", g_labels[pi]);
9689 g_labels[pi] = NULL;
9693 if (wordc > 1 && IS(words[1], "="))
9696 aerr("unhandled equ, wc=%d\n", wordc);
9697 if (g_eqcnt >= eq_alloc) {
9699 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
9700 my_assert_not(g_eqs, NULL);
9703 len = strlen(words[0]);
9704 if (len > sizeof(g_eqs[0].name) - 1)
9705 aerr("equ name too long: %d\n", len);
9706 strcpy(g_eqs[g_eqcnt].name, words[0]);
9708 if (!IS(words[3], "ptr"))
9709 aerr("unhandled equ\n");
9710 if (IS(words[2], "dword"))
9711 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
9712 else if (IS(words[2], "word"))
9713 g_eqs[g_eqcnt].lmod = OPLM_WORD;
9714 else if (IS(words[2], "byte"))
9715 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
9716 else if (IS(words[2], "qword"))
9717 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
9719 aerr("bad lmod: '%s'\n", words[2]);
9721 g_eqs[g_eqcnt].offset = parse_number(words[4], 0);
9726 if (pi >= ARRAY_SIZE(ops))
9727 aerr("too many ops\n");
9729 parse_op(&ops[pi], words, wordc);
9731 ops[pi].datap = sctproto;
9746 // vim:ts=2:shiftwidth=2:expandtab