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), /* 32bit division */
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 op->regmask_src |= op->regmask_dst;
1341 op->regmask_dst = (1 << xDX) | (1 << xAX);
1342 if (op->operand[0].lmod == OPLM_UNSPEC)
1343 op->operand[0].lmod = OPLM_DWORD;
1348 // we could set up operands for edx:eax, but there is no real need to
1349 // (see is_opr_modified())
1350 op->regmask_src |= op->regmask_dst;
1351 op->regmask_dst = (1 << xDX) | (1 << xAX);
1352 if (op->operand[0].lmod == OPLM_UNSPEC)
1353 op->operand[0].lmod = OPLM_DWORD;
1361 op->regmask_src |= op->regmask_dst;
1362 if (op->operand[1].lmod == OPLM_UNSPEC)
1363 op->operand[1].lmod = OPLM_BYTE;
1368 op->regmask_src |= op->regmask_dst;
1369 if (op->operand[2].lmod == OPLM_UNSPEC)
1370 op->operand[2].lmod = OPLM_BYTE;
1374 op->regmask_src |= op->regmask_dst;
1375 op->regmask_dst = 0;
1376 if (op->operand[0].lmod == OPLM_UNSPEC
1377 && (op->operand[0].type == OPT_CONST
1378 || op->operand[0].type == OPT_OFFSET
1379 || op->operand[0].type == OPT_LABEL))
1380 op->operand[0].lmod = OPLM_DWORD;
1386 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1387 && op->operand[0].lmod == op->operand[1].lmod
1388 && op->operand[0].reg == op->operand[1].reg
1389 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1391 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1392 op->regmask_src = op->regmask_dst = 0;
1397 if (op->operand[0].type == OPT_REG
1398 && op->operand[1].type == OPT_REGMEM)
1401 snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1402 if (IS(buf, op->operand[1].name))
1403 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1408 // trashed regs must be explicitly detected later
1409 op->regmask_dst = 0;
1413 op->regmask_dst = (1 << xBP) | (1 << xSP);
1414 op->regmask_src = 1 << xBP;
1419 op->regmask_dst |= mxST0;
1423 op->regmask_dst |= mxST0;
1424 if (IS(words[op_w] + 3, "1"))
1425 op->operand[0].val = X87_CONST_1;
1426 else if (IS(words[op_w] + 3, "l2t"))
1427 op->operand[0].val = X87_CONST_L2T;
1428 else if (IS(words[op_w] + 3, "l2e"))
1429 op->operand[0].val = X87_CONST_L2E;
1430 else if (IS(words[op_w] + 3, "pi"))
1431 op->operand[0].val = X87_CONST_PI;
1432 else if (IS(words[op_w] + 3, "lg2"))
1433 op->operand[0].val = X87_CONST_LG2;
1434 else if (IS(words[op_w] + 3, "ln2"))
1435 op->operand[0].val = X87_CONST_LN2;
1436 else if (IS(words[op_w] + 3, "z"))
1437 op->operand[0].val = X87_CONST_Z;
1439 aerr("fld what?\n");
1444 op->regmask_src |= mxST0;
1453 op->regmask_src |= mxST0;
1454 if (op->operand_cnt == 2)
1455 op->regmask_src |= op->regmask_dst;
1456 else if (op->operand_cnt == 1) {
1457 memcpy(&op->operand[1], &op->operand[0], sizeof(op->operand[1]));
1458 op->operand[0].type = OPT_REG;
1459 op->operand[0].lmod = OPLM_QWORD;
1460 op->operand[0].reg = xST0;
1461 op->regmask_dst |= mxST0;
1464 // IDA doesn't use this
1465 aerr("no operands?\n");
1479 op->regmask_src |= mxST0;
1480 op->regmask_dst |= mxST0;
1485 op->regmask_src |= mxST0 | mxST1;
1486 op->regmask_dst |= mxST0;
1494 op->regmask_src |= mxST0;
1495 if (op->operand_cnt == 0) {
1496 op->operand_cnt = 1;
1497 op->operand[0].type = OPT_REG;
1498 op->operand[0].lmod = OPLM_QWORD;
1499 op->operand[0].reg = xST1;
1500 op->regmask_src |= mxST1;
1508 if (op->operand[0].type == OPT_REG
1509 && op->operand[1].type == OPT_CONST)
1511 struct parsed_opr *op1 = &op->operand[1];
1512 if ((op->op == OP_AND && op1->val == 0)
1515 || (op->operand[0].lmod == OPLM_WORD && op1->val == 0xffff)
1516 || (op->operand[0].lmod == OPLM_BYTE && op1->val == 0xff))))
1518 op->regmask_src = 0;
1523 static const char *op_name(struct parsed_op *po)
1525 static char buf[16];
1529 if (po->op == OP_JCC || po->op == OP_SCC) {
1531 *p++ = (po->op == OP_JCC) ? 'j' : 's';
1534 strcpy(p, parsed_flag_op_names[po->pfo]);
1538 for (i = 0; i < ARRAY_SIZE(op_table); i++)
1539 if (op_table[i].op == po->op)
1540 return op_table[i].name;
1546 static const char *dump_op(struct parsed_op *po)
1548 static char out[128];
1555 snprintf(out, sizeof(out), "%s", op_name(po));
1556 for (i = 0; i < po->operand_cnt; i++) {
1560 snprintf(p, sizeof(out) - (p - out),
1561 po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1562 po->operand[i].name);
1568 static const char *lmod_type_u(struct parsed_op *po,
1569 enum opr_lenmod lmod)
1581 ferr(po, "invalid lmod: %d\n", lmod);
1582 return "(_invalid_)";
1586 static const char *lmod_cast_u(struct parsed_op *po,
1587 enum opr_lenmod lmod)
1599 ferr(po, "invalid lmod: %d\n", lmod);
1600 return "(_invalid_)";
1604 static const char *lmod_cast_u_ptr(struct parsed_op *po,
1605 enum opr_lenmod lmod)
1617 ferr(po, "invalid lmod: %d\n", lmod);
1618 return "(_invalid_)";
1622 static const char *lmod_cast_s(struct parsed_op *po,
1623 enum opr_lenmod lmod)
1635 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1636 return "(_invalid_)";
1640 static const char *lmod_cast(struct parsed_op *po,
1641 enum opr_lenmod lmod, int is_signed)
1644 lmod_cast_s(po, lmod) :
1645 lmod_cast_u(po, lmod);
1648 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1660 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1665 static const char *opr_name(struct parsed_op *po, int opr_num)
1667 if (opr_num >= po->operand_cnt)
1668 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1669 return po->operand[opr_num].name;
1672 static unsigned int opr_const(struct parsed_op *po, int opr_num)
1674 if (opr_num >= po->operand_cnt)
1675 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1676 if (po->operand[opr_num].type != OPT_CONST)
1677 ferr(po, "opr %d: const expected\n", opr_num);
1678 return po->operand[opr_num].val;
1681 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1683 if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
1684 ferr(po, "invalid reg: %d\n", popr->reg);
1685 return regs_r32[popr->reg];
1688 static int check_simple_cast(const char *cast, int *bits, int *is_signed)
1690 if (IS_START(cast, "(s8)") || IS_START(cast, "(u8)"))
1692 else if (IS_START(cast, "(s16)") || IS_START(cast, "(u16)"))
1694 else if (IS_START(cast, "(s32)") || IS_START(cast, "(u32)"))
1696 else if (IS_START(cast, "(s64)") || IS_START(cast, "(u64)"))
1701 *is_signed = cast[1] == 's' ? 1 : 0;
1705 static int check_deref_cast(const char *cast, int *bits)
1707 if (IS_START(cast, "*(u8 *)"))
1709 else if (IS_START(cast, "*(u16 *)"))
1711 else if (IS_START(cast, "*(u32 *)"))
1713 else if (IS_START(cast, "*(u64 *)"))
1721 // cast1 is the "final" cast
1722 static const char *simplify_cast(const char *cast1, const char *cast2)
1724 static char buf[256];
1732 if (IS(cast1, cast2))
1735 if (check_simple_cast(cast1, &bits1, &s1) == 0
1736 && check_simple_cast(cast2, &bits2, &s2) == 0)
1741 if (check_simple_cast(cast1, &bits1, &s1) == 0
1742 && check_deref_cast(cast2, &bits2) == 0)
1744 if (bits1 == bits2) {
1745 snprintf(buf, sizeof(buf), "*(%c%d *)", s1 ? 's' : 'u', bits1);
1750 if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1753 snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1757 static const char *simplify_cast_num(const char *cast, unsigned int val)
1759 if (IS(cast, "(u8)") && val < 0x100)
1761 if (IS(cast, "(s8)") && val < 0x80)
1763 if (IS(cast, "(u16)") && val < 0x10000)
1765 if (IS(cast, "(s16)") && val < 0x8000)
1767 if (IS(cast, "(s32)") && val < 0x80000000)
1773 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1782 namelen = strlen(name);
1784 p = strpbrk(name, "+-");
1788 ferr(po, "equ parse failed for '%s'\n", name);
1791 *extra_offs = strtol(p, &endp, 16);
1792 if (*endp != 0 || errno != 0)
1793 ferr(po, "equ parse failed for '%s'\n", name);
1796 for (i = 0; i < g_eqcnt; i++)
1797 if (strncmp(g_eqs[i].name, name, namelen) == 0
1798 && g_eqs[i].name[namelen] == 0)
1802 ferr(po, "unresolved equ name: '%s'\n", name);
1809 static int is_stack_access(struct parsed_op *po,
1810 const struct parsed_opr *popr)
1812 return (parse_stack_el(popr->name, NULL, NULL, 0)
1813 || (g_bp_frame && !(po->flags & OPF_EBP_S)
1814 && IS_START(popr->name, "ebp")));
1817 static void parse_stack_access(struct parsed_op *po,
1818 const char *name, char *ofs_reg, int *offset_out,
1819 int *stack_ra_out, const char **bp_arg_out, int is_lea)
1821 const char *bp_arg = "";
1822 const char *p = NULL;
1823 struct parsed_equ *eq;
1830 if (IS_START(name, "ebp-")
1831 || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1834 if (IS_START(p, "0x"))
1837 offset = strtoul(p, &endp, 16);
1840 if (*endp != 0 || errno != 0)
1841 ferr(po, "ebp- parse of '%s' failed\n", name);
1844 bp_arg = parse_stack_el(name, ofs_reg, NULL, 0);
1845 eq = equ_find(po, bp_arg, &offset);
1847 ferr(po, "detected but missing eq\n");
1848 offset += eq->offset;
1851 if (!strncmp(name, "ebp", 3))
1854 // yes it sometimes LEAs ra for compares..
1855 if (!is_lea && ofs_reg[0] == 0
1856 && stack_ra <= offset && offset < stack_ra + 4)
1858 ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1861 *offset_out = offset;
1863 *stack_ra_out = stack_ra;
1865 *bp_arg_out = bp_arg;
1868 static int parse_stack_esp_offset(struct parsed_op *po,
1869 const char *name, int *offset_out)
1871 char ofs_reg[16] = { 0, };
1872 struct parsed_equ *eq;
1878 if (strstr(name, "esp") == NULL)
1880 bp_arg = parse_stack_el(name, ofs_reg, &base_val, 0);
1881 if (bp_arg == NULL) {
1882 // just plain offset?
1883 if (!IS_START(name, "esp+"))
1886 offset = strtol(name + 4, &endp, 0);
1887 if (endp == NULL || *endp != 0 || errno != 0)
1889 *offset_out = offset;
1893 if (ofs_reg[0] != 0)
1895 eq = equ_find(po, bp_arg, &offset);
1897 ferr(po, "detected but missing eq\n");
1898 offset += eq->offset;
1899 *offset_out = base_val + offset;
1903 static int stack_frame_access(struct parsed_op *po,
1904 struct parsed_opr *popr, char *buf, size_t buf_size,
1905 const char *name, const char *cast, int is_src, int is_lea)
1907 enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1908 const char *prefix = "";
1909 const char *bp_arg = NULL;
1910 char ofs_reg[16] = { 0, };
1911 int i, arg_i, arg_s;
1918 if (g_bp_frame && (po->flags & OPF_EBP_S)
1919 && !(po->regmask_src & mxSP))
1920 ferr(po, "stack_frame_access while ebp is scratch\n");
1922 parse_stack_access(po, name, ofs_reg, &offset,
1923 &stack_ra, &bp_arg, is_lea);
1925 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1927 if (offset > stack_ra)
1929 arg_i = (offset - stack_ra - 4) / 4;
1930 if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1932 if (g_func_pp->is_vararg
1933 && arg_i == g_func_pp->argc_stack && is_lea)
1935 // should be va_list
1938 snprintf(buf, buf_size, "%sap", cast);
1941 ferr(po, "offset %d (%s,%d) doesn't map to any arg\n",
1942 offset, bp_arg, arg_i);
1944 if (ofs_reg[0] != 0)
1945 ferr(po, "offset reg on arg access?\n");
1947 for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1948 if (g_func_pp->arg[i].reg != NULL)
1954 if (i == g_func_pp->argc)
1955 ferr(po, "arg %d not in prototype?\n", arg_i);
1957 popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
1964 ferr(po, "lea/byte to arg?\n");
1965 if (is_src && (offset & 3) == 0)
1966 snprintf(buf, buf_size, "%sa%d",
1967 simplify_cast(cast, "(u8)"), i + 1);
1969 snprintf(buf, buf_size, "%sBYTE%d(a%d)",
1970 cast, offset & 3, i + 1);
1975 ferr(po, "lea/word to arg?\n");
1980 ferr(po, "problematic arg store\n");
1981 snprintf(buf, buf_size, "%s((char *)&a%d + 1)",
1982 simplify_cast(cast, "*(u16 *)"), i + 1);
1985 ferr(po, "unaligned arg word load\n");
1987 else if (is_src && (offset & 2) == 0)
1988 snprintf(buf, buf_size, "%sa%d",
1989 simplify_cast(cast, "(u16)"), i + 1);
1991 snprintf(buf, buf_size, "%s%sWORD(a%d)",
1992 cast, (offset & 2) ? "HI" : "LO", i + 1);
2004 snprintf(buf, buf_size, "(u32)&a%d + %d",
2007 ferr(po, "unaligned arg store\n");
2009 // mov edx, [ebp+arg_4+2]; movsx ecx, dx
2010 snprintf(buf, buf_size, "%s(a%d >> %d)",
2011 prefix, i + 1, (offset & 3) * 8);
2015 snprintf(buf, buf_size, "%s%sa%d",
2016 prefix, is_lea ? "&" : "", i + 1);
2021 ferr_assert(po, !(offset & 7));
2024 snprintf(buf, buf_size, "%s%sa%d",
2025 prefix, is_lea ? "&" : "", i + 1);
2029 ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
2033 strcat(g_comment, " unaligned");
2036 guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
2037 if (tmp_lmod != OPLM_DWORD
2038 && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
2039 < lmod_bytes(po, popr->lmod) + (offset & 3))))
2041 ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
2042 i + 1, offset, g_func_pp->arg[i].type.name);
2044 // can't check this because msvc likes to reuse
2045 // arg space for scratch..
2046 //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
2047 // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
2051 if (g_stack_fsz == 0)
2052 ferr(po, "stack var access without stackframe\n");
2053 g_stack_frame_used = 1;
2055 sf_ofs = g_stack_fsz + offset;
2056 if (ofs_reg[0] == 0 && (offset > 0 || sf_ofs < 0))
2057 ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
2067 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2068 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2072 if ((sf_ofs & 1) || ofs_reg[0] != 0) {
2073 // known unaligned or possibly unaligned
2074 strcat(g_comment, " unaligned");
2076 prefix = "*(u16 *)&";
2077 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2078 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2081 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
2085 if ((sf_ofs & 3) || ofs_reg[0] != 0) {
2086 // known unaligned or possibly unaligned
2087 strcat(g_comment, " unaligned");
2089 prefix = "*(u32 *)&";
2090 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2091 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2094 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
2098 ferr_assert(po, !(sf_ofs & 7));
2099 ferr_assert(po, ofs_reg[0] == 0);
2100 // only used for x87 int64/float, float sets is_lea
2101 if (!is_lea && (po->flags & OPF_FINT))
2102 prefix = "*(s64 *)&";
2103 snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
2107 ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
2114 static void check_func_pp(struct parsed_op *po,
2115 const struct parsed_proto *pp, const char *pfx)
2117 enum opr_lenmod tmp_lmod;
2121 if (pp->argc_reg != 0) {
2122 if (!g_allow_user_icall && !pp->is_fastcall) {
2123 pp_print(buf, sizeof(buf), pp);
2124 ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
2126 if (pp->argc_stack > 0 && pp->argc_reg != 2)
2127 ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
2128 pfx, pp->argc_reg, pp->argc_stack);
2131 // fptrs must use 32bit args, callsite might have no information and
2132 // lack a cast to smaller types, which results in incorrectly masked
2133 // args passed (callee may assume masked args, it does on ARM)
2134 if (!pp->is_osinc) {
2135 for (i = 0; i < pp->argc; i++) {
2136 ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
2137 if (ret && tmp_lmod != OPLM_DWORD)
2138 ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
2139 i + 1, pp->arg[i].type.name);
2144 static const char *check_label_read_ref(struct parsed_op *po,
2147 const struct parsed_proto *pp;
2149 pp = proto_parse(g_fhdr, name, 0);
2151 ferr(po, "proto_parse failed for ref '%s'\n", name);
2154 check_func_pp(po, pp, "ref");
2159 static void check_opr(struct parsed_op *po, struct parsed_opr *popr)
2161 if (popr->segment == SEG_FS)
2162 ferr(po, "fs: used\n");
2163 if (popr->segment == SEG_GS)
2164 ferr(po, "gs: used\n");
2167 static char *out_src_opr(char *buf, size_t buf_size,
2168 struct parsed_op *po, struct parsed_opr *popr, const char *cast,
2171 char tmp1[256], tmp2[256];
2177 check_opr(po, popr);
2182 switch (popr->type) {
2185 ferr(po, "lea from reg?\n");
2187 switch (popr->lmod) {
2189 snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2192 snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2195 snprintf(buf, buf_size, "%s%s",
2196 simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2199 if (popr->name[1] == 'h') // XXX..
2200 snprintf(buf, buf_size, "%s(%s >> 8)",
2201 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2203 snprintf(buf, buf_size, "%s%s",
2204 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2207 ferr(po, "invalid src lmod: %d\n", popr->lmod);
2212 if (is_stack_access(po, popr)) {
2213 stack_frame_access(po, popr, buf, buf_size,
2214 popr->name, cast, 1, is_lea);
2218 strcpy(expr, popr->name);
2219 if (strchr(expr, '[')) {
2220 // special case: '[' can only be left for label[reg] form
2221 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2223 ferr(po, "parse failure for '%s'\n", expr);
2224 if (tmp1[0] == '(') {
2225 // (off_4FFF50+3)[eax]
2226 p = strchr(tmp1 + 1, ')');
2227 if (p == NULL || p[1] != 0)
2228 ferr(po, "parse failure (2) for '%s'\n", expr);
2230 memmove(tmp1, tmp1 + 1, strlen(tmp1));
2232 snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2235 // XXX: do we need more parsing?
2237 snprintf(buf, buf_size, "%s", expr);
2241 snprintf(buf, buf_size, "%s(%s)",
2242 simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2246 name = check_label_read_ref(po, popr->name);
2247 if (cast[0] == 0 && popr->is_ptr)
2251 snprintf(buf, buf_size, "(u32)&%s", name);
2252 else if (popr->size_lt)
2253 snprintf(buf, buf_size, "%s%s%s%s", cast,
2254 lmod_cast_u_ptr(po, popr->lmod),
2255 popr->is_array ? "" : "&", name);
2257 snprintf(buf, buf_size, "%s%s%s", cast, name,
2258 popr->is_array ? "[0]" : "");
2262 name = check_label_read_ref(po, popr->name);
2266 ferr(po, "lea an offset?\n");
2267 snprintf(buf, buf_size, "%s&%s", cast, name);
2272 ferr(po, "lea from const?\n");
2274 printf_number(tmp1, sizeof(tmp1), popr->val);
2275 if (popr->val == 0 && strchr(cast, '*'))
2276 snprintf(buf, buf_size, "NULL");
2278 snprintf(buf, buf_size, "%s%s",
2279 simplify_cast_num(cast, popr->val), tmp1);
2283 ferr(po, "invalid src type: %d\n", popr->type);
2289 // note: may set is_ptr (we find that out late for ebp frame..)
2290 static char *out_dst_opr(char *buf, size_t buf_size,
2291 struct parsed_op *po, struct parsed_opr *popr)
2293 check_opr(po, popr);
2295 switch (popr->type) {
2297 switch (popr->lmod) {
2299 snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2302 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2306 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2310 if (popr->name[1] == 'h') // XXX..
2311 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2313 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2316 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2321 if (is_stack_access(po, popr)) {
2322 stack_frame_access(po, popr, buf, buf_size,
2323 popr->name, "", 0, 0);
2327 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2330 if (popr->size_mismatch)
2331 snprintf(buf, buf_size, "%s%s%s",
2332 lmod_cast_u_ptr(po, popr->lmod),
2333 popr->is_array ? "" : "&", popr->name);
2335 snprintf(buf, buf_size, "%s%s", popr->name,
2336 popr->is_array ? "[0]" : "");
2340 ferr(po, "invalid dst type: %d\n", popr->type);
2346 static char *out_src_opr_u32(char *buf, size_t buf_size,
2347 struct parsed_op *po, struct parsed_opr *popr)
2349 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2352 static char *out_opr_float(char *buf, size_t buf_size,
2353 struct parsed_op *po, struct parsed_opr *popr, int is_src,
2354 int need_float_stack)
2356 const char *cast = NULL;
2363 switch (popr->type) {
2365 if (popr->reg < xST0 || popr->reg > xST7) {
2367 ferr_assert(po, po->op == OP_PUSH);
2368 ferr_assert(po, popr->lmod == OPLM_DWORD);
2369 snprintf(buf, buf_size, "*(float *)&%s", opr_reg_p(po, popr));
2373 if (need_float_stack) {
2374 if (popr->reg == xST0)
2375 snprintf(buf, buf_size, "f_st[f_stp & 7]");
2377 snprintf(buf, buf_size, "f_st[(f_stp + %d) & 7]",
2381 snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2385 if (popr->lmod == OPLM_QWORD && is_stack_access(po, popr)) {
2386 stack_frame_access(po, popr, buf, buf_size,
2387 popr->name, "", is_src, 0);
2393 switch (popr->lmod) {
2401 ferr(po, "unhandled lmod: %d\n", popr->lmod);
2404 out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2405 snprintf(buf, buf_size, "*(%s *)(%s)", cast, tmp);
2409 // only for func float args pushes
2410 ferr_assert(po, po->op == OP_PUSH);
2411 u.i = po->operand[0].val;
2412 if (ceilf(u.f) == u.f)
2413 snprintf(buf, buf_size, "%.1ff", u.f);
2415 snprintf(buf, buf_size, "%.8ff", u.f);
2419 ferr(po, "invalid float type: %d\n", popr->type);
2425 static char *out_src_opr_float(char *buf, size_t buf_size,
2426 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2428 return out_opr_float(buf, buf_size, po, popr, 1, need_float_stack);
2431 static char *out_dst_opr_float(char *buf, size_t buf_size,
2432 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2434 return out_opr_float(buf, buf_size, po, popr, 0, need_float_stack);
2437 static void out_test_for_cc(char *buf, size_t buf_size,
2438 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2439 enum opr_lenmod lmod, const char *expr)
2441 const char *cast, *scast;
2443 cast = lmod_cast_u(po, lmod);
2444 scast = lmod_cast_s(po, lmod);
2448 case PFO_BE: // CF==1||ZF==1; CF=0
2449 snprintf(buf, buf_size, "(%s%s %s 0)",
2450 cast, expr, is_inv ? "!=" : "==");
2454 case PFO_L: // SF!=OF; OF=0
2455 snprintf(buf, buf_size, "(%s%s %s 0)",
2456 scast, expr, is_inv ? ">=" : "<");
2459 case PFO_LE: // ZF==1||SF!=OF; OF=0
2460 snprintf(buf, buf_size, "(%s%s %s 0)",
2461 scast, expr, is_inv ? ">" : "<=");
2466 snprintf(buf, buf_size, "(%d)", !!is_inv);
2469 case PFO_P: // PF==1
2470 snprintf(buf, buf_size, "(%sdo_parity(%s))",
2471 is_inv ? "!" : "", expr);
2475 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2479 static void out_cmp_for_cc(char *buf, size_t buf_size,
2480 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2483 const char *cast, *scast, *cast_use;
2484 char buf1[256], buf2[256];
2485 enum opr_lenmod lmod;
2487 if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2488 ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2489 po->operand[0].lmod, po->operand[1].lmod);
2490 lmod = po->operand[0].lmod;
2492 cast = lmod_cast_u(po, lmod);
2493 scast = lmod_cast_s(po, lmod);
2509 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2512 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2513 if (po->op == OP_DEC)
2514 snprintf(buf2, sizeof(buf2), "1");
2517 snprintf(cast_op2, sizeof(cast_op2) - 1, "%s", cast_use);
2519 strcat(cast_op2, "-");
2520 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_op2, 0);
2525 // note: must be unsigned compare
2526 snprintf(buf, buf_size, "(%s %s %s)",
2527 buf1, is_inv ? ">=" : "<", buf2);
2531 snprintf(buf, buf_size, "(%s %s %s)",
2532 buf1, is_inv ? "!=" : "==", buf2);
2536 // note: must be unsigned compare
2537 snprintf(buf, buf_size, "(%s %s %s)",
2538 buf1, is_inv ? ">" : "<=", buf2);
2541 if (is_inv && lmod == OPLM_BYTE
2542 && po->operand[1].type == OPT_CONST
2543 && po->operand[1].val == 0xff)
2545 snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2546 snprintf(buf, buf_size, "(0)");
2550 // note: must be signed compare
2552 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2553 scast, buf1, buf2, is_inv ? ">=" : "<");
2557 snprintf(buf, buf_size, "(%s %s %s)",
2558 buf1, is_inv ? ">=" : "<", buf2);
2562 snprintf(buf, buf_size, "(%s %s %s)",
2563 buf1, is_inv ? ">" : "<=", buf2);
2571 static void out_cmp_test(char *buf, size_t buf_size,
2572 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2574 char buf1[256], buf2[256], buf3[256];
2576 if (po->op == OP_TEST) {
2577 if (IS(opr_name(po, 0), opr_name(po, 1))) {
2578 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2581 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2582 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2583 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2585 out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2586 po->operand[0].lmod, buf3);
2588 else if (po->op == OP_CMP) {
2589 out_cmp_for_cc(buf, buf_size, po, pfo, is_inv, 0);
2592 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2595 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2596 struct parsed_opr *popr2)
2598 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2599 ferr(po, "missing lmod for both operands\n");
2601 if (popr1->lmod == OPLM_UNSPEC)
2602 popr1->lmod = popr2->lmod;
2603 else if (popr2->lmod == OPLM_UNSPEC)
2604 popr2->lmod = popr1->lmod;
2605 else if (popr1->lmod != popr2->lmod) {
2606 if (popr1->type_from_var) {
2607 popr1->size_mismatch = 1;
2608 if (popr1->lmod < popr2->lmod)
2610 popr1->lmod = popr2->lmod;
2612 else if (popr2->type_from_var) {
2613 popr2->size_mismatch = 1;
2614 if (popr2->lmod < popr1->lmod)
2616 popr2->lmod = popr1->lmod;
2619 ferr(po, "conflicting lmods: %d vs %d\n",
2620 popr1->lmod, popr2->lmod);
2624 static const char *op_to_c(struct parsed_op *po)
2648 ferr(po, "op_to_c was supplied with %d\n", po->op);
2652 // last op in stream - unconditional branch or ret
2653 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2654 || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2655 && ops[_i].op != OP_CALL))
2657 #define check_i(po, i) \
2659 ferr(po, "bad " #i ": %d\n", i)
2661 // note: this skips over calls and rm'd stuff assuming they're handled
2662 // so it's intended to use at one of final passes
2663 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2664 int depth, int seen_noreturn, int flags_set)
2666 struct parsed_op *po;
2671 for (; i < opcnt; i++) {
2673 if (po->cc_scratch == magic)
2674 return ret; // already checked
2675 po->cc_scratch = magic;
2677 if (po->flags & OPF_TAIL) {
2678 if (po->op == OP_CALL) {
2679 if (po->pp != NULL && po->pp->is_noreturn)
2688 if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
2691 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2692 if (po->btj != NULL) {
2694 for (j = 0; j < po->btj->count; j++) {
2695 check_i(po, po->btj->d[j].bt_i);
2696 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2697 depth, seen_noreturn, flags_set);
2699 return ret; // dead end
2704 check_i(po, po->bt_i);
2705 if (po->flags & OPF_CJMP) {
2706 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2707 depth, seen_noreturn, flags_set);
2709 return ret; // dead end
2718 if ((po->op == OP_POP || po->op == OP_PUSH)
2719 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2724 if (po->op == OP_PUSH) {
2727 else if (po->op == OP_POP) {
2728 if (relevant && depth == 0) {
2729 po->flags |= flags_set;
2737 // for noreturn, assume msvc skipped stack cleanup
2738 return seen_noreturn ? 1 : -1;
2741 // scan for 'reg' pop backwards starting from i
2742 // intended to use for register restore search, so other reg
2743 // references are considered an error
2744 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2746 struct parsed_op *po;
2747 struct label_ref *lr;
2750 ops[i].cc_scratch = magic;
2754 if (g_labels[i] != NULL) {
2755 lr = &g_label_refs[i];
2756 for (; lr != NULL; lr = lr->next) {
2757 check_i(&ops[i], lr->i);
2758 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2762 if (i > 0 && LAST_OP(i - 1))
2770 if (ops[i].cc_scratch == magic)
2772 ops[i].cc_scratch = magic;
2775 if (po->op == OP_POP && po->operand[0].reg == reg) {
2776 if (po->flags & (OPF_RMD|OPF_DONE))
2779 po->flags |= set_flags;
2783 // this also covers the case where we reach corresponding push
2784 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2788 // nothing interesting on this path,
2789 // still return ret for something recursive calls could find
2793 static void find_reachable_exits(int i, int opcnt, int magic,
2794 int *exits, int *exit_count)
2796 struct parsed_op *po;
2799 for (; i < opcnt; i++)
2802 if (po->cc_scratch == magic)
2804 po->cc_scratch = magic;
2806 if (po->flags & OPF_TAIL) {
2807 ferr_assert(po, *exit_count < MAX_EXITS);
2808 exits[*exit_count] = i;
2813 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2814 if (po->flags & OPF_RMD)
2817 if (po->btj != NULL) {
2818 for (j = 0; j < po->btj->count; j++) {
2819 check_i(po, po->btj->d[j].bt_i);
2820 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2826 check_i(po, po->bt_i);
2827 if (po->flags & OPF_CJMP)
2828 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2836 // scan for 'reg' pop backwards starting from exits (all paths)
2837 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2839 static int exits[MAX_EXITS];
2840 static int exit_count;
2846 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2848 ferr_assert(&ops[i], exit_count > 0);
2851 for (j = 0; j < exit_count; j++) {
2853 ret = scan_for_rsave_pop_reg(e, i + opcnt * 16 + set_flags,
2859 if (ops[e].op == OP_CALL && ops[e].pp != NULL
2860 && ops[e].pp->is_noreturn)
2862 // assume stack cleanup was skipped
2871 // scan for one or more pop of push <const>
2872 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2873 int push_i, int is_probe)
2875 struct parsed_op *po;
2876 struct label_ref *lr;
2880 for (; i < opcnt; i++)
2883 if (po->cc_scratch == magic)
2884 return ret; // already checked
2885 po->cc_scratch = magic;
2887 if (po->flags & OPF_JMP) {
2888 if (po->flags & OPF_RMD)
2890 if (po->op == OP_CALL)
2893 if (po->btj != NULL) {
2894 for (j = 0; j < po->btj->count; j++) {
2895 check_i(po, po->btj->d[j].bt_i);
2896 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2904 check_i(po, po->bt_i);
2905 if (po->flags & OPF_CJMP) {
2906 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2917 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2920 if (g_labels[i] != NULL) {
2921 // all refs must be visited
2922 lr = &g_label_refs[i];
2923 for (; lr != NULL; lr = lr->next) {
2925 if (ops[lr->i].cc_scratch != magic)
2928 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2932 if (po->op == OP_POP)
2934 if (po->flags & (OPF_RMD|OPF_DONE))
2938 po->flags |= OPF_DONE;
2939 po->datap = &ops[push_i];
2948 static void scan_for_pop_const(int i, int opcnt, int magic)
2952 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
2954 ops[i].flags |= OPF_RMD | OPF_DONE;
2955 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
2959 // check if all branch targets within a marked path are also marked
2960 // note: the path checked must not be empty or end with a branch
2961 static int check_path_branches(int opcnt, int magic)
2963 struct parsed_op *po;
2966 for (i = 0; i < opcnt; i++) {
2968 if (po->cc_scratch != magic)
2971 if (po->flags & OPF_JMP) {
2972 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
2975 if (po->btj != NULL) {
2976 for (j = 0; j < po->btj->count; j++) {
2977 check_i(po, po->btj->d[j].bt_i);
2978 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
2983 check_i(po, po->bt_i);
2984 if (ops[po->bt_i].cc_scratch != magic)
2986 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
2994 // scan for multiple pushes for given pop
2995 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
2998 int reg = ops[pop_i].operand[0].reg;
2999 struct parsed_op *po;
3000 struct label_ref *lr;
3003 ops[i].cc_scratch = magic;
3007 if (g_labels[i] != NULL) {
3008 lr = &g_label_refs[i];
3009 for (; lr != NULL; lr = lr->next) {
3010 check_i(&ops[i], lr->i);
3011 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
3015 if (i > 0 && LAST_OP(i - 1))
3023 if (ops[i].cc_scratch == magic)
3025 ops[i].cc_scratch = magic;
3028 if (po->op == OP_CALL)
3030 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
3033 if (po->op == OP_PUSH)
3035 if (po->datap != NULL)
3037 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
3038 // leave this case for reg save/restore handlers
3042 po->flags |= OPF_PPUSH | OPF_DONE;
3043 po->datap = &ops[pop_i];
3052 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
3054 int magic = i + opcnt * 14;
3057 ret = scan_pushes_for_pop_r(i, magic, i, 1);
3059 ret = check_path_branches(opcnt, magic);
3061 ops[i].flags |= OPF_PPUSH | OPF_DONE;
3062 *regmask_pp |= 1 << ops[i].operand[0].reg;
3063 scan_pushes_for_pop_r(i, magic + 1, i, 0);
3068 static void scan_propagate_df(int i, int opcnt)
3070 struct parsed_op *po = &ops[i];
3073 for (; i < opcnt; i++) {
3075 if (po->flags & OPF_DF)
3076 return; // already resolved
3077 po->flags |= OPF_DF;
3079 if (po->op == OP_CALL)
3080 ferr(po, "call with DF set?\n");
3082 if (po->flags & OPF_JMP) {
3083 if (po->btj != NULL) {
3085 for (j = 0; j < po->btj->count; j++) {
3086 check_i(po, po->btj->d[j].bt_i);
3087 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
3092 if (po->flags & OPF_RMD)
3094 check_i(po, po->bt_i);
3095 if (po->flags & OPF_CJMP)
3096 scan_propagate_df(po->bt_i, opcnt);
3102 if (po->flags & OPF_TAIL)
3105 if (po->op == OP_CLD) {
3106 po->flags |= OPF_RMD | OPF_DONE;
3111 ferr(po, "missing DF clear?\n");
3114 // is operand 'opr' referenced by parsed_op 'po'?
3115 static int is_opr_referenced(const struct parsed_opr *opr,
3116 const struct parsed_op *po)
3120 if (opr->type == OPT_REG) {
3121 mask = po->regmask_dst | po->regmask_src;
3122 if (po->op == OP_CALL)
3123 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
3124 if ((1 << opr->reg) & mask)
3130 for (i = 0; i < po->operand_cnt; i++)
3131 if (IS(po->operand[0].name, opr->name))
3137 // is operand 'opr' read by parsed_op 'po'?
3138 static int is_opr_read(const struct parsed_opr *opr,
3139 const struct parsed_op *po)
3141 if (opr->type == OPT_REG) {
3142 if (po->regmask_src & (1 << opr->reg))
3152 // is operand 'opr' modified by parsed_op 'po'?
3153 static int is_opr_modified(const struct parsed_opr *opr,
3154 const struct parsed_op *po)
3158 if (opr->type == OPT_REG) {
3159 if (po->op == OP_CALL) {
3160 mask = po->regmask_dst;
3161 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
3162 if (mask & (1 << opr->reg))
3168 if (po->regmask_dst & (1 << opr->reg))
3174 return IS(po->operand[0].name, opr->name);
3177 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
3178 static int is_any_opr_modified(const struct parsed_op *po_test,
3179 const struct parsed_op *po, int c_mode)
3184 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
3187 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3190 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
3193 // in reality, it can wreck any register, but in decompiled C
3194 // version it can only overwrite eax or edx:eax
3195 mask = (1 << xAX) | (1 << xDX);
3199 if (po->op == OP_CALL
3200 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
3203 for (i = 0; i < po_test->operand_cnt; i++)
3204 if (IS(po_test->operand[i].name, po->operand[0].name))
3210 // scan for any po_test operand modification in range given
3211 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
3214 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3217 for (; i < opcnt; i++) {
3218 if (is_any_opr_modified(po_test, &ops[i], c_mode))
3225 // scan for po_test operand[0] modification in range given
3226 static int scan_for_mod_opr0(struct parsed_op *po_test,
3229 for (; i < opcnt; i++) {
3230 if (is_opr_modified(&po_test->operand[0], &ops[i]))
3237 static int try_resolve_const(int i, const struct parsed_opr *opr,
3238 int magic, unsigned int *val);
3240 static int scan_for_flag_set(int i, int opcnt, int magic,
3241 int *branched, int *setters, int *setter_cnt)
3243 struct label_ref *lr;
3247 if (ops[i].cc_scratch == magic) {
3248 // is this a problem?
3249 //ferr(&ops[i], "%s looped\n", __func__);
3252 ops[i].cc_scratch = magic;
3254 if (g_labels[i] != NULL) {
3257 lr = &g_label_refs[i];
3258 for (; lr->next; lr = lr->next) {
3259 check_i(&ops[i], lr->i);
3260 ret = scan_for_flag_set(lr->i, opcnt, magic,
3261 branched, setters, setter_cnt);
3266 check_i(&ops[i], lr->i);
3267 if (i > 0 && LAST_OP(i - 1)) {
3271 ret = scan_for_flag_set(lr->i, opcnt, magic,
3272 branched, setters, setter_cnt);
3278 if (ops[i].flags & OPF_FLAGS) {
3279 setters[*setter_cnt] = i;
3282 if (ops[i].flags & OPF_REP) {
3283 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
3286 ret = try_resolve_const(i, &opr, i + opcnt * 7, &uval);
3287 if (ret != 1 || uval == 0) {
3288 // can't treat it as full setter because of ecx=0 case,
3289 // also disallow delayed compare
3298 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3305 // scan back for cdq, if anything modifies edx, fail
3306 static int scan_for_cdq_edx(int i)
3309 if (g_labels[i] != NULL) {
3310 if (g_label_refs[i].next != NULL)
3312 if (i > 0 && LAST_OP(i - 1)) {
3313 i = g_label_refs[i].i;
3320 if (ops[i].op == OP_CDQ)
3323 if (ops[i].regmask_dst & (1 << xDX))
3330 static int scan_for_reg_clear(int i, int reg)
3333 if (g_labels[i] != NULL) {
3334 if (g_label_refs[i].next != NULL)
3336 if (i > 0 && LAST_OP(i - 1)) {
3337 i = g_label_refs[i].i;
3344 if (ops[i].op == OP_XOR
3345 && ops[i].operand[0].lmod == OPLM_DWORD
3346 && ops[i].operand[0].reg == ops[i].operand[1].reg
3347 && ops[i].operand[0].reg == reg)
3350 if (ops[i].regmask_dst & (1 << reg))
3357 static void patch_esp_adjust(struct parsed_op *po, int adj)
3359 ferr_assert(po, po->op == OP_ADD);
3360 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3361 ferr_assert(po, po->operand[1].type == OPT_CONST);
3363 // this is a bit of a hack, but deals with use of
3364 // single adj for multiple calls
3365 po->operand[1].val -= adj;
3366 po->flags |= OPF_RMD;
3367 if (po->operand[1].val == 0)
3368 po->flags |= OPF_DONE;
3369 ferr_assert(po, (int)po->operand[1].val >= 0);
3372 // scan for positive, constant esp adjust
3373 // multipath case is preliminary
3374 static int scan_for_esp_adjust(int i, int opcnt,
3375 int adj_expect, int *adj, int *is_multipath, int do_update)
3377 int adj_expect_unknown = 0;
3378 struct parsed_op *po;
3382 *adj = *is_multipath = 0;
3383 if (adj_expect < 0) {
3384 adj_expect_unknown = 1;
3385 adj_expect = 32 * 4; // enough?
3388 for (; i < opcnt && *adj < adj_expect; i++) {
3389 if (g_labels[i] != NULL)
3393 if (po->flags & OPF_DONE)
3396 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3397 if (po->operand[1].type != OPT_CONST)
3398 ferr(&ops[i], "non-const esp adjust?\n");
3399 *adj += po->operand[1].val;
3401 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3404 patch_esp_adjust(po, adj_expect);
3406 po->flags |= OPF_RMD;
3410 else if (po->op == OP_PUSH) {
3411 //if (first_pop == -1)
3412 // first_pop = -2; // none
3413 *adj -= lmod_bytes(po, po->operand[0].lmod);
3415 else if (po->op == OP_POP) {
3416 if (!(po->flags & OPF_DONE)) {
3417 // seems like msvc only uses 'pop ecx' for stack realignment..
3418 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3420 if (first_pop == -1 && *adj >= 0)
3423 if (do_update && *adj >= 0) {
3424 po->flags |= OPF_RMD;
3426 po->flags |= OPF_DONE | OPF_NOREGS;
3429 *adj += lmod_bytes(po, po->operand[0].lmod);
3430 if (*adj > adj_best)
3433 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3434 if (po->op == OP_JMP && po->btj == NULL) {
3440 if (po->op != OP_CALL)
3442 if (po->operand[0].type != OPT_LABEL)
3444 if (po->pp != NULL && po->pp->is_stdcall)
3446 if (adj_expect_unknown && first_pop >= 0)
3448 // assume it's another cdecl call
3452 if (first_pop >= 0) {
3453 // probably only 'pop ecx' was used
3461 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3463 struct parsed_op *po;
3467 ferr(ops, "%s: followed bad branch?\n", __func__);
3469 for (; i < opcnt; i++) {
3471 if (po->cc_scratch == magic)
3473 po->cc_scratch = magic;
3476 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3477 if (po->btj != NULL) {
3479 for (j = 0; j < po->btj->count; j++)
3480 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3484 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3485 if (!(po->flags & OPF_CJMP))
3488 if (po->flags & OPF_TAIL)
3493 static const struct parsed_proto *try_recover_pp(
3494 struct parsed_op *po, const struct parsed_opr *opr,
3495 int is_call, int *search_instead)
3497 const struct parsed_proto *pp = NULL;
3501 // maybe an arg of g_func?
3502 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3504 char ofs_reg[16] = { 0, };
3505 int arg, arg_s, arg_i;
3512 parse_stack_access(po, opr->name, ofs_reg,
3513 &offset, &stack_ra, NULL, 0);
3514 if (ofs_reg[0] != 0)
3515 ferr(po, "offset reg on arg access?\n");
3516 if (offset <= stack_ra) {
3517 // search who set the stack var instead
3518 if (search_instead != NULL)
3519 *search_instead = 1;
3523 arg_i = (offset - stack_ra - 4) / 4;
3524 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3525 if (g_func_pp->arg[arg].reg != NULL)
3531 if (arg == g_func_pp->argc)
3532 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3534 pp = g_func_pp->arg[arg].pp;
3537 ferr(po, "icall arg: arg%d has no pp\n", arg + 1);
3538 check_func_pp(po, pp, "icall arg");
3541 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3543 p = strchr(opr->name + 1, '[');
3544 memcpy(buf, opr->name, p - opr->name);
3545 buf[p - opr->name] = 0;
3546 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3548 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3549 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3552 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3555 check_func_pp(po, pp, "reg-fptr ref");
3561 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3562 int magic, const struct parsed_proto **pp_found, int *pp_i,
3565 const struct parsed_proto *pp = NULL;
3566 struct parsed_op *po;
3567 struct label_ref *lr;
3569 ops[i].cc_scratch = magic;
3572 if (g_labels[i] != NULL) {
3573 lr = &g_label_refs[i];
3574 for (; lr != NULL; lr = lr->next) {
3575 check_i(&ops[i], lr->i);
3576 scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3578 if (i > 0 && LAST_OP(i - 1))
3586 if (ops[i].cc_scratch == magic)
3588 ops[i].cc_scratch = magic;
3590 if (!(ops[i].flags & OPF_DATA))
3592 if (!is_opr_modified(opr, &ops[i]))
3594 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3595 // most probably trashed by some processing
3600 opr = &ops[i].operand[1];
3601 if (opr->type != OPT_REG)
3605 po = (i >= 0) ? &ops[i] : ops;
3608 // reached the top - can only be an arg-reg
3609 if (opr->type != OPT_REG || g_func_pp == NULL)
3612 for (i = 0; i < g_func_pp->argc; i++) {
3613 if (g_func_pp->arg[i].reg == NULL)
3615 if (IS(opr->name, g_func_pp->arg[i].reg))
3618 if (i == g_func_pp->argc)
3620 pp = g_func_pp->arg[i].pp;
3622 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3623 i + 1, g_func_pp->arg[i].reg);
3624 check_func_pp(po, pp, "icall reg-arg");
3627 pp = try_recover_pp(po, opr, 1, NULL);
3629 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3630 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3631 || (*pp_found)->is_stdcall != pp->is_stdcall
3632 //|| (*pp_found)->is_fptr != pp->is_fptr
3633 || (*pp_found)->argc != pp->argc
3634 || (*pp_found)->argc_reg != pp->argc_reg
3635 || (*pp_found)->argc_stack != pp->argc_stack)
3637 ferr(po, "icall: parsed_proto mismatch\n");
3647 static void add_label_ref(struct label_ref *lr, int op_i)
3649 struct label_ref *lr_new;
3656 lr_new = calloc(1, sizeof(*lr_new));
3658 lr_new->next = lr->next;
3662 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3664 struct parsed_op *po = &ops[i];
3665 struct parsed_data *pd;
3666 char label[NAMELEN], *p;
3669 p = strchr(po->operand[0].name, '[');
3673 len = p - po->operand[0].name;
3674 strncpy(label, po->operand[0].name, len);
3677 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3678 if (IS(g_func_pd[j].label, label)) {
3684 //ferr(po, "label '%s' not parsed?\n", label);
3687 if (pd->type != OPT_OFFSET)
3688 ferr(po, "label '%s' with non-offset data?\n", label);
3690 // find all labels, link
3691 for (j = 0; j < pd->count; j++) {
3692 for (l = 0; l < opcnt; l++) {
3693 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3694 add_label_ref(&g_label_refs[l], i);
3704 static void clear_labels(int count)
3708 for (i = 0; i < count; i++) {
3709 if (g_labels[i] != NULL) {
3716 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3721 for (i = 0; i < pp->argc; i++) {
3722 if (pp->arg[i].reg != NULL) {
3723 reg = char_array_i(regs_r32,
3724 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3726 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3727 pp->arg[i].reg, pp->name);
3728 regmask |= 1 << reg;
3735 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3740 if (pp->has_retreg) {
3741 for (i = 0; i < pp->argc; i++) {
3742 if (pp->arg[i].type.is_retreg) {
3743 reg = char_array_i(regs_r32,
3744 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3745 ferr_assert(ops, reg >= 0);
3746 regmask |= 1 << reg;
3751 if (strstr(pp->ret_type.name, "int64"))
3752 return regmask | (1 << xAX) | (1 << xDX);
3753 if (IS(pp->ret_type.name, "float")
3754 || IS(pp->ret_type.name, "double"))
3756 return regmask | mxST0;
3758 if (strcasecmp(pp->ret_type.name, "void") == 0)
3761 return regmask | mxAX;
3764 static int are_ops_same(struct parsed_op *po1, struct parsed_op *po2)
3766 return po1->op == po2->op && po1->operand_cnt == po2->operand_cnt
3767 && memcmp(po1->operand, po2->operand,
3768 sizeof(po1->operand[0]) * po1->operand_cnt) == 0;
3771 static void resolve_branches_parse_calls(int opcnt)
3773 static const struct {
3777 unsigned int regmask_src;
3778 unsigned int regmask_dst;
3780 { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3781 { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3782 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3783 // more precise? Wine gets away with just __ftol handler
3784 { "__ftol2", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3785 { "__CIpow", OPP_CIPOW, OPF_FPOP, mxST0|mxST1, mxST0 },
3787 const struct parsed_proto *pp_c;
3788 struct parsed_proto *pp;
3789 struct parsed_data *pd;
3790 struct parsed_op *po;
3791 const char *tmpname;
3796 for (i = 0; i < opcnt; i++)
3802 if (po->datap != NULL) {
3803 pp = calloc(1, sizeof(*pp));
3804 my_assert_not(pp, NULL);
3806 ret = parse_protostr(po->datap, pp);
3808 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3814 if (po->op == OP_CALL) {
3819 else if (po->operand[0].type == OPT_LABEL)
3821 tmpname = opr_name(po, 0);
3822 if (IS_START(tmpname, "loc_"))
3823 ferr(po, "call to loc_*\n");
3824 if (IS(tmpname, "__alloca_probe"))
3826 if (IS(tmpname, "__SEH_prolog")) {
3827 ferr_assert(po, g_seh_found == 0);
3831 if (IS(tmpname, "__SEH_epilog"))
3834 // convert some calls to pseudo-ops
3835 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3836 if (!IS(tmpname, pseudo_ops[l].name))
3839 po->op = pseudo_ops[l].op;
3840 po->operand_cnt = 0;
3841 po->regmask_src = pseudo_ops[l].regmask_src;
3842 po->regmask_dst = pseudo_ops[l].regmask_dst;
3843 po->flags = pseudo_ops[l].flags;
3844 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3847 if (l < ARRAY_SIZE(pseudo_ops))
3850 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3851 if (!g_header_mode && pp_c == NULL)
3852 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3855 pp = proto_clone(pp_c);
3856 my_assert_not(pp, NULL);
3862 check_func_pp(po, pp, "fptr var call");
3863 if (pp->is_noreturn) {
3864 po->flags |= OPF_TAIL;
3865 po->flags &= ~OPF_ATAIL; // most likely...
3872 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3875 if (po->operand[0].type == OPT_REGMEM) {
3876 pd = try_resolve_jumptab(i, opcnt);
3884 for (l = 0; l < opcnt; l++) {
3885 if (g_labels[l] != NULL
3886 && IS(po->operand[0].name, g_labels[l]))
3888 if (l == i + 1 && po->op == OP_JMP) {
3889 // yet another alignment type..
3890 po->flags |= OPF_RMD|OPF_DONE;
3893 add_label_ref(&g_label_refs[l], i);
3899 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3902 if (po->operand[0].type == OPT_LABEL)
3906 ferr(po, "unhandled branch\n");
3910 po->flags |= OPF_TAIL;
3911 prev_op = i > 0 ? ops[i - 1].op : OP_UD2;
3912 if (prev_op == OP_POP)
3913 po->flags |= OPF_ATAIL;
3914 if (g_stack_fsz + g_bp_frame == 0 && prev_op != OP_PUSH
3915 && (g_func_pp == NULL || g_func_pp->argc_stack > 0))
3917 po->flags |= OPF_ATAIL;
3923 static int resolve_origin(int i, const struct parsed_opr *opr,
3924 int magic, int *op_i, int *is_caller);
3926 static void eliminate_seh_writes(int opcnt)
3928 const struct parsed_opr *opr;
3933 // assume all sf writes above g_seh_size to be seh related
3934 // (probably unsafe but oh well)
3935 for (i = 0; i < opcnt; i++) {
3936 if (ops[i].op != OP_MOV)
3938 opr = &ops[i].operand[0];
3939 if (opr->type != OPT_REGMEM)
3941 if (!is_stack_access(&ops[i], opr))
3945 parse_stack_access(&ops[i], opr->name, ofs_reg, &offset,
3947 if (offset < 0 && offset >= -g_seh_size)
3948 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3952 static void eliminate_seh(int opcnt)
3956 for (i = 0; i < opcnt; i++) {
3957 if (ops[i].op != OP_MOV)
3959 if (ops[i].operand[0].segment != SEG_FS)
3961 if (!IS(opr_name(&ops[i], 0), "0"))
3964 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3965 if (ops[i].operand[1].reg == xSP) {
3966 for (j = i - 1; j >= 0; j--) {
3967 if (ops[j].op != OP_PUSH)
3969 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3971 if (ops[j].operand[0].val == ~0)
3973 if (ops[j].operand[0].type == OPT_REG) {
3975 ret = resolve_origin(j, &ops[j].operand[0],
3976 j + opcnt * 22, &k, NULL);
3978 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3982 ferr(ops, "missing seh terminator\n");
3986 ret = resolve_origin(i, &ops[i].operand[1],
3987 i + opcnt * 23, &k, NULL);
3989 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3993 eliminate_seh_writes(opcnt);
3996 static void eliminate_seh_calls(int opcnt)
3998 int epilog_found = 0;
4005 ferr_assert(&ops[i], ops[i].op == OP_PUSH
4006 && ops[i].operand[0].type == OPT_CONST);
4007 g_stack_fsz = g_seh_size + ops[i].operand[0].val;
4008 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4011 ferr_assert(&ops[i], ops[i].op == OP_PUSH
4012 && ops[i].operand[0].type == OPT_OFFSET);
4013 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4016 ferr_assert(&ops[i], ops[i].op == OP_CALL
4017 && IS(opr_name(&ops[i], 0), "__SEH_prolog"));
4018 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4020 for (i++; i < opcnt; i++) {
4021 if (ops[i].op != OP_CALL)
4023 if (!IS(opr_name(&ops[i], 0), "__SEH_epilog"))
4026 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4029 ferr_assert(ops, epilog_found);
4031 eliminate_seh_writes(opcnt);
4034 static int scan_prologue(int i, int opcnt, int *ecx_push, int *esp_sub)
4038 for (; i < opcnt; i++)
4039 if (!(ops[i].flags & OPF_DONE))
4042 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4043 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4049 for (; i < opcnt; i++) {
4050 if (i > 0 && g_labels[i] != NULL)
4052 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
4054 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
4055 && ops[i].operand[1].type == OPT_CONST)
4057 g_stack_fsz += opr_const(&ops[i], 1);
4058 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4063 if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
4064 && ops[i].operand[1].type == OPT_CONST)
4066 for (j = i + 1; j < opcnt; j++)
4067 if (!(ops[j].flags & OPF_DONE))
4069 if (ops[j].op == OP_CALL
4070 && IS(opr_name(&ops[j], 0), "__alloca_probe"))
4072 g_stack_fsz += opr_const(&ops[i], 1);
4073 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4074 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4085 static void scan_prologue_epilogue(int opcnt, int *stack_align)
4087 int ecx_push = 0, esp_sub = 0, pusha = 0;
4088 int sandard_epilogue;
4092 if (g_seh_found == 2) {
4093 eliminate_seh_calls(opcnt);
4097 eliminate_seh(opcnt);
4098 // ida treats seh as part of sf
4099 g_stack_fsz = g_seh_size;
4103 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
4104 && ops[1].op == OP_MOV
4105 && IS(opr_name(&ops[1], 0), "ebp")
4106 && IS(opr_name(&ops[1], 1), "esp"))
4109 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4110 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4112 for (i = 2; i < opcnt; i++)
4113 if (!(ops[i].flags & OPF_DONE))
4116 if (ops[i].op == OP_PUSHA) {
4117 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4122 if (ops[i].op == OP_AND && ops[i].operand[0].reg == xSP
4123 && ops[i].operand[1].type == OPT_CONST)
4125 l = ops[i].operand[1].val;
4127 if (j == -1 || (l >> j) != -1)
4128 ferr(&ops[i], "unhandled esp align: %x\n", l);
4129 if (stack_align != NULL)
4130 *stack_align = 1 << j;
4131 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4135 i = scan_prologue(i, opcnt, &ecx_push, &esp_sub);
4139 for (; i < opcnt; i++)
4140 if (ops[i].flags & OPF_TAIL)
4143 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4144 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4150 sandard_epilogue = 0;
4151 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
4153 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4154 // the standard epilogue is sometimes even used without a sf
4155 if (ops[j - 1].op == OP_MOV
4156 && IS(opr_name(&ops[j - 1], 0), "esp")
4157 && IS(opr_name(&ops[j - 1], 1), "ebp"))
4158 sandard_epilogue = 1;
4160 else if (ops[j].op == OP_LEAVE)
4162 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4163 sandard_epilogue = 1;
4165 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
4166 && ops[i].pp->is_noreturn)
4168 // on noreturn, msvc sometimes cleans stack, sometimes not
4173 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4174 ferr(&ops[j], "'pop ebp' expected\n");
4176 if (g_stack_fsz != 0 || sandard_epilogue) {
4177 if (ops[j].op == OP_LEAVE)
4179 else if (sandard_epilogue) // mov esp, ebp
4181 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4184 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4186 ferr(&ops[j], "esp restore expected\n");
4189 if (ecx_push && j >= 0 && ops[j].op == OP_POP
4190 && IS(opr_name(&ops[j], 0), "ecx"))
4192 ferr(&ops[j], "unexpected ecx pop\n");
4197 if (ops[j].op == OP_POPA)
4198 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4200 ferr(&ops[j], "popa expected\n");
4205 } while (i < opcnt);
4208 ferr(ops, "missing ebp epilogue\n");
4213 i = scan_prologue(0, opcnt, &ecx_push, &esp_sub);
4215 if (ecx_push && !esp_sub) {
4216 // could actually be args for a call..
4217 for (; i < opcnt; i++)
4218 if (ops[i].op != OP_PUSH)
4221 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
4222 const struct parsed_proto *pp;
4223 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
4224 j = pp ? pp->argc_stack : 0;
4225 while (i > 0 && j > 0) {
4227 if (ops[i].op == OP_PUSH) {
4228 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
4233 ferr(&ops[i], "unhandled prologue\n");
4237 g_stack_fsz = g_seh_size;
4238 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4239 if (!(ops[i].flags & OPF_RMD))
4249 if (ecx_push || esp_sub)
4254 for (; i < opcnt; i++)
4255 if (ops[i].flags & OPF_TAIL)
4259 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4260 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4265 else if (i < opcnt && (ops[i].flags & OPF_ATAIL)) {
4266 // skip arg updates for arg-reuse tailcall
4267 for (; j >= 0; j--) {
4268 if (ops[j].op != OP_MOV)
4270 if (ops[j].operand[0].type != OPT_REGMEM)
4272 if (strstr(ops[j].operand[0].name, "arg_") == NULL)
4277 if (ecx_push > 0 && !esp_sub) {
4278 for (l = 0; l < ecx_push && j >= 0; l++) {
4279 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
4281 else if (ops[j].op == OP_ADD
4282 && IS(opr_name(&ops[j], 0), "esp")
4283 && ops[j].operand[1].type == OPT_CONST)
4286 l += ops[j].operand[1].val / 4 - 1;
4291 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4294 if (l != ecx_push) {
4295 if (i < opcnt && ops[i].op == OP_CALL
4296 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4298 // noreturn tailcall with no epilogue
4303 ferr(&ops[j], "epilogue scan failed\n");
4310 if (ops[j].op != OP_ADD
4311 || !IS(opr_name(&ops[j], 0), "esp")
4312 || ops[j].operand[1].type != OPT_CONST)
4314 if (i < opcnt && ops[i].op == OP_CALL
4315 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4317 // noreturn tailcall with no epilogue
4322 ferr(&ops[j], "'add esp' expected\n");
4325 if (ops[j].operand[1].val < g_stack_fsz)
4326 ferr(&ops[j], "esp adj is too low (need %d)\n", g_stack_fsz);
4328 ops[j].operand[1].val -= g_stack_fsz; // for stack arg scanner
4329 if (ops[j].operand[1].val == 0)
4330 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4335 } while (i < opcnt);
4338 ferr(ops, "missing esp epilogue\n");
4342 // find an instruction that changed opr before i op
4343 // *op_i must be set to -1 by the caller
4344 // *is_caller is set to 1 if one source is determined to be g_func arg
4345 // returns 1 if found, *op_i is then set to origin
4346 // returns -1 if multiple origins are found
4347 static int resolve_origin(int i, const struct parsed_opr *opr,
4348 int magic, int *op_i, int *is_caller)
4350 struct label_ref *lr;
4354 if (g_labels[i] != NULL) {
4355 lr = &g_label_refs[i];
4356 for (; lr != NULL; lr = lr->next) {
4357 check_i(&ops[i], lr->i);
4358 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4360 if (i > 0 && LAST_OP(i - 1))
4366 if (is_caller != NULL)
4371 if (ops[i].cc_scratch == magic)
4373 ops[i].cc_scratch = magic;
4375 if (!(ops[i].flags & OPF_DATA))
4377 if (!is_opr_modified(opr, &ops[i]))
4381 if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4392 // find an instruction that previously referenced opr
4393 // if multiple results are found - fail
4394 // *op_i must be set to -1 by the caller
4395 // returns 1 if found, *op_i is then set to referencer insn
4396 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4397 int magic, int *op_i)
4399 struct label_ref *lr;
4403 if (g_labels[i] != NULL) {
4404 lr = &g_label_refs[i];
4405 for (; lr != NULL; lr = lr->next) {
4406 check_i(&ops[i], lr->i);
4407 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4409 if (i > 0 && LAST_OP(i - 1))
4417 if (ops[i].cc_scratch == magic)
4419 ops[i].cc_scratch = magic;
4421 if (!is_opr_referenced(opr, &ops[i]))
4432 // adjust datap of all reachable 'op' insns when moving back
4433 // returns 1 if at least 1 op was found
4434 // returns -1 if path without an op was found
4435 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4437 struct label_ref *lr;
4440 if (ops[i].cc_scratch == magic)
4442 ops[i].cc_scratch = magic;
4445 if (g_labels[i] != NULL) {
4446 lr = &g_label_refs[i];
4447 for (; lr != NULL; lr = lr->next) {
4448 check_i(&ops[i], lr->i);
4449 ret |= adjust_prev_op(lr->i, op, magic, datap);
4451 if (i > 0 && LAST_OP(i - 1))
4459 if (ops[i].cc_scratch == magic)
4461 ops[i].cc_scratch = magic;
4463 if (ops[i].op != op)
4466 ops[i].datap = datap;
4471 // find next instruction that reads opr
4472 // *op_i must be set to -1 by the caller
4473 // on return, *op_i is set to first referencer insn
4474 // returns 1 if exactly 1 referencer is found
4475 static int find_next_read(int i, int opcnt,
4476 const struct parsed_opr *opr, int magic, int *op_i)
4478 struct parsed_op *po;
4481 for (; i < opcnt; i++)
4483 if (ops[i].cc_scratch == magic)
4485 ops[i].cc_scratch = magic;
4488 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4489 if (po->btj != NULL) {
4491 for (j = 0; j < po->btj->count; j++) {
4492 check_i(po, po->btj->d[j].bt_i);
4493 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4499 if (po->flags & OPF_RMD)
4501 check_i(po, po->bt_i);
4502 if (po->flags & OPF_CJMP) {
4503 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4512 if (!is_opr_read(opr, po)) {
4514 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4515 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4517 full_opr = po->operand[0].lmod >= opr->lmod;
4519 if (is_opr_modified(opr, po) && full_opr) {
4523 if (po->flags & OPF_TAIL)
4538 // find next instruction that reads opr
4539 // *op_i must be set to -1 by the caller
4540 // on return, *op_i is set to first flag user insn
4541 // returns 1 if exactly 1 flag user is found
4542 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4544 struct parsed_op *po;
4547 for (; i < opcnt; i++)
4549 if (ops[i].cc_scratch == magic)
4551 ops[i].cc_scratch = magic;
4554 if (po->op == OP_CALL)
4556 if (po->flags & OPF_JMP) {
4557 if (po->btj != NULL) {
4559 for (j = 0; j < po->btj->count; j++) {
4560 check_i(po, po->btj->d[j].bt_i);
4561 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4567 if (po->flags & OPF_RMD)
4569 check_i(po, po->bt_i);
4570 if (po->flags & OPF_CJMP)
4577 if (!(po->flags & OPF_CC)) {
4578 if (po->flags & OPF_FLAGS)
4581 if (po->flags & OPF_TAIL)
4597 static int try_resolve_const(int i, const struct parsed_opr *opr,
4598 int magic, unsigned int *val)
4603 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4606 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4609 *val = ops[i].operand[1].val;
4616 static int resolve_used_bits(int i, int opcnt, int reg,
4617 int *mask, int *is_z_check)
4619 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4623 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4627 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4629 fnote(&ops[j], "(first read)\n");
4630 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4633 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4634 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4636 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4637 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4639 *mask = ops[j].operand[1].val;
4640 if (ops[j].operand[0].lmod == OPLM_BYTE
4641 && ops[j].operand[0].name[1] == 'h')
4645 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4648 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4650 *is_z_check = ops[k].pfo == PFO_Z;
4655 static const struct parsed_proto *resolve_deref(int i, int magic,
4656 struct parsed_opr *opr, int level)
4658 struct parsed_opr opr_s = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
4659 const struct parsed_proto *pp = NULL;
4660 int from_caller = 0;
4669 ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4670 if (ret != 2 || len != strlen(opr->name)) {
4671 ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4672 if (ret != 1 || len != strlen(opr->name))
4676 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4681 ret = resolve_origin(i, &opr_s, i + magic, &j, NULL);
4685 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4686 && strlen(ops[j].operand[1].name) == 3
4687 && ops[j].operand[0].lmod == OPLM_DWORD
4688 && ops[j].pp == NULL // no hint
4691 // allow one simple dereference (com/directx)
4692 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4693 ops[j].operand[1].name);
4697 ret = resolve_origin(j, &opr_s, j + magic, &k, NULL);
4702 if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
4705 if (ops[j].pp != NULL) {
4709 else if (ops[j].operand[1].type == OPT_REGMEM) {
4710 pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
4712 // maybe structure ptr in structure
4713 pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
4716 else if (ops[j].operand[1].type == OPT_LABEL)
4717 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4718 else if (ops[j].operand[1].type == OPT_REG) {
4721 ret = resolve_origin(j, &ops[j].operand[1], i + magic,
4723 if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
4724 for (k = 0; k < g_func_pp->argc; k++) {
4725 if (g_func_pp->arg[k].reg == NULL)
4727 if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
4728 pp = g_func_pp->arg[k].pp;
4737 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4739 ferr(&ops[j], "expected struct, got '%s %s'\n",
4740 pp->type.name, pp->name);
4744 return proto_lookup_struct(g_fhdr, pp->type.name, offset);
4747 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4748 int *pp_i, int *multi_src)
4750 const struct parsed_proto *pp = NULL;
4751 int search_advice = 0;
4756 switch (ops[i].operand[0].type) {
4758 // try to resolve struct member calls
4759 pp = resolve_deref(i, i + opcnt * 19, &ops[i].operand[0], 0);
4765 pp = try_recover_pp(&ops[i], &ops[i].operand[0],
4771 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4779 static struct parsed_proto *process_call_early(int i, int opcnt,
4782 struct parsed_op *po = &ops[i];
4783 struct parsed_proto *pp;
4789 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4793 // look for and make use of esp adjust
4795 if (!pp->is_stdcall && pp->argc_stack > 0)
4796 ret = scan_for_esp_adjust(i + 1, opcnt,
4797 pp->argc_stack * 4, &adj, &multipath, 0);
4799 if (pp->argc_stack > adj / 4)
4803 if (ops[ret].op == OP_POP) {
4804 for (j = 1; j < adj / 4; j++) {
4805 if (ops[ret + j].op != OP_POP
4806 || ops[ret + j].operand[0].reg != xCX)
4818 static struct parsed_proto *process_call(int i, int opcnt)
4820 struct parsed_op *po = &ops[i];
4821 const struct parsed_proto *pp_c;
4822 struct parsed_proto *pp;
4823 const char *tmpname;
4824 int call_i = -1, ref_i = -1;
4825 int adj = 0, multipath = 0;
4828 tmpname = opr_name(po, 0);
4833 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4835 if (!pp_c->is_func && !pp_c->is_fptr)
4836 ferr(po, "call to non-func: %s\n", pp_c->name);
4837 pp = proto_clone(pp_c);
4838 my_assert_not(pp, NULL);
4840 // not resolved just to single func
4843 switch (po->operand[0].type) {
4845 // we resolved this call and no longer need the register
4846 po->regmask_src &= ~(1 << po->operand[0].reg);
4848 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4849 && ops[call_i].operand[1].type == OPT_LABEL)
4851 // no other source users?
4852 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4854 if (ret == 1 && call_i == ref_i) {
4855 // and nothing uses it after us?
4857 find_next_read(i + 1, opcnt, &po->operand[0],
4858 i + opcnt * 11, &ref_i);
4860 // then also don't need the source mov
4861 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4873 pp = calloc(1, sizeof(*pp));
4874 my_assert_not(pp, NULL);
4877 ret = scan_for_esp_adjust(i + 1, opcnt,
4878 -1, &adj, &multipath, 0);
4879 if (ret < 0 || adj < 0) {
4880 if (!g_allow_regfunc)
4881 ferr(po, "non-__cdecl indirect call unhandled yet\n");
4882 pp->is_unresolved = 1;
4886 if (adj > ARRAY_SIZE(pp->arg))
4887 ferr(po, "esp adjust too large: %d\n", adj);
4888 pp->ret_type.name = strdup("int");
4889 pp->argc = pp->argc_stack = adj;
4890 for (arg = 0; arg < pp->argc; arg++)
4891 pp->arg[arg].type.name = strdup("int");
4896 // look for and make use of esp adjust
4899 if (!pp->is_stdcall && pp->argc_stack > 0) {
4900 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
4901 ret = scan_for_esp_adjust(i + 1, opcnt,
4902 adj_expect, &adj, &multipath, 0);
4905 if (pp->is_vararg) {
4906 if (adj / 4 < pp->argc_stack) {
4907 fnote(po, "(this call)\n");
4908 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
4909 adj, pp->argc_stack * 4);
4911 // modify pp to make it have varargs as normal args
4913 pp->argc += adj / 4 - pp->argc_stack;
4914 for (; arg < pp->argc; arg++) {
4915 pp->arg[arg].type.name = strdup("int");
4918 if (pp->argc > ARRAY_SIZE(pp->arg))
4919 ferr(po, "too many args for '%s'\n", tmpname);
4921 if (pp->argc_stack > adj / 4) {
4922 if (pp->is_noreturn)
4923 // assume no stack adjust was emited
4925 fnote(po, "(this call)\n");
4926 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
4927 tmpname, pp->argc_stack * 4, adj);
4930 scan_for_esp_adjust(i + 1, opcnt,
4931 pp->argc_stack * 4, &adj, &multipath, 1);
4933 else if (pp->is_vararg)
4934 ferr(po, "missing esp_adjust for vararg func '%s'\n",
4941 static void mark_float_arg(struct parsed_op *po,
4942 struct parsed_proto *pp, int arg, int *regmask_ffca)
4945 po->p_argnum = arg + 1;
4946 ferr_assert(po, pp->arg[arg].datap == NULL);
4947 pp->arg[arg].datap = po;
4948 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
4949 if (regmask_ffca != NULL)
4950 *regmask_ffca |= 1 << arg;
4953 static int check_for_stp(int i, int i_to)
4955 struct parsed_op *po;
4957 for (; i < i_to; i++) {
4959 if (po->op == OP_FST)
4961 if (g_labels[i] != NULL || (po->flags & OPF_JMP))
4963 if (po->op == OP_CALL || po->op == OP_PUSH || po->op == OP_POP)
4965 if (po->op == OP_ADD && po->operand[0].reg == xSP)
4972 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
4975 struct parsed_op *po;
4981 for (base_arg = 0; base_arg < pp->argc; base_arg++)
4982 if (pp->arg[base_arg].reg == NULL)
4985 for (j = i; j > 0; )
4987 ferr_assert(&ops[j], g_labels[j] == NULL);
4991 ferr_assert(po, po->op != OP_PUSH);
4992 if (po->op == OP_FST)
4994 if (po->operand[0].type != OPT_REGMEM)
4996 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
4999 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3)) {
5000 //ferr(po, "offset %d, %d args\n", offset, pp->argc_stack);
5004 arg = base_arg + offset / 4;
5005 mark_float_arg(po, pp, arg, regmask_ffca);
5007 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5008 && po->operand[1].type == OPT_CONST)
5010 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5015 for (arg = base_arg; arg < pp->argc; arg++) {
5016 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
5017 po = pp->arg[arg].datap;
5019 ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
5020 if (po->operand[0].lmod == OPLM_QWORD)
5027 static int collect_call_args_early(int i, struct parsed_proto *pp,
5028 int *regmask, int *regmask_ffca)
5030 struct parsed_op *po;
5035 for (arg = 0; arg < pp->argc; arg++)
5036 if (pp->arg[arg].reg == NULL)
5039 // first see if it can be easily done
5040 for (j = i; j > 0 && arg < pp->argc; )
5042 if (g_labels[j] != NULL)
5047 if (po->op == OP_CALL)
5049 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
5051 else if (po->op == OP_POP)
5053 else if (po->flags & OPF_CJMP)
5055 else if (po->op == OP_PUSH) {
5056 if (po->flags & (OPF_FARG|OPF_FARGNR))
5058 if (!g_header_mode) {
5059 ret = scan_for_mod(po, j + 1, i, 1);
5064 if (pp->arg[arg].type.is_va_list)
5068 for (arg++; arg < pp->argc; arg++)
5069 if (pp->arg[arg].reg == NULL)
5072 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5073 && po->operand[1].type == OPT_CONST)
5075 if (po->flags & (OPF_RMD|OPF_DONE))
5077 if (po->operand[1].val != pp->argc_stack * 4)
5078 ferr(po, "unexpected esp adjust: %d\n",
5079 po->operand[1].val * 4);
5080 ferr_assert(po, pp->argc - arg == pp->argc_stack);
5081 return collect_call_args_no_push(i, pp, regmask_ffca);
5089 for (arg = 0; arg < pp->argc; arg++)
5090 if (pp->arg[arg].reg == NULL)
5093 for (j = i; j > 0 && arg < pp->argc; )
5097 if (ops[j].op == OP_PUSH)
5099 ops[j].p_argnext = -1;
5100 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
5102 k = check_for_stp(j + 1, i);
5104 // push ecx; fstp dword ptr [esp]
5105 ret = parse_stack_esp_offset(&ops[k],
5106 ops[k].operand[0].name, &offset);
5107 if (ret == 0 && offset == 0) {
5108 if (!pp->arg[arg].type.is_float)
5109 ferr(&ops[i], "arg %d should be float\n", arg + 1);
5110 mark_float_arg(&ops[k], pp, arg, regmask_ffca);
5114 if (pp->arg[arg].datap == NULL) {
5115 pp->arg[arg].datap = &ops[j];
5116 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
5117 *regmask |= 1 << ops[j].operand[0].reg;
5120 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5121 ops[j].flags &= ~OPF_RSAVE;
5124 for (arg++; arg < pp->argc; arg++)
5125 if (pp->arg[arg].reg == NULL)
5133 static int sync_argnum(struct parsed_op *po, int argnum)
5135 struct parsed_op *po_tmp;
5137 // see if other branches don't have higher argnum
5138 for (po_tmp = po; po_tmp != NULL; ) {
5139 if (argnum < po_tmp->p_argnum)
5140 argnum = po_tmp->p_argnum;
5141 // note: p_argnext is active on current collect_call_args only
5142 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5145 // make all argnums consistent
5146 for (po_tmp = po; po_tmp != NULL; ) {
5147 if (po_tmp->p_argnum != 0)
5148 po_tmp->p_argnum = argnum;
5149 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5155 static int collect_call_args_r(struct parsed_op *po, int i,
5156 struct parsed_proto *pp, int *regmask, int *arg_grp,
5157 int arg, int argnum, int magic, int need_op_saving, int may_reuse)
5159 struct parsed_proto *pp_tmp;
5160 struct parsed_op *po_tmp;
5161 struct label_ref *lr;
5162 int need_to_save_current;
5163 int arg_grp_current = 0;
5164 int save_args_seen = 0;
5171 ferr(po, "dead label encountered\n");
5175 for (; arg < pp->argc; arg++, argnum++)
5176 if (pp->arg[arg].reg == NULL)
5178 magic = (magic & 0xffffff) | (arg << 24);
5180 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
5182 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
5183 if (ops[j].cc_scratch != magic) {
5184 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
5188 // ok: have already been here
5191 ops[j].cc_scratch = magic;
5193 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
5194 lr = &g_label_refs[j];
5195 if (lr->next != NULL)
5197 for (; lr->next; lr = lr->next) {
5198 check_i(&ops[j], lr->i);
5199 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5201 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5202 arg, argnum, magic, need_op_saving, may_reuse);
5207 check_i(&ops[j], lr->i);
5208 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5210 if (j > 0 && LAST_OP(j - 1)) {
5211 // follow last branch in reverse
5216 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5217 arg, argnum, magic, need_op_saving, may_reuse);
5223 if (ops[j].op == OP_CALL)
5225 if (pp->is_unresolved)
5230 ferr(po, "arg collect %d/%d hit unparsed call '%s'\n",
5231 arg, pp->argc, ops[j].operand[0].name);
5232 if (may_reuse && pp_tmp->argc_stack > 0)
5233 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
5234 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
5236 // esp adjust of 0 means we collected it before
5237 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
5238 && (ops[j].operand[1].type != OPT_CONST
5239 || ops[j].operand[1].val != 0))
5241 if (pp->is_unresolved)
5244 fnote(po, "(this call)\n");
5245 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
5246 arg, pp->argc, ops[j].operand[1].val);
5248 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
5250 if (pp->is_unresolved)
5253 fnote(po, "(this call)\n");
5254 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
5256 else if (ops[j].flags & OPF_CJMP)
5258 if (pp->is_unresolved)
5263 else if (ops[j].op == OP_PUSH
5264 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
5266 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
5269 ops[j].p_argnext = -1;
5270 po_tmp = pp->arg[arg].datap;
5272 ops[j].p_argnext = po_tmp - ops;
5273 pp->arg[arg].datap = &ops[j];
5275 argnum = sync_argnum(&ops[j], argnum);
5277 need_to_save_current = 0;
5279 if (ops[j].operand[0].type == OPT_REG)
5280 reg = ops[j].operand[0].reg;
5282 if (!need_op_saving) {
5283 ret = scan_for_mod(&ops[j], j + 1, i, 1);
5284 need_to_save_current = (ret >= 0);
5286 if (need_op_saving || need_to_save_current) {
5287 // mark this arg as one that needs operand saving
5288 pp->arg[arg].is_saved = 1;
5290 if (save_args_seen & (1 << (argnum - 1))) {
5293 if (arg_grp_current >= MAX_ARG_GRP)
5294 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
5298 else if (ops[j].p_argnum == 0)
5299 ops[j].flags |= OPF_RMD;
5301 // some PUSHes are reused by different calls on other branches,
5302 // but that can't happen if we didn't branch, so they
5303 // can be removed from future searches (handles nested calls)
5305 ops[j].flags |= OPF_FARGNR;
5307 ops[j].flags |= OPF_FARG;
5308 ops[j].flags &= ~OPF_RSAVE;
5310 // check for __VALIST
5311 if (!pp->is_unresolved && g_func_pp != NULL
5312 && pp->arg[arg].type.is_va_list)
5315 ret = resolve_origin(j, &ops[j].operand[0],
5316 magic + 1, &k, NULL);
5317 if (ret == 1 && k >= 0)
5319 if (ops[k].op == OP_LEA) {
5320 if (!g_func_pp->is_vararg)
5321 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
5324 snprintf(buf, sizeof(buf), "arg_%X",
5325 g_func_pp->argc_stack * 4);
5326 if (strstr(ops[k].operand[1].name, buf)
5327 || strstr(ops[k].operand[1].name, "arglist"))
5329 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
5330 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
5331 pp->arg[arg].is_saved = 0;
5335 ferr(&ops[k], "va_list arg detection failed\n");
5337 // check for va_list from g_func_pp arg too
5338 else if (ops[k].op == OP_MOV
5339 && is_stack_access(&ops[k], &ops[k].operand[1]))
5341 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5342 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5344 ops[k].flags |= OPF_RMD | OPF_DONE;
5345 ops[j].flags |= OPF_RMD;
5346 ops[j].p_argpass = ret + 1;
5347 pp->arg[arg].is_saved = 0;
5354 if (pp->arg[arg].is_saved) {
5355 ops[j].flags &= ~OPF_RMD;
5356 ops[j].p_argnum = argnum;
5359 // tracking reg usage
5361 *regmask |= 1 << reg;
5365 if (!pp->is_unresolved) {
5367 for (; arg < pp->argc; arg++, argnum++)
5368 if (pp->arg[arg].reg == NULL)
5371 magic = (magic & 0xffffff) | (arg << 24);
5374 if (ops[j].p_arggrp > arg_grp_current) {
5376 arg_grp_current = ops[j].p_arggrp;
5378 if (ops[j].p_argnum > 0)
5379 save_args_seen |= 1 << (ops[j].p_argnum - 1);
5382 if (arg < pp->argc) {
5383 ferr(po, "arg collect failed for '%s': %d/%d\n",
5384 pp->name, arg, pp->argc);
5388 if (arg_grp_current > *arg_grp)
5389 *arg_grp = arg_grp_current;
5394 static int collect_call_args(struct parsed_op *po, int i,
5395 struct parsed_proto *pp, int *regmask, int magic)
5397 // arg group is for cases when pushes for
5398 // multiple funcs are going on
5399 struct parsed_op *po_tmp;
5404 ret = collect_call_args_r(po, i, pp, regmask, &arg_grp,
5410 // propagate arg_grp
5411 for (a = 0; a < pp->argc; a++) {
5412 if (pp->arg[a].reg != NULL)
5415 po_tmp = pp->arg[a].datap;
5416 while (po_tmp != NULL) {
5417 po_tmp->p_arggrp = arg_grp;
5418 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5423 if (pp->is_unresolved) {
5425 pp->argc_stack += ret;
5426 for (a = 0; a < pp->argc; a++)
5427 if (pp->arg[a].type.name == NULL)
5428 pp->arg[a].type.name = strdup("int");
5434 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5435 int regmask_now, int *regmask,
5436 int regmask_save_now, int *regmask_save,
5437 int *regmask_init, int regmask_arg)
5439 struct parsed_op *po;
5447 for (; i < opcnt; i++)
5450 if (cbits[i >> 3] & (1 << (i & 7)))
5452 cbits[i >> 3] |= (1 << (i & 7));
5454 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5455 if (po->flags & (OPF_RMD|OPF_DONE))
5457 if (po->btj != NULL) {
5458 for (j = 0; j < po->btj->count; j++) {
5459 check_i(po, po->btj->d[j].bt_i);
5460 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5461 regmask_now, regmask, regmask_save_now, regmask_save,
5462 regmask_init, regmask_arg);
5467 check_i(po, po->bt_i);
5468 if (po->flags & OPF_CJMP)
5469 reg_use_pass(po->bt_i, opcnt, cbits,
5470 regmask_now, regmask, regmask_save_now, regmask_save,
5471 regmask_init, regmask_arg);
5477 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5478 && !g_func_pp->is_userstack
5479 && po->operand[0].type == OPT_REG)
5481 reg = po->operand[0].reg;
5482 ferr_assert(po, reg >= 0);
5485 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5486 if (regmask_now & (1 << reg)) {
5487 already_saved = regmask_save_now & (1 << reg);
5488 flags_set = OPF_RSAVE | OPF_DONE;
5491 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, 0);
5493 scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5494 reg, 0, 0, flags_set);
5497 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5499 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5504 ferr_assert(po, !already_saved);
5505 po->flags |= flags_set;
5507 if (regmask_now & (1 << reg)) {
5508 regmask_save_now |= (1 << reg);
5509 *regmask_save |= regmask_save_now;
5514 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5515 reg = po->operand[0].reg;
5516 ferr_assert(po, reg >= 0);
5518 if (regmask_save_now & (1 << reg))
5519 regmask_save_now &= ~(1 << reg);
5521 regmask_now &= ~(1 << reg);
5524 else if (po->op == OP_CALL) {
5525 if ((po->regmask_dst & (1 << xAX))
5526 && !(po->regmask_dst & (1 << xDX)))
5528 if (po->flags & OPF_TAIL)
5529 // don't need eax, will do "return f();" or "f(); return;"
5530 po->regmask_dst &= ~(1 << xAX);
5532 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
5534 find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
5537 po->regmask_dst &= ~(1 << xAX);
5541 // not "full stack" mode and have something in stack
5542 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5543 ferr(po, "float stack is not empty on func call\n");
5546 if (po->flags & OPF_NOREGS)
5549 // if incomplete register is used, clear it on init to avoid
5550 // later use of uninitialized upper part in some situations
5551 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5552 && po->operand[0].lmod != OPLM_DWORD)
5554 reg = po->operand[0].reg;
5555 ferr_assert(po, reg >= 0);
5557 if (!(regmask_now & (1 << reg)))
5558 *regmask_init |= 1 << reg;
5561 regmask_op = po->regmask_src | po->regmask_dst;
5563 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5564 regmask_new &= ~(1 << xSP);
5565 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5566 regmask_new &= ~(1 << xBP);
5568 if (regmask_new != 0)
5569 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5571 if (regmask_op & (1 << xBP)) {
5572 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5573 if (po->regmask_dst & (1 << xBP))
5574 // compiler decided to drop bp frame and use ebp as scratch
5575 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5577 regmask_op &= ~(1 << xBP);
5581 if (po->flags & OPF_FPUSH) {
5582 if (regmask_now & mxST1)
5583 regmask_now |= mxSTa; // switch to "full stack" mode
5584 if (regmask_now & mxSTa)
5585 po->flags |= OPF_FSHIFT;
5586 if (!(regmask_now & mxST7_2)) {
5588 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5592 regmask_now |= regmask_op;
5593 *regmask |= regmask_now;
5596 if (po->flags & OPF_FPOPP) {
5597 if ((regmask_now & mxSTa) == 0)
5598 ferr(po, "float pop on empty stack?\n");
5599 if (regmask_now & mxST7_2)
5600 po->flags |= OPF_FSHIFT;
5601 if (!(regmask_now & mxST7_2))
5602 regmask_now &= ~mxST1_0;
5604 else if (po->flags & OPF_FPOP) {
5605 if ((regmask_now & mxSTa) == 0)
5606 ferr(po, "float pop on empty stack?\n");
5607 if (regmask_now & (mxST7_2 | mxST1))
5608 po->flags |= OPF_FSHIFT;
5609 if (!(regmask_now & mxST7_2)) {
5611 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5615 if (po->flags & OPF_TAIL) {
5616 if (!(regmask_now & mxST7_2)) {
5617 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5618 if (!(regmask_now & mxST0))
5619 ferr(po, "no st0 on float return, mask: %x\n",
5622 else if (regmask_now & mxST1_0)
5623 ferr(po, "float regs on tail: %x\n", regmask_now);
5626 // there is support for "conditional tailcall", sort of
5627 if (!(po->flags & OPF_CC))
5633 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5637 for (i = 0; i < pp->argc; i++)
5638 if (pp->arg[i].reg == NULL)
5642 memmove(&pp->arg[i + 1], &pp->arg[i],
5643 sizeof(pp->arg[0]) * pp->argc_stack);
5644 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5645 pp->arg[i].reg = strdup(reg);
5646 pp->arg[i].type.name = strdup("int");
5651 static void output_std_flag_z(FILE *fout, struct parsed_op *po,
5652 int *pfomask, const char *dst_opr_text)
5654 if (*pfomask & (1 << PFO_Z)) {
5655 fprintf(fout, "\n cond_z = (%s%s == 0);",
5656 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5657 *pfomask &= ~(1 << PFO_Z);
5661 static void output_std_flag_s(FILE *fout, struct parsed_op *po,
5662 int *pfomask, const char *dst_opr_text)
5664 if (*pfomask & (1 << PFO_S)) {
5665 fprintf(fout, "\n cond_s = (%s%s < 0);",
5666 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5667 *pfomask &= ~(1 << PFO_S);
5671 static void output_std_flags(FILE *fout, struct parsed_op *po,
5672 int *pfomask, const char *dst_opr_text)
5674 output_std_flag_z(fout, po, pfomask, dst_opr_text);
5675 output_std_flag_s(fout, po, pfomask, dst_opr_text);
5679 OPP_FORCE_NORETURN = (1 << 0),
5680 OPP_SIMPLE_ARGS = (1 << 1),
5681 OPP_ALIGN = (1 << 2),
5684 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
5687 const char *cconv = "";
5689 if (pp->is_fastcall)
5690 cconv = "__fastcall ";
5691 else if (pp->is_stdcall && pp->argc_reg == 0)
5692 cconv = "__stdcall ";
5694 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5696 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
5697 fprintf(fout, "noreturn ");
5700 static void output_pp(FILE *fout, const struct parsed_proto *pp,
5705 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5709 output_pp_attrs(fout, pp, flags);
5712 fprintf(fout, "%s", pp->name);
5717 for (i = 0; i < pp->argc; i++) {
5719 fprintf(fout, ", ");
5720 if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
5721 && !(flags & OPP_SIMPLE_ARGS))
5724 output_pp(fout, pp->arg[i].pp, 0);
5726 else if (pp->arg[i].type.is_retreg) {
5727 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
5730 fprintf(fout, "%s", pp->arg[i].type.name);
5732 fprintf(fout, " a%d", i + 1);
5735 if (pp->arg[i].type.is_64bit)
5738 if (pp->is_vararg) {
5740 fprintf(fout, ", ");
5741 fprintf(fout, "...");
5746 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
5752 snprintf(buf1, sizeof(buf1), "%d", grp);
5753 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
5758 static void gen_x_cleanup(int opcnt);
5760 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
5762 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
5763 struct parsed_opr *last_arith_dst = NULL;
5764 char buf1[256], buf2[256], buf3[256], cast[64];
5765 struct parsed_proto *pp, *pp_tmp;
5766 struct parsed_data *pd;
5767 int save_arg_vars[MAX_ARG_GRP] = { 0, };
5768 unsigned char cbits[MAX_OPS / 8];
5769 const char *float_type;
5770 const char *float_st0;
5771 const char *float_st1;
5772 int need_float_stack = 0;
5773 int need_float_sw = 0; // status word
5774 int need_tmp_var = 0;
5778 int label_pending = 0;
5779 int need_double = 0;
5780 int stack_align = 0;
5781 int stack_fsz_adj = 0;
5782 int regmask_save = 0; // used regs saved/restored in this func
5783 int regmask_arg; // regs from this function args (fastcall, etc)
5784 int regmask_ret; // regs needed on ret
5785 int regmask_now; // temp
5786 int regmask_init = 0; // regs that need zero initialization
5787 int regmask_pp = 0; // regs used in complex push-pop graph
5788 int regmask_ffca = 0; // float function call args
5789 int regmask = 0; // used regs
5799 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
5800 g_stack_frame_used = 0;
5802 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
5803 regmask_init = g_regmask_init;
5805 g_func_pp = proto_parse(fhdr, funcn, 0);
5806 if (g_func_pp == NULL)
5807 ferr(ops, "proto_parse failed for '%s'\n", funcn);
5809 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
5810 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
5813 // - resolve all branches
5814 // - parse calls with labels
5815 resolve_branches_parse_calls(opcnt);
5818 // - handle ebp/esp frame, remove ops related to it
5819 scan_prologue_epilogue(opcnt, &stack_align);
5821 // handle a case where sf size is unalignment, but is
5822 // placed in a way that elements are still aligned
5823 if (g_stack_fsz & 4) {
5824 for (i = 0; i < g_eqcnt; i++) {
5825 if (g_eqs[i].lmod != OPLM_QWORD)
5827 if (!(g_eqs[i].offset & 4)) {
5836 // - remove dead labels
5837 // - set regs needed at ret
5838 for (i = 0; i < opcnt; i++)
5840 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
5845 if (ops[i].op == OP_RET)
5846 ops[i].regmask_src |= regmask_ret;
5850 // - process trivial calls
5851 for (i = 0; i < opcnt; i++)
5854 if (po->flags & (OPF_RMD|OPF_DONE))
5857 if (po->op == OP_CALL)
5859 pp = process_call_early(i, opcnt, &j);
5861 if (!(po->flags & OPF_ATAIL)) {
5862 // since we know the args, try to collect them
5863 ret = collect_call_args_early(i, pp, ®mask, ®mask_ffca);
5871 // commit esp adjust
5872 if (ops[j].op != OP_POP)
5873 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5875 for (l = 0; l < pp->argc_stack; l++)
5876 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
5880 if (strstr(pp->ret_type.name, "int64"))
5883 po->flags |= OPF_DONE;
5889 // - process calls, stage 2
5890 // - handle some push/pop pairs
5891 // - scan for STD/CLD, propagate DF
5892 // - try to resolve needed x87 status word bits
5893 for (i = 0; i < opcnt; i++)
5898 if (po->flags & OPF_RMD)
5901 if (po->op == OP_CALL)
5903 if (!(po->flags & OPF_DONE)) {
5904 pp = process_call(i, opcnt);
5906 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
5907 // since we know the args, collect them
5908 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
5910 // for unresolved, collect after other passes
5914 ferr_assert(po, pp != NULL);
5916 po->regmask_src |= get_pp_arg_regmask_src(pp);
5917 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
5919 if (po->regmask_dst & mxST0)
5920 po->flags |= OPF_FPUSH;
5922 if (strstr(pp->ret_type.name, "int64"))
5928 if (po->flags & OPF_DONE)
5933 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
5934 && po->operand[0].type == OPT_CONST)
5936 scan_for_pop_const(i, opcnt, i + opcnt * 12);
5941 scan_pushes_for_pop(i, opcnt, ®mask_pp);
5945 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
5946 scan_propagate_df(i + 1, opcnt);
5951 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
5952 ferr(po, "TODO: fnstsw to mem\n");
5953 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
5955 ferr(po, "fnstsw resolve failed\n");
5956 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
5957 (void *)(long)(mask | (z_check << 16)));
5959 ferr(po, "failed to find fcom: %d\n", ret);
5968 // - find POPs for PUSHes, rm both
5969 // - scan for all used registers
5970 memset(cbits, 0, sizeof(cbits));
5971 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
5972 0, ®mask_save, ®mask_init, regmask_arg);
5974 need_float_stack = !!(regmask & mxST7_2);
5977 // - find flag set ops for their users
5978 // - do unresolved calls
5979 // - declare indirect functions
5980 // - other op specific processing
5981 for (i = 0; i < opcnt; i++)
5984 if (po->flags & (OPF_RMD|OPF_DONE))
5987 if (po->flags & OPF_CC)
5989 int setters[16], cnt = 0, branched = 0;
5991 ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
5992 &branched, setters, &cnt);
5993 if (ret < 0 || cnt <= 0)
5994 ferr(po, "unable to trace flag setter(s)\n");
5995 if (cnt > ARRAY_SIZE(setters))
5996 ferr(po, "too many flag setters\n");
5998 for (j = 0; j < cnt; j++)
6000 tmp_op = &ops[setters[j]]; // flag setter
6003 // to get nicer code, we try to delay test and cmp;
6004 // if we can't because of operand modification, or if we
6005 // have arith op, or branch, make it calculate flags explicitly
6006 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
6008 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
6009 pfomask = 1 << po->pfo;
6011 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
6012 pfomask = 1 << po->pfo;
6015 // see if we'll be able to handle based on op result
6016 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
6017 && po->pfo != PFO_Z && po->pfo != PFO_S
6018 && po->pfo != PFO_P)
6020 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
6022 pfomask = 1 << po->pfo;
6025 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
6026 propagate_lmod(tmp_op, &tmp_op->operand[0],
6027 &tmp_op->operand[1]);
6028 if (tmp_op->operand[0].lmod == OPLM_DWORD)
6033 tmp_op->pfomask |= pfomask;
6034 cond_vars |= pfomask;
6036 // note: may overwrite, currently not a problem
6040 if (po->op == OP_RCL || po->op == OP_RCR
6041 || po->op == OP_ADC || po->op == OP_SBB)
6042 cond_vars |= 1 << PFO_C;
6048 cond_vars |= 1 << PFO_Z;
6052 if (po->operand[0].lmod == OPLM_DWORD)
6057 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
6062 // note: resolved non-reg calls are OPF_DONE already
6064 ferr_assert(po, pp != NULL);
6066 if (pp->is_unresolved) {
6067 int regmask_stack = 0;
6068 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
6070 // this is pretty rough guess:
6071 // see ecx and edx were pushed (and not their saved versions)
6072 for (arg = 0; arg < pp->argc; arg++) {
6073 if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
6076 tmp_op = pp->arg[arg].datap;
6078 ferr(po, "parsed_op missing for arg%d\n", arg);
6079 if (tmp_op->operand[0].type == OPT_REG)
6080 regmask_stack |= 1 << tmp_op->operand[0].reg;
6083 if (!((regmask_stack & (1 << xCX))
6084 && (regmask_stack & (1 << xDX))))
6086 if (pp->argc_stack != 0
6087 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
6089 pp_insert_reg_arg(pp, "ecx");
6090 pp->is_fastcall = 1;
6091 regmask_init |= 1 << xCX;
6092 regmask |= 1 << xCX;
6094 if (pp->argc_stack != 0
6095 || ((regmask | regmask_arg) & (1 << xDX)))
6097 pp_insert_reg_arg(pp, "edx");
6098 regmask_init |= 1 << xDX;
6099 regmask |= 1 << xDX;
6103 // note: __cdecl doesn't fall into is_unresolved category
6104 if (pp->argc_stack > 0)
6110 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
6112 // <var> = offset <something>
6113 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
6114 && !IS_START(po->operand[1].name, "off_"))
6116 if (!po->operand[0].pp->is_fptr)
6117 ferr(po, "%s not declared as fptr when it should be\n",
6118 po->operand[0].name);
6119 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
6120 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
6121 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
6122 fnote(po, "var: %s\n", buf1);
6123 fnote(po, "func: %s\n", buf2);
6124 ferr(po, "^ mismatch\n");
6132 if (po->operand[0].lmod == OPLM_DWORD) {
6133 // 32bit division is common, look for it
6134 if (po->op == OP_DIV)
6135 ret = scan_for_reg_clear(i, xDX);
6137 ret = scan_for_cdq_edx(i);
6139 po->flags |= OPF_32BIT;
6148 po->flags |= OPF_RMD | OPF_DONE;
6158 if (po->operand[0].lmod == OPLM_QWORD)
6168 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
6170 find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
6172 po->flags |= OPF_32BIT;
6180 // this might need it's own pass...
6181 if (po->op != OP_FST && po->p_argnum > 0)
6182 save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
6184 // correct for "full stack" mode late enable
6185 if ((po->flags & (OPF_PPUSH|OPF_FPOP|OPF_FPOPP))
6186 && need_float_stack)
6187 po->flags |= OPF_FSHIFT;
6190 float_type = need_double ? "double" : "float";
6191 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
6192 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
6194 // output starts here
6197 fprintf(fout, "// had SEH\n");
6199 // define userstack size
6200 if (g_func_pp->is_userstack) {
6201 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
6202 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
6203 fprintf(fout, "#endif\n");
6206 // the function itself
6207 ferr_assert(ops, !g_func_pp->is_fptr);
6208 output_pp(fout, g_func_pp,
6209 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
6210 fprintf(fout, "\n{\n");
6212 // declare indirect functions
6213 for (i = 0; i < opcnt; i++) {
6215 if (po->flags & OPF_RMD)
6218 if (po->op == OP_CALL) {
6221 ferr(po, "NULL pp\n");
6223 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
6224 if (pp->name[0] != 0) {
6225 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
6226 memcpy(pp->name, "i_", 2);
6228 // might be declared already
6230 for (j = 0; j < i; j++) {
6231 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
6232 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
6242 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
6245 output_pp(fout, pp, OPP_SIMPLE_ARGS);
6246 fprintf(fout, ";\n");
6251 // output LUTs/jumptables
6252 for (i = 0; i < g_func_pd_cnt; i++) {
6254 fprintf(fout, " static const ");
6255 if (pd->type == OPT_OFFSET) {
6256 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
6258 for (j = 0; j < pd->count; j++) {
6260 fprintf(fout, ", ");
6261 fprintf(fout, "&&%s", pd->d[j].u.label);
6265 fprintf(fout, "%s %s[] =\n { ",
6266 lmod_type_u(ops, pd->lmod), pd->label);
6268 for (j = 0; j < pd->count; j++) {
6270 fprintf(fout, ", ");
6271 fprintf(fout, "%u", pd->d[j].u.val);
6274 fprintf(fout, " };\n");
6278 // declare stack frame, va_arg
6281 fprintf(fout, " // stack_fsz_adj %d\n", stack_fsz_adj);
6283 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
6284 if (g_func_lmods & (1 << OPLM_WORD))
6285 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
6286 if (g_func_lmods & (1 << OPLM_BYTE))
6287 fprintf(fout, " u8 b[%d];", g_stack_fsz);
6288 if (g_func_lmods & (1 << OPLM_QWORD))
6289 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
6291 if (stack_align > 8)
6292 ferr(ops, "unhandled stack align of %d\n", stack_align);
6293 else if (stack_align == 8)
6294 fprintf(fout, " u64 align;");
6295 fprintf(fout, " } sf;\n");
6299 if (g_func_pp->is_userstack) {
6300 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
6301 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
6305 if (g_func_pp->is_vararg) {
6306 fprintf(fout, " va_list ap;\n");
6310 // declare arg-registers
6311 for (i = 0; i < g_func_pp->argc; i++) {
6312 if (g_func_pp->arg[i].reg != NULL) {
6313 reg = char_array_i(regs_r32,
6314 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
6315 if (regmask & (1 << reg)) {
6316 if (g_func_pp->arg[i].type.is_retreg)
6317 fprintf(fout, " u32 %s = *r_%s;\n",
6318 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
6320 fprintf(fout, " u32 %s = (u32)a%d;\n",
6321 g_func_pp->arg[i].reg, i + 1);
6324 if (g_func_pp->arg[i].type.is_retreg)
6325 ferr(ops, "retreg '%s' is unused?\n",
6326 g_func_pp->arg[i].reg);
6327 fprintf(fout, " // %s = a%d; // unused\n",
6328 g_func_pp->arg[i].reg, i + 1);
6334 // declare normal registers
6335 regmask_now = regmask & ~regmask_arg;
6336 regmask_now &= ~(1 << xSP);
6337 if (regmask_now & 0x00ff) {
6338 for (reg = 0; reg < 8; reg++) {
6339 if (regmask_now & (1 << reg)) {
6340 fprintf(fout, " u32 %s", regs_r32[reg]);
6341 if (regmask_init & (1 << reg))
6342 fprintf(fout, " = 0");
6343 fprintf(fout, ";\n");
6349 if (regmask_now & 0xff00) {
6350 for (reg = 8; reg < 16; reg++) {
6351 if (regmask_now & (1 << reg)) {
6352 fprintf(fout, " mmxr %s", regs_r32[reg]);
6353 if (regmask_init & (1 << reg))
6354 fprintf(fout, " = { 0, }");
6355 fprintf(fout, ";\n");
6361 if (need_float_stack) {
6362 fprintf(fout, " %s f_st[8];\n", float_type);
6363 fprintf(fout, " int f_stp = 0;\n");
6367 if (regmask_now & 0xff0000) {
6368 for (reg = 16; reg < 24; reg++) {
6369 if (regmask_now & (1 << reg)) {
6370 fprintf(fout, " %s f_st%d", float_type, reg - 16);
6371 if (regmask_init & (1 << reg))
6372 fprintf(fout, " = 0");
6373 fprintf(fout, ";\n");
6380 if (need_float_sw) {
6381 fprintf(fout, " u16 f_sw;\n");
6386 for (reg = 0; reg < 8; reg++) {
6387 if (regmask_save & (1 << reg)) {
6388 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
6394 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6395 if (save_arg_vars[i] == 0)
6397 for (reg = 0; reg < 32; reg++) {
6398 if (save_arg_vars[i] & (1 << reg)) {
6399 fprintf(fout, " u32 %s;\n",
6400 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
6407 for (reg = 0; reg < 32; reg++) {
6408 if (regmask_ffca & (1 << reg)) {
6409 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
6415 // declare push-pop temporaries
6417 for (reg = 0; reg < 8; reg++) {
6418 if (regmask_pp & (1 << reg)) {
6419 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
6426 for (i = 0; i < 8; i++) {
6427 if (cond_vars & (1 << i)) {
6428 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
6435 fprintf(fout, " u32 tmp;\n");
6440 fprintf(fout, " u64 tmp64;\n");
6445 fprintf(fout, "\n");
6447 // do stack clear, if needed
6448 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6450 if (g_stack_clear_len != 0) {
6451 if (g_stack_clear_len <= 4) {
6452 for (i = 0; i < g_stack_clear_len; i++)
6453 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6454 fprintf(fout, "0;\n");
6457 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6458 g_stack_clear_start, g_stack_clear_len * 4);
6462 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6465 if (g_func_pp->is_vararg) {
6466 if (g_func_pp->argc_stack == 0)
6467 ferr(ops, "vararg func without stack args?\n");
6468 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
6472 for (i = 0; i < opcnt; i++)
6474 if (g_labels[i] != NULL) {
6475 fprintf(fout, "\n%s:\n", g_labels[i]);
6478 delayed_flag_op = NULL;
6479 last_arith_dst = NULL;
6483 if (po->flags & OPF_RMD)
6488 #define assert_operand_cnt(n_) \
6489 if (po->operand_cnt != n_) \
6490 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6492 // conditional/flag using op?
6493 if (po->flags & OPF_CC)
6499 // we go through all this trouble to avoid using parsed_flag_op,
6500 // which makes generated code much nicer
6501 if (delayed_flag_op != NULL)
6503 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6504 po->pfo, po->pfo_inv);
6507 else if (last_arith_dst != NULL
6508 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6509 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6512 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6513 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6514 last_arith_dst->lmod, buf3);
6517 else if (tmp_op != NULL) {
6518 // use preprocessed flag calc results
6519 if (!(tmp_op->pfomask & (1 << po->pfo)))
6520 ferr(po, "not prepared for pfo %d\n", po->pfo);
6522 // note: pfo_inv was not yet applied
6523 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6524 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6527 ferr(po, "all methods of finding comparison failed\n");
6530 if (po->flags & OPF_JMP) {
6531 fprintf(fout, " if %s", buf1);
6533 else if (po->op == OP_RCL || po->op == OP_RCR
6534 || po->op == OP_ADC || po->op == OP_SBB)
6537 fprintf(fout, " cond_%s = %s;\n",
6538 parsed_flag_op_names[po->pfo], buf1);
6540 else if (po->flags & OPF_DATA) { // SETcc
6541 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6542 fprintf(fout, " %s = %s;", buf2, buf1);
6545 ferr(po, "unhandled conditional op\n");
6549 pfomask = po->pfomask;
6554 assert_operand_cnt(2);
6555 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6556 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6557 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
6558 fprintf(fout, " %s = %s;", buf1,
6559 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6564 assert_operand_cnt(2);
6565 po->operand[1].lmod = OPLM_DWORD; // always
6566 fprintf(fout, " %s = %s;",
6567 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6568 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6573 assert_operand_cnt(2);
6574 fprintf(fout, " %s = %s;",
6575 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6576 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6580 assert_operand_cnt(2);
6581 switch (po->operand[1].lmod) {
6583 strcpy(buf3, "(s8)");
6586 strcpy(buf3, "(s16)");
6589 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6591 fprintf(fout, " %s = %s;",
6592 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6593 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6598 assert_operand_cnt(2);
6599 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6600 fprintf(fout, " tmp = %s;",
6601 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6602 fprintf(fout, " %s = %s;",
6603 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6604 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6605 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6606 fprintf(fout, " %s = %stmp;",
6607 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6608 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
6609 snprintf(g_comment, sizeof(g_comment), "xchg");
6613 assert_operand_cnt(1);
6614 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6615 fprintf(fout, " %s = ~%s;", buf1, buf1);
6619 assert_operand_cnt(2);
6620 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6621 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6622 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6623 strcpy(g_comment, "xlat");
6627 assert_operand_cnt(2);
6628 fprintf(fout, " %s = (s32)%s >> 31;",
6629 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6630 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6631 strcpy(g_comment, "cdq");
6635 assert_operand_cnt(1);
6636 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6637 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
6641 if (po->flags & OPF_REP) {
6642 assert_operand_cnt(3);
6647 assert_operand_cnt(2);
6648 fprintf(fout, " %s = %sesi; esi %c= %d;",
6649 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6650 lmod_cast_u_ptr(po, po->operand[1].lmod),
6651 (po->flags & OPF_DF) ? '-' : '+',
6652 lmod_bytes(po, po->operand[1].lmod));
6653 strcpy(g_comment, "lods");
6658 if (po->flags & OPF_REP) {
6659 assert_operand_cnt(3);
6660 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
6661 (po->flags & OPF_DF) ? '-' : '+',
6662 lmod_bytes(po, po->operand[1].lmod));
6663 fprintf(fout, " %sedi = eax;",
6664 lmod_cast_u_ptr(po, po->operand[1].lmod));
6665 strcpy(g_comment, "rep stos");
6668 assert_operand_cnt(2);
6669 fprintf(fout, " %sedi = eax; edi %c= %d;",
6670 lmod_cast_u_ptr(po, po->operand[1].lmod),
6671 (po->flags & OPF_DF) ? '-' : '+',
6672 lmod_bytes(po, po->operand[1].lmod));
6673 strcpy(g_comment, "stos");
6678 j = lmod_bytes(po, po->operand[0].lmod);
6679 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6680 l = (po->flags & OPF_DF) ? '-' : '+';
6681 if (po->flags & OPF_REP) {
6682 assert_operand_cnt(3);
6684 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
6687 " %sedi = %sesi;", buf1, buf1);
6688 strcpy(g_comment, "rep movs");
6691 assert_operand_cnt(2);
6692 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
6693 buf1, buf1, l, j, l, j);
6694 strcpy(g_comment, "movs");
6699 // repe ~ repeat while ZF=1
6700 j = lmod_bytes(po, po->operand[0].lmod);
6701 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6702 l = (po->flags & OPF_DF) ? '-' : '+';
6703 if (po->flags & OPF_REP) {
6704 assert_operand_cnt(3);
6706 " while (ecx != 0) {\n");
6707 if (pfomask & (1 << PFO_C)) {
6710 " cond_c = %sesi < %sedi;\n", buf1, buf1);
6711 pfomask &= ~(1 << PFO_C);
6714 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
6715 buf1, buf1, l, j, l, j);
6718 " if (cond_z %s 0) break;\n",
6719 (po->flags & OPF_REPZ) ? "==" : "!=");
6722 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
6723 (po->flags & OPF_REPZ) ? "e" : "ne");
6726 assert_operand_cnt(2);
6728 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
6729 buf1, buf1, l, j, l, j);
6730 strcpy(g_comment, "cmps");
6732 pfomask &= ~(1 << PFO_Z);
6733 last_arith_dst = NULL;
6734 delayed_flag_op = NULL;
6738 // only does ZF (for now)
6739 // repe ~ repeat while ZF=1
6740 j = lmod_bytes(po, po->operand[1].lmod);
6741 l = (po->flags & OPF_DF) ? '-' : '+';
6742 if (po->flags & OPF_REP) {
6743 assert_operand_cnt(3);
6745 " while (ecx != 0) {\n");
6747 " cond_z = (%seax == %sedi); edi %c= %d;\n",
6748 lmod_cast_u(po, po->operand[1].lmod),
6749 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6752 " if (cond_z %s 0) break;\n",
6753 (po->flags & OPF_REPZ) ? "==" : "!=");
6756 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
6757 (po->flags & OPF_REPZ) ? "e" : "ne");
6760 assert_operand_cnt(2);
6761 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
6762 lmod_cast_u(po, po->operand[1].lmod),
6763 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6764 strcpy(g_comment, "scas");
6766 pfomask &= ~(1 << PFO_Z);
6767 last_arith_dst = NULL;
6768 delayed_flag_op = NULL;
6771 // arithmetic w/flags
6773 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
6774 goto dualop_arith_const;
6775 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6779 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6780 if (po->operand[1].type == OPT_CONST) {
6781 j = lmod_bytes(po, po->operand[0].lmod);
6782 if (((1ull << j * 8) - 1) == po->operand[1].val)
6783 goto dualop_arith_const;
6788 assert_operand_cnt(2);
6789 fprintf(fout, " %s %s= %s;",
6790 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6792 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6793 output_std_flags(fout, po, &pfomask, buf1);
6794 last_arith_dst = &po->operand[0];
6795 delayed_flag_op = NULL;
6799 // and 0, or ~0 used instead mov
6800 assert_operand_cnt(2);
6801 fprintf(fout, " %s = %s;",
6802 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6803 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6804 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6805 output_std_flags(fout, po, &pfomask, buf1);
6806 last_arith_dst = &po->operand[0];
6807 delayed_flag_op = NULL;
6812 assert_operand_cnt(2);
6813 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6814 if (pfomask & (1 << PFO_C)) {
6815 if (po->operand[1].type == OPT_CONST) {
6816 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6817 j = po->operand[1].val;
6820 if (po->op == OP_SHL)
6824 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
6828 ferr(po, "zero shift?\n");
6832 pfomask &= ~(1 << PFO_C);
6834 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
6835 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6836 if (po->operand[1].type != OPT_CONST)
6837 fprintf(fout, " & 0x1f");
6839 output_std_flags(fout, po, &pfomask, buf1);
6840 last_arith_dst = &po->operand[0];
6841 delayed_flag_op = NULL;
6845 assert_operand_cnt(2);
6846 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6847 fprintf(fout, " %s = %s%s >> %s;", buf1,
6848 lmod_cast_s(po, po->operand[0].lmod), buf1,
6849 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6850 output_std_flags(fout, po, &pfomask, buf1);
6851 last_arith_dst = &po->operand[0];
6852 delayed_flag_op = NULL;
6857 assert_operand_cnt(3);
6858 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6859 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6860 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
6861 if (po->operand[2].type != OPT_CONST) {
6862 // no handling for "undefined" case, hopefully not needed
6863 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
6866 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6867 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6868 if (po->op == OP_SHLD) {
6869 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
6870 buf1, buf3, buf1, buf2, l, buf3);
6871 strcpy(g_comment, "shld");
6874 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
6875 buf1, buf3, buf1, buf2, l, buf3);
6876 strcpy(g_comment, "shrd");
6878 output_std_flags(fout, po, &pfomask, buf1);
6879 last_arith_dst = &po->operand[0];
6880 delayed_flag_op = NULL;
6885 assert_operand_cnt(2);
6886 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6887 if (po->operand[1].type == OPT_CONST) {
6888 j = po->operand[1].val;
6889 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
6890 fprintf(fout, po->op == OP_ROL ?
6891 " %s = (%s << %d) | (%s >> %d);" :
6892 " %s = (%s >> %d) | (%s << %d);",
6893 buf1, buf1, j, buf1,
6894 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
6898 output_std_flags(fout, po, &pfomask, buf1);
6899 last_arith_dst = &po->operand[0];
6900 delayed_flag_op = NULL;
6905 assert_operand_cnt(2);
6906 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6907 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6908 if (po->operand[1].type == OPT_CONST) {
6909 j = po->operand[1].val % l;
6911 ferr(po, "zero rotate\n");
6912 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
6913 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
6914 if (po->op == OP_RCL) {
6916 " %s = (%s << %d) | (cond_c << %d)",
6917 buf1, buf1, j, j - 1);
6919 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
6923 " %s = (%s >> %d) | (cond_c << %d)",
6924 buf1, buf1, j, l - j);
6926 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
6928 fprintf(fout, ";\n");
6929 fprintf(fout, " cond_c = tmp;");
6933 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
6934 output_std_flags(fout, po, &pfomask, buf1);
6935 last_arith_dst = &po->operand[0];
6936 delayed_flag_op = NULL;
6940 assert_operand_cnt(2);
6941 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6942 if (IS(opr_name(po, 0), opr_name(po, 1))) {
6943 // special case for XOR
6944 int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
6945 for (j = 0; j <= PFO_LE; j++) {
6946 if (pfomask & (1 << j)) {
6947 fprintf(fout, " cond_%s = %d;\n",
6948 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
6949 pfomask &= ~(1 << j);
6952 fprintf(fout, " %s = 0;",
6953 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6954 last_arith_dst = &po->operand[0];
6955 delayed_flag_op = NULL;
6961 assert_operand_cnt(2);
6962 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6963 if (pfomask & (1 << PFO_C)) {
6964 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6965 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6966 if (po->operand[0].lmod == OPLM_DWORD) {
6967 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
6968 fprintf(fout, " cond_c = tmp64 >> 32;\n");
6969 fprintf(fout, " %s = (u32)tmp64;",
6970 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6971 strcat(g_comment, " add64");
6974 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
6975 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
6976 fprintf(fout, " %s += %s;",
6977 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6980 pfomask &= ~(1 << PFO_C);
6981 output_std_flags(fout, po, &pfomask, buf1);
6982 last_arith_dst = &po->operand[0];
6983 delayed_flag_op = NULL;
6986 if (pfomask & (1 << PFO_LE)) {
6987 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
6988 fprintf(fout, " cond_%s = %s;\n",
6989 parsed_flag_op_names[PFO_LE], buf1);
6990 pfomask &= ~(1 << PFO_LE);
6995 assert_operand_cnt(2);
6996 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6997 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
6998 for (j = 0; j <= PFO_LE; j++) {
6999 if (!(pfomask & (1 << j)))
7001 if (j == PFO_Z || j == PFO_S)
7004 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7005 fprintf(fout, " cond_%s = %s;\n",
7006 parsed_flag_op_names[j], buf1);
7007 pfomask &= ~(1 << j);
7014 assert_operand_cnt(2);
7015 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7016 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7017 if (po->op == OP_SBB
7018 && IS(po->operand[0].name, po->operand[1].name))
7020 // avoid use of unitialized var
7021 fprintf(fout, " %s = -cond_c;", buf1);
7022 // carry remains what it was
7023 pfomask &= ~(1 << PFO_C);
7026 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
7027 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7029 output_std_flags(fout, po, &pfomask, buf1);
7030 last_arith_dst = &po->operand[0];
7031 delayed_flag_op = NULL;
7036 // on SKL, if src is 0, dst is left unchanged
7037 assert_operand_cnt(2);
7038 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7039 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7040 output_std_flag_z(fout, po, &pfomask, buf2);
7041 if (po->op == OP_BSF)
7042 snprintf(buf3, sizeof(buf3), "__builtin_ffs(%s) - 1", buf2);
7044 snprintf(buf3, sizeof(buf3), "31 - __builtin_clz(%s)", buf2);
7045 fprintf(fout, " if (%s) %s = %s;", buf2, buf1, buf3);
7046 last_arith_dst = &po->operand[0];
7047 delayed_flag_op = NULL;
7048 strcat(g_comment, po->op == OP_BSF ? " bsf" : " bsr");
7052 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
7053 for (j = 0; j <= PFO_LE; j++) {
7054 if (!(pfomask & (1 << j)))
7056 if (j == PFO_Z || j == PFO_S || j == PFO_C)
7059 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7060 fprintf(fout, " cond_%s = %s;\n",
7061 parsed_flag_op_names[j], buf1);
7062 pfomask &= ~(1 << j);
7068 if (pfomask & (1 << PFO_C))
7069 // carry is unaffected by inc/dec.. wtf?
7070 ferr(po, "carry propagation needed\n");
7072 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7073 if (po->operand[0].type == OPT_REG) {
7074 strcpy(buf2, po->op == OP_INC ? "++" : "--");
7075 fprintf(fout, " %s%s;", buf1, buf2);
7078 strcpy(buf2, po->op == OP_INC ? "+" : "-");
7079 fprintf(fout, " %s %s= 1;", buf1, buf2);
7081 output_std_flags(fout, po, &pfomask, buf1);
7082 last_arith_dst = &po->operand[0];
7083 delayed_flag_op = NULL;
7087 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7088 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
7089 fprintf(fout, " %s = -%s%s;", buf1,
7090 lmod_cast_s(po, po->operand[0].lmod), buf2);
7091 last_arith_dst = &po->operand[0];
7092 delayed_flag_op = NULL;
7093 if (pfomask & PFOB_C) {
7094 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
7097 output_std_flags(fout, po, &pfomask, buf1);
7101 if (po->operand_cnt == 2) {
7102 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7105 if (po->operand_cnt == 3)
7106 ferr(po, "TODO imul3\n");
7109 assert_operand_cnt(1);
7110 switch (po->operand[0].lmod) {
7112 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
7113 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
7114 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
7115 fprintf(fout, " edx = tmp64 >> 32;\n");
7116 fprintf(fout, " eax = tmp64;");
7119 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
7120 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
7121 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
7125 ferr(po, "TODO: unhandled mul type\n");
7128 last_arith_dst = NULL;
7129 delayed_flag_op = NULL;
7134 assert_operand_cnt(1);
7135 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7136 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
7137 po->op == OP_IDIV));
7138 switch (po->operand[0].lmod) {
7140 if (po->flags & OPF_32BIT)
7141 snprintf(buf2, sizeof(buf2), "%seax", cast);
7143 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7144 snprintf(buf2, sizeof(buf2), "%stmp64",
7145 (po->op == OP_IDIV) ? "(s64)" : "");
7147 if (po->operand[0].type == OPT_REG
7148 && po->operand[0].reg == xDX)
7150 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
7151 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
7154 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
7155 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
7159 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
7160 snprintf(buf2, sizeof(buf2), "%stmp",
7161 (po->op == OP_IDIV) ? "(s32)" : "");
7162 if (po->operand[0].type == OPT_REG
7163 && po->operand[0].reg == xDX)
7165 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
7167 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
7171 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
7173 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
7176 strcat(g_comment, " div16");
7179 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
7181 last_arith_dst = NULL;
7182 delayed_flag_op = NULL;
7187 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7189 for (j = 0; j < 8; j++) {
7190 if (pfomask & (1 << j)) {
7191 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
7192 fprintf(fout, " cond_%s = %s;",
7193 parsed_flag_op_names[j], buf1);
7200 last_arith_dst = NULL;
7201 delayed_flag_op = po;
7205 // SETcc - should already be handled
7208 // note: we reuse OP_Jcc for SETcc, only flags differ
7210 fprintf(fout, "\n goto %s;", po->operand[0].name);
7214 fprintf(fout, " if (ecx == 0)\n");
7215 fprintf(fout, " goto %s;", po->operand[0].name);
7216 strcat(g_comment, " jecxz");
7220 fprintf(fout, " if (--ecx != 0)\n");
7221 fprintf(fout, " goto %s;", po->operand[0].name);
7222 strcat(g_comment, " loop");
7226 assert_operand_cnt(1);
7227 last_arith_dst = NULL;
7228 delayed_flag_op = NULL;
7230 if (po->operand[0].type == OPT_REGMEM) {
7231 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
7234 ferr(po, "parse failure for jmp '%s'\n",
7235 po->operand[0].name);
7236 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
7239 else if (po->operand[0].type != OPT_LABEL)
7240 ferr(po, "unhandled jmp type\n");
7242 fprintf(fout, " goto %s;", po->operand[0].name);
7246 assert_operand_cnt(1);
7248 my_assert_not(pp, NULL);
7251 if (po->flags & OPF_CC) {
7252 // we treat conditional branch to another func
7253 // (yes such code exists..) as conditional tailcall
7255 fprintf(fout, " {\n");
7258 if (pp->is_fptr && !pp->is_arg) {
7259 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
7260 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7262 if (pp->is_unresolved || IS_START(pp->name, "i_guess"))
7263 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
7264 buf3, asmfn, po->asmln, pp->name);
7267 fprintf(fout, "%s", buf3);
7268 if (strstr(pp->ret_type.name, "int64")) {
7269 if (po->flags & OPF_TAIL)
7270 ferr(po, "int64 and tail?\n");
7271 fprintf(fout, "tmp64 = ");
7273 else if (!IS(pp->ret_type.name, "void")) {
7274 if (po->flags & OPF_TAIL) {
7275 if (regmask_ret & mxAX) {
7276 fprintf(fout, "return ");
7277 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
7278 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
7280 else if (regmask_ret & mxST0)
7281 ferr(po, "float tailcall\n");
7283 else if (po->regmask_dst & mxAX) {
7284 fprintf(fout, "eax = ");
7285 if (pp->ret_type.is_ptr)
7286 fprintf(fout, "(u32)");
7288 else if (po->regmask_dst & mxST0) {
7289 ferr_assert(po, po->flags & OPF_FPUSH);
7290 if (need_float_stack)
7291 fprintf(fout, "f_st[--f_stp & 7] = ");
7293 fprintf(fout, "f_st0 = ");
7297 if (pp->name[0] == 0)
7298 ferr(po, "missing pp->name\n");
7299 fprintf(fout, "%s%s(", pp->name,
7300 pp->has_structarg ? "_sa" : "");
7302 if (po->flags & OPF_ATAIL) {
7304 g_func_pp->is_stdcall && g_func_pp->argc_stack > 0;
7305 check_compat |= pp->argc_stack > 0;
7307 && (pp->argc_stack != g_func_pp->argc_stack
7308 || pp->is_stdcall != g_func_pp->is_stdcall))
7309 ferr(po, "incompatible arg-reuse tailcall\n");
7310 if (g_func_pp->has_retreg)
7311 ferr(po, "TODO: retreg+tailcall\n");
7313 for (arg = j = 0; arg < pp->argc; arg++) {
7315 fprintf(fout, ", ");
7318 if (pp->arg[arg].type.is_ptr)
7319 snprintf(cast, sizeof(cast), "(%s)",
7320 pp->arg[arg].type.name);
7322 if (pp->arg[arg].reg != NULL) {
7323 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7327 for (; j < g_func_pp->argc; j++)
7328 if (g_func_pp->arg[j].reg == NULL)
7330 fprintf(fout, "%sa%d", cast, j + 1);
7335 for (arg = 0; arg < pp->argc; arg++) {
7337 fprintf(fout, ", ");
7340 if (pp->arg[arg].type.is_ptr)
7341 snprintf(cast, sizeof(cast), "(%s)",
7342 pp->arg[arg].type.name);
7344 if (pp->arg[arg].reg != NULL) {
7345 if (pp->arg[arg].type.is_retreg)
7346 fprintf(fout, "&%s", pp->arg[arg].reg);
7347 else if (IS(pp->arg[arg].reg, "ebp")
7348 && g_bp_frame && !(po->flags & OPF_EBP_S))
7350 // rare special case
7351 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
7352 strcat(g_comment, " bp_ref");
7355 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7360 tmp_op = pp->arg[arg].datap;
7362 ferr(po, "parsed_op missing for arg%d\n", arg);
7364 if (tmp_op->flags & OPF_VAPUSH) {
7365 fprintf(fout, "ap");
7367 else if (tmp_op->op == OP_FST) {
7368 fprintf(fout, "fs_%d", tmp_op->p_argnum);
7369 if (tmp_op->operand[0].lmod == OPLM_QWORD)
7372 else if (pp->arg[arg].type.is_64bit) {
7373 ferr_assert(po, tmp_op->p_argpass == 0);
7374 ferr_assert(po, !pp->arg[arg].is_saved);
7375 ferr_assert(po, !pp->arg[arg].type.is_float);
7376 ferr_assert(po, cast[0] == 0);
7377 out_src_opr(buf1, sizeof(buf1),
7378 tmp_op, &tmp_op->operand[0], cast, 0);
7379 tmp_op = pp->arg[++arg].datap;
7380 ferr_assert(po, tmp_op != NULL);
7381 out_src_opr(buf2, sizeof(buf2),
7382 tmp_op, &tmp_op->operand[0], cast, 0);
7383 fprintf(fout, "((u64)(%s) << 32) | (%s)",
7386 else if (tmp_op->p_argpass != 0) {
7387 ferr_assert(po, !pp->arg[arg].type.is_float);
7388 fprintf(fout, "a%d", tmp_op->p_argpass);
7390 else if (pp->arg[arg].is_saved) {
7391 ferr_assert(po, tmp_op->p_argnum > 0);
7392 ferr_assert(po, !pp->arg[arg].type.is_float);
7393 fprintf(fout, "%s%s", cast,
7394 saved_arg_name(buf1, sizeof(buf1),
7395 tmp_op->p_arggrp, tmp_op->p_argnum));
7397 else if (pp->arg[arg].type.is_float) {
7398 ferr_assert(po, !pp->arg[arg].type.is_64bit);
7400 out_src_opr_float(buf1, sizeof(buf1),
7401 tmp_op, &tmp_op->operand[0], need_float_stack));
7405 out_src_opr(buf1, sizeof(buf1),
7406 tmp_op, &tmp_op->operand[0], cast, 0));
7410 fprintf(fout, ");");
7412 if (strstr(pp->ret_type.name, "int64")) {
7413 fprintf(fout, "\n");
7414 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7415 fprintf(fout, "%seax = tmp64;", buf3);
7418 if (pp->is_unresolved) {
7419 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
7421 strcat(g_comment, buf2);
7424 if (po->flags & OPF_TAIL) {
7426 if (i == opcnt - 1 || pp->is_noreturn)
7428 else if (IS(pp->ret_type.name, "void"))
7430 else if (!(regmask_ret & (1 << xAX)))
7432 // else already handled as 'return f()'
7435 fprintf(fout, "\n%sreturn;", buf3);
7436 strcat(g_comment, " ^ tailcall");
7439 strcat(g_comment, " tailcall");
7441 if ((regmask_ret & (1 << xAX))
7442 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7444 ferr(po, "int func -> void func tailcall?\n");
7447 if (pp->is_noreturn)
7448 strcat(g_comment, " noreturn");
7449 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7450 strcat(g_comment, " argframe");
7451 if (po->flags & OPF_CC)
7452 strcat(g_comment, " cond");
7454 if (po->flags & OPF_CC)
7455 fprintf(fout, "\n }");
7457 delayed_flag_op = NULL;
7458 last_arith_dst = NULL;
7462 if (g_func_pp->is_vararg)
7463 fprintf(fout, " va_end(ap);\n");
7464 if (g_func_pp->has_retreg) {
7465 for (arg = 0; arg < g_func_pp->argc; arg++)
7466 if (g_func_pp->arg[arg].type.is_retreg)
7467 fprintf(fout, " *r_%s = %s;\n",
7468 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7471 if (regmask_ret & mxST0) {
7472 fprintf(fout, " return %s;", float_st0);
7474 else if (!(regmask_ret & mxAX)) {
7475 if (i != opcnt - 1 || label_pending)
7476 fprintf(fout, " return;");
7478 else if (g_func_pp->ret_type.is_ptr) {
7479 fprintf(fout, " return (%s)eax;",
7480 g_func_pp->ret_type.name);
7482 else if (IS(g_func_pp->ret_type.name, "__int64"))
7483 fprintf(fout, " return ((u64)edx << 32) | eax;");
7485 fprintf(fout, " return eax;");
7487 last_arith_dst = NULL;
7488 delayed_flag_op = NULL;
7492 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7493 if (po->p_argnum != 0) {
7494 // special case - saved func arg
7495 fprintf(fout, " %s = %s;",
7496 saved_arg_name(buf2, sizeof(buf2),
7497 po->p_arggrp, po->p_argnum), buf1);
7500 else if (po->flags & OPF_RSAVE) {
7501 fprintf(fout, " s_%s = %s;", buf1, buf1);
7504 else if (po->flags & OPF_PPUSH) {
7506 ferr_assert(po, tmp_op != NULL);
7507 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7508 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7511 else if (g_func_pp->is_userstack) {
7512 fprintf(fout, " *(--esp) = %s;", buf1);
7515 if (!(g_ida_func_attr & IDAFA_NORETURN))
7516 ferr(po, "stray push encountered\n");
7521 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7522 if (po->flags & OPF_RSAVE) {
7523 fprintf(fout, " %s = s_%s;", buf1, buf1);
7526 else if (po->flags & OPF_PPUSH) {
7527 // push/pop graph / non-const
7528 ferr_assert(po, po->datap == NULL);
7529 fprintf(fout, " %s = pp_%s;", buf1, buf1);
7532 else if (po->datap != NULL) {
7535 fprintf(fout, " %s = %s;", buf1,
7536 out_src_opr(buf2, sizeof(buf2),
7537 tmp_op, &tmp_op->operand[0],
7538 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7541 else if (g_func_pp->is_userstack) {
7542 fprintf(fout, " %s = *esp++;", buf1);
7546 ferr(po, "stray pop encountered\n");
7556 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7557 fprintf(fout, " tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
7558 po->op == OPP_ALLSHL ? "<<" : ">>");
7559 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
7560 strcat(g_comment, po->op == OPP_ALLSHL
7561 ? " allshl" : " allshr");
7566 if (need_float_stack) {
7567 out_src_opr_float(buf1, sizeof(buf1),
7568 po, &po->operand[0], 1);
7569 if (po->regmask_src & mxSTa) {
7570 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7574 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
7577 if (po->flags & OPF_FSHIFT)
7578 fprintf(fout, " f_st1 = f_st0;");
7579 if (po->operand[0].type == OPT_REG
7580 && po->operand[0].reg == xST0)
7582 strcat(g_comment, " fld st");
7585 fprintf(fout, " f_st0 = %s;",
7586 out_src_opr_float(buf1, sizeof(buf1),
7587 po, &po->operand[0], 0));
7589 strcat(g_comment, " fld");
7593 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7594 lmod_cast(po, po->operand[0].lmod, 1), 0);
7595 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7596 if (need_float_stack) {
7597 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
7600 if (po->flags & OPF_FSHIFT)
7601 fprintf(fout, " f_st1 = f_st0;");
7602 fprintf(fout, " f_st0 = %s;", buf2);
7604 strcat(g_comment, " fild");
7608 if (need_float_stack)
7609 fprintf(fout, " f_st[--f_stp & 7] = ");
7611 if (po->flags & OPF_FSHIFT)
7612 fprintf(fout, " f_st1 = f_st0;");
7613 fprintf(fout, " f_st0 = ");
7615 switch (po->operand[0].val) {
7616 case X87_CONST_1: fprintf(fout, "1.0;"); break;
7617 case X87_CONST_L2T: fprintf(fout, "3.321928094887362;"); break;
7618 case X87_CONST_L2E: fprintf(fout, "M_LOG2E;"); break;
7619 case X87_CONST_PI: fprintf(fout, "M_PI;"); break;
7620 case X87_CONST_LG2: fprintf(fout, "0.301029995663981;"); break;
7621 case X87_CONST_LN2: fprintf(fout, "M_LN2;"); break;
7622 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
7623 default: ferr_assert(po, 0); break;
7628 if (po->flags & OPF_FARG) {
7629 // store to stack as func arg
7630 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7634 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7636 dead_dst = po->operand[0].type == OPT_REG
7637 && po->operand[0].reg == xST0;
7640 fprintf(fout, " %s = %s;", buf1, float_st0);
7641 if (po->flags & OPF_FSHIFT) {
7642 if (need_float_stack)
7643 fprintf(fout, " f_stp++;");
7645 fprintf(fout, " f_st0 = f_st1;");
7647 if (dead_dst && !(po->flags & OPF_FSHIFT))
7650 strcat(g_comment, " fst");
7654 fprintf(fout, " %s = %s%s;",
7655 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7656 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7657 if (po->flags & OPF_FSHIFT) {
7658 if (need_float_stack)
7659 fprintf(fout, " f_stp++;");
7661 fprintf(fout, " f_st0 = f_st1;");
7663 strcat(g_comment, " fist");
7670 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7672 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7674 dead_dst = (po->flags & OPF_FPOP)
7675 && po->operand[0].type == OPT_REG
7676 && po->operand[0].reg == xST0;
7678 case OP_FADD: j = '+'; break;
7679 case OP_FDIV: j = '/'; break;
7680 case OP_FMUL: j = '*'; break;
7681 case OP_FSUB: j = '-'; break;
7682 default: j = 'x'; break;
7684 if (need_float_stack) {
7686 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7687 if (po->flags & OPF_FSHIFT)
7688 fprintf(fout, " f_stp++;");
7691 if (po->flags & OPF_FSHIFT) {
7692 // note: assumes only 2 regs handled
7694 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
7696 fprintf(fout, " f_st0 = f_st1;");
7699 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7701 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7706 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7708 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7710 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
7712 dead_dst = (po->flags & OPF_FPOP)
7713 && po->operand[0].type == OPT_REG
7714 && po->operand[0].reg == xST0;
7715 j = po->op == OP_FDIVR ? '/' : '-';
7716 if (need_float_stack) {
7718 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7719 if (po->flags & OPF_FSHIFT)
7720 fprintf(fout, " f_stp++;");
7723 if (po->flags & OPF_FSHIFT) {
7725 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
7727 fprintf(fout, " f_st0 = f_st1;");
7730 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7732 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7740 case OP_FIADD: j = '+'; break;
7741 case OP_FIDIV: j = '/'; break;
7742 case OP_FIMUL: j = '*'; break;
7743 case OP_FISUB: j = '-'; break;
7744 default: j = 'x'; break;
7746 fprintf(fout, " %s %c= (%s)%s;", float_st0,
7748 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7749 lmod_cast(po, po->operand[0].lmod, 1), 0));
7754 fprintf(fout, " %s = %s %c %s;", float_st0,
7755 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7757 po->op == OP_FIDIVR ? '/' : '-', float_st0);
7762 ferr_assert(po, po->datap != NULL);
7763 mask = (long)po->datap & 0xffff;
7764 z_check = ((long)po->datap >> 16) & 1;
7765 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7767 if (mask == 0x0100 || mask == 0x0500) { // C0 -> <
7768 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
7771 else if (mask == 0x4000 || mask == 0x4400) { // C3 -> =
7772 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
7775 else if (mask == 0x4100) { // C3, C0
7777 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
7779 strcat(g_comment, " z_chk_det");
7782 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
7783 "(%s < %s ? 0x0100 : 0);",
7784 float_st0, buf1, float_st0, buf1);
7788 ferr(po, "unhandled sw mask: %x\n", mask);
7789 if (po->flags & OPF_FSHIFT) {
7790 if (need_float_stack) {
7791 if (po->flags & OPF_FPOPP)
7792 fprintf(fout, " f_stp += 2;");
7794 fprintf(fout, " f_stp++;");
7797 ferr_assert(po, !(po->flags & OPF_FPOPP));
7798 fprintf(fout, " f_st0 = f_st1;");
7805 fprintf(fout, " %s = f_sw;",
7806 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7810 fprintf(fout, " %s = -%s;", float_st0, float_st0);
7814 fprintf(fout, " %s = cos%s(%s);", float_st0,
7815 need_double ? "" : "f", float_st0);
7819 if (need_float_stack) {
7820 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
7821 need_double ? "" : "f", float_st1, float_st0);
7822 fprintf(fout, " f_stp++;");
7825 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
7826 need_double ? "" : "f");
7831 if (need_float_stack) {
7832 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
7833 float_st1, need_double ? "" : "f", float_st0);
7834 fprintf(fout, " f_stp++;");
7837 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
7838 need_double ? "" : "f");
7840 strcat(g_comment, " fyl2x");
7844 fprintf(fout, " %s = sin%s(%s);", float_st0,
7845 need_double ? "" : "f", float_st0);
7849 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
7850 need_double ? "" : "f", float_st0);
7854 dead_dst = po->operand[0].type == OPT_REG
7855 && po->operand[0].reg == xST0;
7857 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7859 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
7860 float_st0, float_st0, buf1, buf1);
7861 strcat(g_comment, " fxch");
7868 ferr_assert(po, po->flags & OPF_32BIT);
7869 fprintf(fout, " eax = (s32)%s;", float_st0);
7870 if (po->flags & OPF_FSHIFT) {
7871 if (need_float_stack)
7872 fprintf(fout, " f_stp++;");
7874 fprintf(fout, " f_st0 = f_st1;");
7876 strcat(g_comment, " ftol");
7880 if (need_float_stack) {
7881 fprintf(fout, " %s = pow%s(%s, %s);", float_st1,
7882 need_double ? "" : "f", float_st1, float_st0);
7883 fprintf(fout, " f_stp++;");
7886 fprintf(fout, " f_st0 = pow%s(f_st1, f_st0);",
7887 need_double ? "" : "f");
7889 strcat(g_comment, " CIpow");
7893 fprintf(fout, " do_skip_code_abort();");
7898 fprintf(fout, " do_emms();");
7903 ferr(po, "unhandled op type %d, flags %x\n",
7908 if (g_comment[0] != 0) {
7909 char *p = g_comment;
7910 while (my_isblank(*p))
7912 fprintf(fout, " // %s", p);
7917 fprintf(fout, "\n");
7919 // some sanity checking
7920 if (po->flags & OPF_REP) {
7921 if (po->op != OP_STOS && po->op != OP_MOVS
7922 && po->op != OP_CMPS && po->op != OP_SCAS)
7923 ferr(po, "unexpected rep\n");
7924 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
7925 && (po->op == OP_CMPS || po->op == OP_SCAS))
7926 ferr(po, "cmps/scas with plain rep\n");
7928 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
7929 && po->op != OP_CMPS && po->op != OP_SCAS)
7930 ferr(po, "unexpected repz/repnz\n");
7933 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
7935 // see is delayed flag stuff is still valid
7936 if (delayed_flag_op != NULL && delayed_flag_op != po) {
7937 if (is_any_opr_modified(delayed_flag_op, po, 0))
7938 delayed_flag_op = NULL;
7941 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
7942 if (is_opr_modified(last_arith_dst, po))
7943 last_arith_dst = NULL;
7950 if (g_stack_fsz && !g_stack_frame_used)
7951 fprintf(fout, " (void)sf;\n");
7953 fprintf(fout, "}\n\n");
7955 gen_x_cleanup(opcnt);
7958 static void gen_x_cleanup(int opcnt)
7962 for (i = 0; i < opcnt; i++) {
7963 struct label_ref *lr, *lr_del;
7965 lr = g_label_refs[i].next;
7966 while (lr != NULL) {
7971 g_label_refs[i].i = -1;
7972 g_label_refs[i].next = NULL;
7974 if (ops[i].op == OP_CALL) {
7976 proto_release(ops[i].pp);
7982 struct func_proto_dep;
7984 struct func_prototype {
7989 int has_ret:3; // -1, 0, 1: unresolved, no, yes
7990 unsigned int dep_resolved:1;
7991 unsigned int is_stdcall:1;
7992 struct func_proto_dep *dep_func;
7994 const struct parsed_proto *pp; // seed pp, if any
7997 struct func_proto_dep {
7999 struct func_prototype *proto;
8000 int regmask_live; // .. at the time of call
8001 unsigned int ret_dep:1; // return from this is caller's return
8004 static struct func_prototype *hg_fp;
8005 static int hg_fp_cnt;
8007 static struct scanned_var {
8009 enum opr_lenmod lmod;
8010 unsigned int is_seeded:1;
8011 unsigned int is_c_str:1;
8012 const struct parsed_proto *pp; // seed pp, if any
8014 static int hg_var_cnt;
8016 static char **hg_refs;
8017 static int hg_ref_cnt;
8019 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8022 static struct func_prototype *hg_fp_add(const char *funcn)
8024 struct func_prototype *fp;
8026 if ((hg_fp_cnt & 0xff) == 0) {
8027 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
8028 my_assert_not(hg_fp, NULL);
8029 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
8032 fp = &hg_fp[hg_fp_cnt];
8033 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
8035 fp->argc_stack = -1;
8041 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
8046 for (i = 0; i < fp->dep_func_cnt; i++)
8047 if (IS(fp->dep_func[i].name, name))
8048 return &fp->dep_func[i];
8053 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
8056 if (hg_fp_find_dep(fp, name))
8059 if ((fp->dep_func_cnt & 0xff) == 0) {
8060 fp->dep_func = realloc(fp->dep_func,
8061 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
8062 my_assert_not(fp->dep_func, NULL);
8063 memset(&fp->dep_func[fp->dep_func_cnt], 0,
8064 sizeof(fp->dep_func[0]) * 0x100);
8066 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
8070 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
8072 const struct func_prototype *p1 = p1_, *p2 = p2_;
8073 return strcmp(p1->name, p2->name);
8077 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
8079 const struct func_prototype *p1 = p1_, *p2 = p2_;
8080 return p1->id - p2->id;
8084 static void hg_ref_add(const char *name)
8086 if ((hg_ref_cnt & 0xff) == 0) {
8087 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
8088 my_assert_not(hg_refs, NULL);
8089 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
8092 hg_refs[hg_ref_cnt] = strdup(name);
8093 my_assert_not(hg_refs[hg_ref_cnt], NULL);
8097 // recursive register dep pass
8098 // - track saved regs (part 2)
8099 // - try to figure out arg-regs
8100 // - calculate reg deps
8101 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
8102 struct func_prototype *fp, int regmask_save, int regmask_dst,
8103 int *regmask_dep, int *has_ret)
8105 struct func_proto_dep *dep;
8106 struct parsed_op *po;
8107 int from_caller = 0;
8112 for (; i < opcnt; i++)
8114 if (cbits[i >> 3] & (1 << (i & 7)))
8116 cbits[i >> 3] |= (1 << (i & 7));
8120 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
8121 if (po->flags & OPF_RMD)
8124 if (po->btj != NULL) {
8126 for (j = 0; j < po->btj->count; j++) {
8127 check_i(po, po->btj->d[j].bt_i);
8128 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
8129 regmask_save, regmask_dst, regmask_dep, has_ret);
8134 check_i(po, po->bt_i);
8135 if (po->flags & OPF_CJMP) {
8136 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
8137 regmask_save, regmask_dst, regmask_dep, has_ret);
8145 if (po->flags & OPF_FARG)
8146 /* (just calculate register deps) */;
8147 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
8149 reg = po->operand[0].reg;
8150 ferr_assert(po, reg >= 0);
8152 if (po->flags & OPF_RSAVE) {
8153 regmask_save |= 1 << reg;
8156 if (po->flags & OPF_DONE)
8159 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0, 0);
8161 regmask_save |= 1 << reg;
8162 po->flags |= OPF_RMD;
8163 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, OPF_RMD);
8167 else if (po->flags & OPF_RMD)
8169 else if (po->op == OP_CALL) {
8170 po->regmask_dst |= 1 << xAX;
8172 dep = hg_fp_find_dep(fp, po->operand[0].name);
8174 dep->regmask_live = regmask_save | regmask_dst;
8175 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8176 dep->regmask_live |= 1 << xBP;
8179 else if (po->op == OP_RET) {
8180 if (po->operand_cnt > 0) {
8182 if (fp->argc_stack >= 0
8183 && fp->argc_stack != po->operand[0].val / 4)
8184 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
8185 fp->argc_stack = po->operand[0].val / 4;
8189 // if has_ret is 0, there is uninitialized eax path,
8190 // which means it's most likely void func
8191 if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
8192 if (po->op == OP_CALL) {
8197 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
8200 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
8203 if (ret != 1 && from_caller) {
8204 // unresolved eax - probably void func
8208 if (j >= 0 && ops[j].op == OP_CALL) {
8209 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
8220 l = regmask_save | regmask_dst;
8221 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8224 l = po->regmask_src & ~l;
8227 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
8228 l, regmask_dst, regmask_save, po->flags);
8231 regmask_dst |= po->regmask_dst;
8233 if (po->flags & OPF_TAIL)
8238 static void gen_hdr(const char *funcn, int opcnt)
8240 unsigned char cbits[MAX_OPS / 8];
8241 const struct parsed_proto *pp_c;
8242 struct parsed_proto *pp;
8243 struct func_prototype *fp;
8244 struct parsed_op *po;
8245 int regmask_dummy = 0;
8247 int max_bp_offset = 0;
8252 pp_c = proto_parse(g_fhdr, funcn, 1);
8254 // already in seed, will add to hg_fp later
8257 fp = hg_fp_add(funcn);
8259 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
8260 g_stack_frame_used = 0;
8264 // - resolve all branches
8265 // - parse calls with labels
8266 resolve_branches_parse_calls(opcnt);
8269 // - handle ebp/esp frame, remove ops related to it
8270 scan_prologue_epilogue(opcnt, NULL);
8273 // - remove dead labels
8275 for (i = 0; i < opcnt; i++)
8277 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8283 if (po->flags & (OPF_RMD|OPF_DONE))
8286 if (po->op == OP_CALL) {
8287 if (po->operand[0].type == OPT_LABEL)
8288 hg_fp_add_dep(fp, opr_name(po, 0));
8289 else if (po->pp != NULL)
8290 hg_fp_add_dep(fp, po->pp->name);
8295 // - remove dead labels
8296 // - handle push <const>/pop pairs
8297 for (i = 0; i < opcnt; i++)
8299 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8305 if (po->flags & (OPF_RMD|OPF_DONE))
8308 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
8309 scan_for_pop_const(i, opcnt, i + opcnt * 13);
8313 // - process trivial calls
8314 for (i = 0; i < opcnt; i++)
8317 if (po->flags & (OPF_RMD|OPF_DONE))
8320 if (po->op == OP_CALL)
8322 pp = process_call_early(i, opcnt, &j);
8324 if (!(po->flags & OPF_ATAIL))
8325 // since we know the args, try to collect them
8326 if (collect_call_args_early(i, pp, NULL, NULL) != 0)
8332 // commit esp adjust
8333 if (ops[j].op != OP_POP)
8334 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
8336 for (l = 0; l < pp->argc_stack; l++)
8337 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
8341 po->flags |= OPF_DONE;
8347 // - track saved regs (simple)
8349 for (i = 0; i < opcnt; i++)
8352 if (po->flags & (OPF_RMD|OPF_DONE))
8355 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
8356 && po->operand[0].reg != xCX)
8358 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
8360 // regmask_save |= 1 << po->operand[0].reg; // do it later
8361 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
8362 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
8365 else if (po->op == OP_CALL)
8367 pp = process_call(i, opcnt);
8369 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
8370 // since we know the args, collect them
8371 ret = collect_call_args(po, i, pp, ®mask_dummy,
8378 memset(cbits, 0, sizeof(cbits));
8382 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, ®mask_dep, &has_ret);
8384 // find unreachable code - must be fixed in IDA
8385 for (i = 0; i < opcnt; i++)
8387 if (cbits[i >> 3] & (1 << (i & 7)))
8390 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
8391 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
8393 // the compiler sometimes still generates code after
8394 // noreturn OS functions
8397 if (ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
8398 ferr(&ops[i], "unreachable code\n");
8401 for (i = 0; i < g_eqcnt; i++) {
8402 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
8403 max_bp_offset = g_eqs[i].offset;
8406 if (fp->argc_stack < 0) {
8407 max_bp_offset = (max_bp_offset + 3) & ~3;
8408 fp->argc_stack = max_bp_offset / 4;
8409 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
8413 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
8414 fp->has_ret = has_ret;
8416 printf("// has_ret %d, regmask_dep %x\n",
8417 fp->has_ret, fp->regmask_dep);
8418 output_hdr_fp(stdout, fp, 1);
8419 if (IS(funcn, "sub_10007F72")) exit(1);
8422 gen_x_cleanup(opcnt);
8425 static void hg_fp_resolve_deps(struct func_prototype *fp)
8427 struct func_prototype fp_s;
8431 // this thing is recursive, so mark first..
8432 fp->dep_resolved = 1;
8434 for (i = 0; i < fp->dep_func_cnt; i++) {
8435 strcpy(fp_s.name, fp->dep_func[i].name);
8436 fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8437 sizeof(hg_fp[0]), hg_fp_cmp_name);
8438 if (fp->dep_func[i].proto != NULL) {
8439 if (!fp->dep_func[i].proto->dep_resolved)
8440 hg_fp_resolve_deps(fp->dep_func[i].proto);
8442 dep = ~fp->dep_func[i].regmask_live
8443 & fp->dep_func[i].proto->regmask_dep;
8444 fp->regmask_dep |= dep;
8445 // printf("dep %s %s |= %x\n", fp->name,
8446 // fp->dep_func[i].name, dep);
8448 if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
8449 fp->has_ret = fp->dep_func[i].proto->has_ret;
8454 // make all thiscall/edx arg functions referenced from .data fastcall
8455 static void do_func_refs_from_data(void)
8457 struct func_prototype *fp, fp_s;
8460 for (i = 0; i < hg_ref_cnt; i++) {
8461 strcpy(fp_s.name, hg_refs[i]);
8462 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8463 sizeof(hg_fp[0]), hg_fp_cmp_name);
8467 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
8468 fp->regmask_dep |= mxCX | mxDX;
8472 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8475 const struct parsed_proto *pp;
8476 char *p, namebuf[NAMELEN];
8482 for (; count > 0; count--, fp++) {
8483 if (fp->has_ret == -1)
8484 fprintf(fout, "// ret unresolved\n");
8486 fprintf(fout, "// dep:");
8487 for (j = 0; j < fp->dep_func_cnt; j++) {
8488 fprintf(fout, " %s/", fp->dep_func[j].name);
8489 if (fp->dep_func[j].proto != NULL)
8490 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8491 fp->dep_func[j].proto->has_ret);
8493 fprintf(fout, "\n");
8496 p = strchr(fp->name, '@');
8498 memcpy(namebuf, fp->name, p - fp->name);
8499 namebuf[p - fp->name] = 0;
8507 pp = proto_parse(g_fhdr, name, 1);
8508 if (pp != NULL && pp->is_include)
8511 if (fp->pp != NULL) {
8512 // part of seed, output later
8516 regmask_dep = fp->regmask_dep;
8517 argc_normal = fp->argc_stack;
8519 fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
8520 (fp->has_ret ? "int" : "void"));
8521 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
8522 && (regmask_dep & ~mxCX) == 0)
8524 fprintf(fout, "/*__thiscall*/ ");
8528 else if (regmask_dep && (fp->is_stdcall || fp->argc_stack == 0)
8529 && (regmask_dep & ~(mxCX | mxDX)) == 0)
8531 fprintf(fout, " __fastcall ");
8532 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8538 else if (regmask_dep && !fp->is_stdcall) {
8539 fprintf(fout, "/*__usercall*/ ");
8541 else if (regmask_dep) {
8542 fprintf(fout, "/*__userpurge*/ ");
8544 else if (fp->is_stdcall)
8545 fprintf(fout, " __stdcall ");
8547 fprintf(fout, " __cdecl ");
8549 fprintf(fout, "%s(", name);
8552 for (j = 0; j < xSP; j++) {
8553 if (regmask_dep & (1 << j)) {
8556 fprintf(fout, ", ");
8558 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8560 fprintf(fout, "int");
8561 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
8565 for (j = 0; j < argc_normal; j++) {
8568 fprintf(fout, ", ");
8569 if (fp->pp != NULL) {
8570 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8571 if (!fp->pp->arg[arg - 1].type.is_ptr)
8575 fprintf(fout, "int ");
8576 fprintf(fout, "a%d", arg);
8579 fprintf(fout, ");\n");
8583 static void output_hdr(FILE *fout)
8585 static const char *lmod_c_names[] = {
8586 [OPLM_UNSPEC] = "???",
8587 [OPLM_BYTE] = "uint8_t",
8588 [OPLM_WORD] = "uint16_t",
8589 [OPLM_DWORD] = "uint32_t",
8590 [OPLM_QWORD] = "uint64_t",
8592 const struct scanned_var *var;
8593 struct func_prototype *fp;
8594 char line[256] = { 0, };
8598 // add stuff from headers
8599 for (i = 0; i < pp_cache_size; i++) {
8600 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
8601 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
8603 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
8604 fp = hg_fp_add(name);
8605 fp->pp = &pp_cache[i];
8606 fp->argc_stack = fp->pp->argc_stack;
8607 fp->is_stdcall = fp->pp->is_stdcall;
8608 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
8609 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
8613 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
8614 for (i = 0; i < hg_fp_cnt; i++)
8615 hg_fp_resolve_deps(&hg_fp[i]);
8617 // adjust functions referenced from data segment
8618 do_func_refs_from_data();
8620 // note: messes up .proto ptr, don't use
8621 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
8624 for (i = 0; i < hg_var_cnt; i++) {
8627 if (var->pp != NULL)
8630 else if (var->is_c_str)
8631 fprintf(fout, "extern %-8s %s[];", "char", var->name);
8633 fprintf(fout, "extern %-8s %s;",
8634 lmod_c_names[var->lmod], var->name);
8637 fprintf(fout, " // seeded");
8638 fprintf(fout, "\n");
8641 fprintf(fout, "\n");
8643 // output function prototypes
8644 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
8647 fprintf(fout, "\n// - seed -\n");
8650 while (fgets(line, sizeof(line), g_fhdr))
8651 fwrite(line, 1, strlen(line), fout);
8654 // '=' needs special treatment
8656 static char *next_word_s(char *w, size_t wsize, char *s)
8663 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
8665 for (i = 1; i < wsize - 1; i++) {
8667 printf("warning: missing closing quote: \"%s\"\n", s);
8676 for (; i < wsize - 1; i++) {
8677 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
8683 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
8684 printf("warning: '%s' truncated\n", w);
8689 static int cmpstringp(const void *p1, const void *p2)
8691 return strcmp(*(char * const *)p1, *(char * const *)p2);
8694 static int is_xref_needed(char *p, char **rlist, int rlist_len)
8699 if (strstr(p, "..."))
8700 // unable to determine, assume needed
8703 if (*p == '.') // .text, .data, ...
8704 // ref from other data or non-function -> no
8707 p2 = strpbrk(p, "+:\r\n\x18");
8710 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8711 // referenced from removed code
8717 static int ida_xrefs_show_need(FILE *fasm, char *p,
8718 char **rlist, int rlist_len)
8724 p = strrchr(p, ';');
8725 if (p != NULL && *p == ';') {
8726 if (IS_START(p + 2, "sctref"))
8728 if (IS_START(p + 2, "DATA XREF: ")) {
8730 if (is_xref_needed(p, rlist, rlist_len))
8738 if (!my_fgets(line, sizeof(line), fasm))
8740 // non-first line is always indented
8741 if (!my_isblank(line[0]))
8744 // should be no content, just comment
8749 p = strrchr(p, ';');
8752 if (IS_START(p, "sctref")) {
8757 // it's printed once, but no harm to check again
8758 if (IS_START(p, "DATA XREF: "))
8761 if (is_xref_needed(p, rlist, rlist_len)) {
8766 fseek(fasm, pos, SEEK_SET);
8770 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
8772 struct scanned_var *var;
8773 char line[256] = { 0, };
8782 // skip to next data section
8783 while (my_fgets(line, sizeof(line), fasm))
8788 if (*p == 0 || *p == ';')
8791 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
8792 if (*p == 0 || *p == ';')
8795 if (*p != 's' || !IS_START(p, "segment para public"))
8801 if (p == NULL || !IS_START(p, "segment para public"))
8805 if (!IS_START(p, "'DATA'"))
8809 while (my_fgets(line, sizeof(line), fasm))
8814 no_identifier = my_isblank(*p);
8817 if (*p == 0 || *p == ';')
8820 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8821 words[wordc][0] = 0;
8822 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8823 if (*p == 0 || *p == ';') {
8829 if (wordc == 2 && IS(words[1], "ends"))
8834 if (no_identifier) {
8835 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
8836 hg_ref_add(words[2]);
8840 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
8841 // when this starts, we don't need anything from this section
8845 // check refs comment(s)
8846 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
8849 if ((hg_var_cnt & 0xff) == 0) {
8850 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
8851 * (hg_var_cnt + 0x100));
8852 my_assert_not(hg_vars, NULL);
8853 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
8856 var = &hg_vars[hg_var_cnt++];
8857 snprintf(var->name, sizeof(var->name), "%s", words[0]);
8859 // maybe already in seed header?
8860 var->pp = proto_parse(g_fhdr, var->name, 1);
8861 if (var->pp != NULL) {
8862 if (var->pp->is_fptr) {
8863 var->lmod = OPLM_DWORD;
8866 else if (var->pp->is_func)
8868 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
8869 aerr("unhandled C type '%s' for '%s'\n",
8870 var->pp->type.name, var->name);
8876 if (IS(words[1], "dd")) {
8877 var->lmod = OPLM_DWORD;
8878 if (wordc >= 4 && IS(words[2], "offset"))
8879 hg_ref_add(words[3]);
8881 else if (IS(words[1], "dw"))
8882 var->lmod = OPLM_WORD;
8883 else if (IS(words[1], "db")) {
8884 var->lmod = OPLM_BYTE;
8885 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
8886 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
8890 else if (IS(words[1], "dq"))
8891 var->lmod = OPLM_QWORD;
8892 //else if (IS(words[1], "dt"))
8894 aerr("type '%s' not known\n", words[1]);
8902 static void set_label(int i, const char *name)
8908 p = strchr(name, ':');
8912 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
8913 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
8914 g_labels[i] = realloc(g_labels[i], len + 1);
8915 my_assert_not(g_labels[i], NULL);
8916 memcpy(g_labels[i], name, len);
8917 g_labels[i][len] = 0;
8926 static struct chunk_item *func_chunks;
8927 static int func_chunk_cnt;
8928 static int func_chunk_alloc;
8930 static void add_func_chunk(FILE *fasm, const char *name, int line)
8932 if (func_chunk_cnt >= func_chunk_alloc) {
8933 func_chunk_alloc *= 2;
8934 func_chunks = realloc(func_chunks,
8935 func_chunk_alloc * sizeof(func_chunks[0]));
8936 my_assert_not(func_chunks, NULL);
8938 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
8939 func_chunks[func_chunk_cnt].name = strdup(name);
8940 func_chunks[func_chunk_cnt].asmln = line;
8944 static int cmp_chunks(const void *p1, const void *p2)
8946 const struct chunk_item *c1 = p1, *c2 = p2;
8947 return strcmp(c1->name, c2->name);
8950 static void scan_ahead_for_chunks(FILE *fasm)
8960 oldpos = ftell(fasm);
8963 while (my_fgets(line, sizeof(line), fasm))
8974 // get rid of random tabs
8975 for (i = 0; line[i] != 0; i++)
8976 if (line[i] == '\t')
8979 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8982 next_word(words[0], sizeof(words[0]), p);
8983 if (words[0][0] == 0)
8984 aerr("missing name for func chunk?\n");
8986 add_func_chunk(fasm, words[0], asmln);
8988 else if (IS_START(p, "; sctend"))
8994 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8995 words[wordc][0] = 0;
8996 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8997 if (*p == 0 || *p == ';') {
9003 if (wordc == 2 && IS(words[1], "ends"))
9007 fseek(fasm, oldpos, SEEK_SET);
9011 int main(int argc, char *argv[])
9013 FILE *fout, *fasm, *frlist;
9014 struct parsed_data *pd = NULL;
9016 char **rlist = NULL;
9018 int rlist_alloc = 0;
9019 int func_chunks_used = 0;
9020 int func_chunks_sorted = 0;
9021 int func_chunk_i = -1;
9022 long func_chunk_ret = 0;
9023 int func_chunk_ret_ln = 0;
9024 int scanned_ahead = 0;
9026 char words[20][256];
9027 enum opr_lenmod lmod;
9028 char *sctproto = NULL;
9030 int pending_endp = 0;
9032 int skip_code_end = 0;
9033 int skip_warned = 0;
9046 for (arg = 1; arg < argc; arg++) {
9047 if (IS(argv[arg], "-v"))
9049 else if (IS(argv[arg], "-rf"))
9050 g_allow_regfunc = 1;
9051 else if (IS(argv[arg], "-uc"))
9052 g_allow_user_icall = 1;
9053 else if (IS(argv[arg], "-m"))
9055 else if (IS(argv[arg], "-hdr"))
9056 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
9061 if (argc < arg + 3) {
9062 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
9063 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
9065 " -hdr - header generation mode\n"
9066 " -rf - allow unannotated indirect calls\n"
9067 " -uc - allow ind. calls/refs to __usercall\n"
9068 " -m - allow multiple .text sections\n"
9069 "[rlist] is a file with function names to skip,"
9077 asmfn = argv[arg++];
9078 fasm = fopen(asmfn, "r");
9079 my_assert_not(fasm, NULL);
9081 hdrfn = argv[arg++];
9082 g_fhdr = fopen(hdrfn, "r");
9083 my_assert_not(g_fhdr, NULL);
9086 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
9087 my_assert_not(rlist, NULL);
9088 // needs special handling..
9089 rlist[rlist_len++] = "__alloca_probe";
9091 func_chunk_alloc = 32;
9092 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
9093 my_assert_not(func_chunks, NULL);
9095 memset(words, 0, sizeof(words));
9097 for (; arg < argc; arg++) {
9100 frlist = fopen(argv[arg], "r");
9101 my_assert_not(frlist, NULL);
9103 while (my_fgets(line, sizeof(line), frlist)) {
9105 if (*p == 0 || *p == ';')
9108 if (IS_START(p, "#if 0")
9109 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
9113 else if (IS_START(p, "#endif"))
9120 p = next_word(words[0], sizeof(words[0]), p);
9121 if (words[0][0] == 0)
9124 if (rlist_len >= rlist_alloc) {
9125 rlist_alloc = rlist_alloc * 2 + 64;
9126 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
9127 my_assert_not(rlist, NULL);
9129 rlist[rlist_len++] = strdup(words[0]);
9137 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
9139 fout = fopen(argv[arg_out], "w");
9140 my_assert_not(fout, NULL);
9143 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
9144 my_assert_not(g_eqs, NULL);
9146 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
9147 g_label_refs[i].i = -1;
9148 g_label_refs[i].next = NULL;
9152 scan_variables(fasm, rlist, rlist_len);
9154 while (my_fgets(line, sizeof(line), fasm))
9163 // get rid of random tabs
9164 for (i = 0; line[i] != 0; i++)
9165 if (line[i] == '\t')
9170 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
9171 goto do_pending_endp; // eww..
9173 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
9175 static const char *attrs[] = {
9184 // parse IDA's attribute-list comment
9185 g_ida_func_attr = 0;
9188 for (; *p != 0; p = sskip(p)) {
9189 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9190 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9191 g_ida_func_attr |= 1 << i;
9192 p += strlen(attrs[i]);
9196 if (i == ARRAY_SIZE(attrs)) {
9197 anote("unparsed IDA attr: %s\n", p);
9200 if (IS(attrs[i], "fpd=")) {
9201 p = next_word(words[0], sizeof(words[0]), p);
9206 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
9208 static const char *attrs[] = {
9213 // parse manual attribute-list comment
9214 g_sct_func_attr = 0;
9217 for (; *p != 0; p = sskip(p)) {
9218 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9219 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9220 g_sct_func_attr |= 1 << i;
9221 p += strlen(attrs[i]);
9228 // clear_sf=start,len (in dwords)
9229 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
9230 &g_stack_clear_len, &j);
9232 // clear_regmask=<mask>
9233 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
9235 anote("unparsed attr value: %s\n", p);
9240 else if (i == ARRAY_SIZE(attrs)) {
9241 anote("unparsed sct attr: %s\n", p);
9246 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9249 next_word(words[0], sizeof(words[0]), p);
9250 if (words[0][0] == 0)
9251 aerr("missing name for func chunk?\n");
9253 if (!scanned_ahead) {
9254 add_func_chunk(fasm, words[0], asmln);
9255 func_chunks_sorted = 0;
9258 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
9260 if (func_chunk_i >= 0) {
9261 if (func_chunk_i < func_chunk_cnt
9262 && IS(func_chunks[func_chunk_i].name, g_func))
9264 // move on to next chunk
9265 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9267 aerr("seek failed for '%s' chunk #%d\n",
9268 g_func, func_chunk_i);
9269 asmln = func_chunks[func_chunk_i].asmln;
9273 if (func_chunk_ret == 0)
9274 aerr("no return from chunk?\n");
9275 fseek(fasm, func_chunk_ret, SEEK_SET);
9276 asmln = func_chunk_ret_ln;
9282 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
9283 func_chunks_used = 1;
9285 if (IS_START(g_func, "sub_")) {
9286 unsigned long addr = strtoul(p, NULL, 16);
9287 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
9288 if (addr > f_addr && !scanned_ahead) {
9289 //anote("scan_ahead caused by '%s', addr %lx\n",
9291 scan_ahead_for_chunks(fasm);
9293 func_chunks_sorted = 0;
9301 for (i = wordc; i < ARRAY_SIZE(words); i++)
9303 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9304 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9305 if (*p == 0 || *p == ';') {
9310 if (*p != 0 && *p != ';')
9311 aerr("too many words\n");
9313 if (skip_code_end) {
9318 // allow asm patches in comments
9320 if (IS_START(p, "; sctpatch:")) {
9322 if (*p == 0 || *p == ';')
9324 goto parse_words; // lame
9326 if (IS_START(p, "; sctproto:")) {
9327 sctproto = strdup(p + 11);
9329 else if (IS_START(p, "; sctend")) {
9334 else if (IS_START(p, "; sctskip_start")) {
9335 if (in_func && !g_skip_func) {
9337 ops[pi].op = OPP_ABORT;
9338 ops[pi].asmln = asmln;
9344 else if (IS_START(p, "; sctskip_end")) {
9352 awarn("wordc == 0?\n");
9356 // don't care about this:
9357 if (words[0][0] == '.'
9358 || IS(words[0], "include")
9359 || IS(words[0], "assume") || IS(words[1], "segment")
9360 || IS(words[0], "align"))
9366 // do delayed endp processing to collect switch jumptables
9368 if (in_func && !g_skip_func && !end && wordc >= 2
9369 && ((words[0][0] == 'd' && words[0][2] == 0)
9370 || (words[1][0] == 'd' && words[1][2] == 0)))
9373 if (words[1][0] == 'd' && words[1][2] == 0) {
9375 if (g_func_pd_cnt >= pd_alloc) {
9376 pd_alloc = pd_alloc * 2 + 16;
9377 g_func_pd = realloc(g_func_pd,
9378 sizeof(g_func_pd[0]) * pd_alloc);
9379 my_assert_not(g_func_pd, NULL);
9381 pd = &g_func_pd[g_func_pd_cnt];
9383 memset(pd, 0, sizeof(*pd));
9384 strcpy(pd->label, words[0]);
9385 pd->type = OPT_CONST;
9386 pd->lmod = lmod_from_directive(words[1]);
9392 anote("skipping alignment byte?\n");
9395 lmod = lmod_from_directive(words[0]);
9396 if (lmod != pd->lmod)
9397 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
9400 if (pd->count_alloc < pd->count + wordc) {
9401 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
9402 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
9403 my_assert_not(pd->d, NULL);
9405 for (; i < wordc; i++) {
9406 if (IS(words[i], "offset")) {
9407 pd->type = OPT_OFFSET;
9410 p = strchr(words[i], ',');
9413 if (pd->type == OPT_OFFSET)
9414 pd->d[pd->count].u.label = strdup(words[i]);
9416 pd->d[pd->count].u.val = parse_number(words[i], 0);
9417 pd->d[pd->count].bt_i = -1;
9423 if (in_func && !g_skip_func) {
9425 gen_hdr(g_func, pi);
9427 gen_func(fout, g_fhdr, g_func, pi);
9432 g_ida_func_attr = 0;
9433 g_sct_func_attr = 0;
9434 g_stack_clear_start = 0;
9435 g_stack_clear_len = 0;
9441 func_chunks_used = 0;
9444 memset(&ops, 0, pi * sizeof(ops[0]));
9449 for (i = 0; i < g_func_pd_cnt; i++) {
9451 if (pd->type == OPT_OFFSET) {
9452 for (j = 0; j < pd->count; j++)
9453 free(pd->d[j].u.label);
9468 if (IS(words[1], "proc")) {
9470 aerr("proc '%s' while in_func '%s'?\n",
9473 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9475 strcpy(g_func, words[0]);
9476 set_label(0, words[0]);
9481 if (IS(words[1], "endp"))
9484 aerr("endp '%s' while not in_func?\n", words[0]);
9485 if (!IS(g_func, words[0]))
9486 aerr("endp '%s' while in_func '%s'?\n",
9489 aerr("endp '%s' while skipping code\n", words[0]);
9491 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
9492 && ops[0].op == OP_JMP && ops[0].operand[0].segment)
9498 if (!g_skip_func && func_chunks_used) {
9499 // start processing chunks
9500 struct chunk_item *ci, key = { g_func, 0 };
9502 func_chunk_ret = ftell(fasm);
9503 func_chunk_ret_ln = asmln;
9504 if (!func_chunks_sorted) {
9505 qsort(func_chunks, func_chunk_cnt,
9506 sizeof(func_chunks[0]), cmp_chunks);
9507 func_chunks_sorted = 1;
9509 ci = bsearch(&key, func_chunks, func_chunk_cnt,
9510 sizeof(func_chunks[0]), cmp_chunks);
9512 aerr("'%s' needs chunks, but none found\n", g_func);
9513 func_chunk_i = ci - func_chunks;
9514 for (; func_chunk_i > 0; func_chunk_i--)
9515 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
9518 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9520 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
9521 asmln = func_chunks[func_chunk_i].asmln;
9529 if (wordc == 2 && IS(words[1], "ends")) {
9533 goto do_pending_endp;
9537 // scan for next text segment
9538 while (my_fgets(line, sizeof(line), fasm)) {
9541 if (*p == 0 || *p == ';')
9544 if (strstr(p, "segment para public 'CODE' use32"))
9551 p = strchr(words[0], ':');
9553 set_label(pi, words[0]);
9557 if (!in_func || g_skip_func || skip_code) {
9558 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
9560 anote("skipping from '%s'\n", g_labels[pi]);
9564 g_labels[pi] = NULL;
9568 if (wordc > 1 && IS(words[1], "="))
9571 aerr("unhandled equ, wc=%d\n", wordc);
9572 if (g_eqcnt >= eq_alloc) {
9574 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
9575 my_assert_not(g_eqs, NULL);
9578 len = strlen(words[0]);
9579 if (len > sizeof(g_eqs[0].name) - 1)
9580 aerr("equ name too long: %d\n", len);
9581 strcpy(g_eqs[g_eqcnt].name, words[0]);
9583 if (!IS(words[3], "ptr"))
9584 aerr("unhandled equ\n");
9585 if (IS(words[2], "dword"))
9586 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
9587 else if (IS(words[2], "word"))
9588 g_eqs[g_eqcnt].lmod = OPLM_WORD;
9589 else if (IS(words[2], "byte"))
9590 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
9591 else if (IS(words[2], "qword"))
9592 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
9594 aerr("bad lmod: '%s'\n", words[2]);
9596 g_eqs[g_eqcnt].offset = parse_number(words[4], 0);
9601 if (pi >= ARRAY_SIZE(ops))
9602 aerr("too many ops\n");
9604 parse_op(&ops[pi], words, wordc);
9606 ops[pi].datap = sctproto;
9621 // vim:ts=2:shiftwidth=2:expandtab