5 * This work is licensed under the terms of 3-clause BSD license.
6 * See COPYING file in the top-level directory.
8 * recognized asm hint comments:
9 * sctattr - function attributes (see code)
10 * sctend - force end of function/chunk
11 * sctpatch: <p> - replace current asm line with <p>
12 * sctproto: <p> - prototype of ref'd function or struct
13 * sctref - variable is referenced, make global
14 * sctskip_start - start of skipped code chunk (inclusive)
15 * sctskip_end - end of skipped code chunk (inclusive)
25 #include "my_assert.h"
29 #include "protoparse.h"
31 static const char *asmfn;
35 #define anote(fmt, ...) \
36 printf("%s:%d: note: " fmt, asmfn, asmln, ##__VA_ARGS__)
37 #define awarn(fmt, ...) \
38 printf("%s:%d: warning: " fmt, asmfn, asmln, ##__VA_ARGS__)
39 #define aerr(fmt, ...) do { \
40 printf("%s:%d: error: " fmt, asmfn, asmln, ##__VA_ARGS__); \
45 #include "masm_tools.h"
48 OPF_RMD = (1 << 0), /* removed from code generation */
49 OPF_DATA = (1 << 1), /* data processing - writes to dst opr */
50 OPF_FLAGS = (1 << 2), /* sets flags */
51 OPF_JMP = (1 << 3), /* branch, call */
52 OPF_CJMP = (1 << 4), /* cond. branch (cc or jecxz/loop) */
53 OPF_CC = (1 << 5), /* uses flags */
54 OPF_TAIL = (1 << 6), /* ret or tail call */
55 OPF_RSAVE = (1 << 7), /* push/pop is local reg save/load */
56 OPF_REP = (1 << 8), /* prefixed by rep */
57 OPF_REPZ = (1 << 9), /* rep is repe/repz */
58 OPF_REPNZ = (1 << 10), /* rep is repne/repnz */
59 OPF_FARG = (1 << 11), /* push collected as func arg */
60 OPF_FARGNR = (1 << 12), /* push collected as func arg (no reuse) */
61 OPF_EBP_S = (1 << 13), /* ebp used as scratch here, not BP */
62 OPF_DF = (1 << 14), /* DF flag set */
63 OPF_ATAIL = (1 << 15), /* tail call with reused arg frame */
64 OPF_32BIT = (1 << 16), /* enough to do 32bit for this op */
65 OPF_LOCK = (1 << 17), /* op has lock prefix */
66 OPF_VAPUSH = (1 << 18), /* vararg ptr push (as call arg) */
67 OPF_DONE = (1 << 19), /* already fully handled by analysis */
68 OPF_PPUSH = (1 << 20), /* part of complex push-pop graph */
69 OPF_NOREGS = (1 << 21), /* don't track regs of this op */
70 OPF_FPUSH = (1 << 22), /* pushes x87 stack */
71 OPF_FPOP = (1 << 23), /* pops x87 stack */
72 OPF_FPOPP = (1 << 24), /* pops x87 stack twice */
73 OPF_FSHIFT = (1 << 25), /* x87 stack shift is actually needed */
74 OPF_FINT = (1 << 26), /* integer float op arg */
165 // pseudo-ops for lib calls
184 // must be sorted (larger len must be further in enum)
193 #define MAX_EXITS 128
195 #define MAX_OPERANDS 3
198 #define OPR_INIT(type_, lmod_, reg_) \
199 { type_, lmod_, reg_, }
203 enum opr_lenmod lmod;
205 unsigned int is_ptr:1; // pointer in C
206 unsigned int is_array:1; // array in C
207 unsigned int type_from_var:1; // .. in header, sometimes wrong
208 unsigned int size_mismatch:1; // type override differs from C
209 unsigned int size_lt:1; // type override is larger than C
210 unsigned int segment:7; // had segment override (enum segment)
211 const struct parsed_proto *pp; // for OPT_LABEL
218 struct parsed_opr operand[MAX_OPERANDS];
221 unsigned char pfo_inv;
222 unsigned char operand_cnt;
223 unsigned char p_argnum; // arg push: altered before call arg #
224 unsigned char p_arggrp; // arg push: arg group # for above
225 unsigned char p_argpass;// arg push: arg of host func
226 short p_argnext;// arg push: same arg pushed elsewhere or -1
227 int regmask_src; // all referensed regs
229 int pfomask; // flagop: parsed_flag_op that can't be delayed
230 int cc_scratch; // scratch storage during analysis
231 int bt_i; // branch target for branches
232 struct parsed_data *btj;// branch targets for jumptables
233 struct parsed_proto *pp;// parsed_proto for OP_CALL
239 // on start: function/data type hint (sctproto)
241 // (OPF_CC) - points to one of (OPF_FLAGS) that affects cc op
242 // OP_PUSH - points to OP_POP in complex push/pop graph
243 // OP_POP - points to OP_PUSH in simple push/pop pair
244 // OP_FCOM - needed_status_word_bits | (is_z_check << 16)
248 enum opr_lenmod lmod;
255 enum opr_lenmod lmod;
269 struct label_ref *next;
273 IDAFA_BP_FRAME = (1 << 0),
274 IDAFA_LIB_FUNC = (1 << 1),
275 IDAFA_STATIC = (1 << 2),
276 IDAFA_NORETURN = (1 << 3),
277 IDAFA_THUNK = (1 << 4),
278 IDAFA_FPD = (1 << 5),
283 SCTFA_CLEAR_SF = (1 << 0), // clear stack frame
284 SCTFA_CLEAR_REGS = (1 << 1), // clear registers (mask)
285 SCTFA_RM_REGS = (1 << 2), // don't emit regs
286 SCTFA_NOWARN = (1 << 3), // don't try to detect problems
308 // note: limited to 32k due to p_argnext
310 #define MAX_ARG_GRP 2
312 static struct parsed_op ops[MAX_OPS];
313 static struct parsed_equ *g_eqs;
315 static char *g_labels[MAX_OPS];
316 static struct label_ref g_label_refs[MAX_OPS];
317 static const struct parsed_proto *g_func_pp;
318 static struct parsed_data *g_func_pd;
319 static int g_func_pd_cnt;
320 static int g_func_lmods;
321 static char g_func[256];
322 static char g_comment[256];
323 static int g_bp_frame;
324 static int g_sp_frame;
325 static int g_stack_frame_used;
326 static int g_stack_fsz;
327 static int g_seh_found;
328 static int g_seh_size;
329 static int g_ida_func_attr;
330 static int g_sct_func_attr;
331 static int g_stack_clear_start; // in dwords
332 static int g_stack_clear_len;
333 static int g_regmask_init;
334 static int g_regmask_rm;
335 static int g_skip_func;
336 static int g_allow_regfunc;
337 static int g_allow_user_icall;
338 static int g_quiet_pp;
339 static int g_header_mode;
341 #define ferr(op_, fmt, ...) do { \
342 printf("%s:%d: error %u: [%s] '%s': " fmt, asmfn, (op_)->asmln, \
343 __LINE__, g_func, dump_op(op_), ##__VA_ARGS__); \
347 #define fnote(op_, fmt, ...) \
348 printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
349 dump_op(op_), ##__VA_ARGS__)
351 #define ferr_assert(op_, cond) do { \
352 if (!(cond)) ferr(op_, "assertion '%s' failed\n", #cond); \
355 #define IS_OP_INDIRECT_CALL(op_) \
356 ((op_)->op == OP_CALL && (op_)->operand[0].type != OPT_LABEL)
358 const char *regs_r32[] = {
359 "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
360 // not r32, but list here for easy parsing and printing
361 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
362 "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"
364 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
365 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
366 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
372 xMM0, xMM1, xMM2, xMM3, // mmx
373 xMM4, xMM5, xMM6, xMM7,
374 xST0, xST1, xST2, xST3, // x87
375 xST4, xST5, xST6, xST7,
378 #define mxAX (1 << xAX)
379 #define mxCX (1 << xCX)
380 #define mxDX (1 << xDX)
381 #define mxSP (1 << xSP)
382 #define mxST0 (1 << xST0)
383 #define mxST1 (1 << xST1)
384 #define mxST1_0 (mxST1 | mxST0)
385 #define mxST7_2 (0xfc << xST0)
386 #define mxSTa (0xff << xST0)
388 // possible basic comparison types (without inversion)
389 enum parsed_flag_op {
393 PFO_BE, // 6 CF=1||ZF=1
397 PFO_LE, // e ZF=1||SF!=OF
400 #define PFOB_O (1 << PFO_O)
401 #define PFOB_C (1 << PFO_C)
402 #define PFOB_Z (1 << PFO_Z)
403 #define PFOB_S (1 << PFO_S)
405 static const char *parsed_flag_op_names[] = {
406 "o", "c", "z", "be", "s", "p", "l", "le"
409 static int char_array_i(const char *array[], size_t len, const char *s)
413 for (i = 0; i < len; i++)
420 static void printf_number(char *buf, size_t buf_size,
421 unsigned long number)
423 // output in C-friendly form
424 snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
427 static int check_segment_prefix(const char *s)
429 if (s[0] == 0 || s[1] != 's' || s[2] != ':')
433 case 'c': return SEG_CS;
434 case 'd': return SEG_DS;
435 case 's': return SEG_SS;
436 case 'e': return SEG_ES;
437 case 'f': return SEG_FS;
438 case 'g': return SEG_GS;
443 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
447 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
449 *reg_lmod = OPLM_QWORD;
453 *reg_lmod = OPLM_DWORD;
456 reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
458 *reg_lmod = OPLM_WORD;
461 reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
463 *reg_lmod = OPLM_BYTE;
466 reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
468 *reg_lmod = OPLM_BYTE;
475 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
477 enum opr_lenmod lmod;
490 while (my_isblank(*s))
492 for (; my_issep(*s); d++, s++)
494 while (my_isblank(*s))
498 // skip '?s:' prefixes
499 if (check_segment_prefix(s))
502 s = next_idt(w, sizeof(w), s);
507 reg = parse_reg(&lmod, w);
509 *regmask |= 1 << reg;
513 if ('0' <= w[0] && w[0] <= '9') {
514 number = parse_number(w, 0);
515 printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
519 // probably some label/identifier - pass
522 snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
526 strcpy(name, cvtbuf);
531 static int is_reg_in_str(const char *s)
535 if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
538 for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
539 if (!strncmp(s, regs_r32[i], 3))
545 static const char *parse_stack_el(const char *name, char *extra_reg,
546 int *base_val, int early_try)
548 const char *p, *p2, *s;
554 if (g_bp_frame || early_try)
557 if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
559 if (extra_reg != NULL) {
560 strncpy(extra_reg, name, 3);
565 if (IS_START(p, "ebp+")) {
569 if (p2 != NULL && is_reg_in_str(p)) {
570 if (extra_reg != NULL) {
571 strncpy(extra_reg, p, p2 - p);
572 extra_reg[p2 - p] = 0;
577 if (!('0' <= *p && *p <= '9'))
584 if (!IS_START(name, "esp+"))
590 if (is_reg_in_str(s)) {
591 if (extra_reg != NULL) {
592 strncpy(extra_reg, s, p - s);
593 extra_reg[p - s] = 0;
598 aerr("%s IDA stackvar not set?\n", __func__);
600 if ('0' <= *s && *s <= '9') {
601 if (s[0] == '0' && s[1] == 'x')
604 if (len < sizeof(buf) - 1) {
605 strncpy(buf, s, len);
608 val = strtol(buf, &endp, 16);
609 if (val == 0 || *endp != 0 || errno != 0) {
610 aerr("%s num parse fail for '%s'\n", __func__, buf);
617 // probably something like [esp+arg_4+2]
625 if ('0' <= *p && *p <= '9')
628 if (base_val != NULL)
633 static int guess_lmod_from_name(struct parsed_opr *opr)
635 if (IS_START(opr->name, "dword_") || IS_START(opr->name, "off_")) {
636 opr->lmod = OPLM_DWORD;
639 if (IS_START(opr->name, "word_")) {
640 opr->lmod = OPLM_WORD;
643 if (IS_START(opr->name, "byte_")) {
644 opr->lmod = OPLM_BYTE;
647 if (IS_START(opr->name, "qword_")) {
648 opr->lmod = OPLM_QWORD;
654 static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
655 const struct parsed_type *c_type)
657 static const char *qword_types[] = {
658 "uint64_t", "int64_t", "__int64",
660 static const char *dword_types[] = {
661 "uint32_t", "int", "_DWORD", "UINT_PTR", "DWORD",
662 "WPARAM", "LPARAM", "UINT", "__int32",
663 "LONG", "HIMC", "BOOL", "size_t",
666 static const char *word_types[] = {
667 "uint16_t", "int16_t", "_WORD", "WORD",
668 "unsigned __int16", "__int16",
670 static const char *byte_types[] = {
671 "uint8_t", "int8_t", "char",
672 "unsigned __int8", "__int8", "BYTE", "_BYTE",
674 // structures.. deal the same as with _UNKNOWN for now
680 if (c_type->is_ptr) {
685 n = skip_type_mod(c_type->name);
687 for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
688 if (IS(n, dword_types[i])) {
694 for (i = 0; i < ARRAY_SIZE(word_types); i++) {
695 if (IS(n, word_types[i])) {
701 for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
702 if (IS(n, byte_types[i])) {
708 for (i = 0; i < ARRAY_SIZE(qword_types); i++) {
709 if (IS(n, qword_types[i])) {
718 static char *default_cast_to(char *buf, size_t buf_size,
719 struct parsed_opr *opr)
723 if (!opr->is_ptr || strchr(opr->name, '['))
725 if (opr->pp == NULL || opr->pp->type.name == NULL
728 snprintf(buf, buf_size, "%s", "(void *)");
732 snprintf(buf, buf_size, "(%s)", opr->pp->type.name);
736 static enum opr_type lmod_from_directive(const char *d)
740 else if (IS(d, "dw"))
742 else if (IS(d, "db"))
745 aerr("unhandled directive: '%s'\n", d);
749 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
755 *regmask |= 1 << reg;
758 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
761 static int parse_operand(struct parsed_opr *opr,
762 int *regmask, int *regmask_indirect,
763 char words[16][256], int wordc, int w, unsigned int op_flags)
765 const struct parsed_proto *pp = NULL;
766 enum opr_lenmod tmplmod;
767 unsigned long number;
775 aerr("parse_operand w %d, wordc %d\n", w, wordc);
779 for (i = w; i < wordc; i++) {
780 len = strlen(words[i]);
781 if (words[i][len - 1] == ',') {
782 words[i][len - 1] = 0;
788 wordc_in = wordc - w;
790 if ((op_flags & OPF_JMP) && wordc_in > 0
791 && !('0' <= words[w][0] && words[w][0] <= '9'))
793 const char *label = NULL;
795 if (wordc_in == 3 && !strncmp(words[w], "near", 4)
796 && IS(words[w + 1], "ptr"))
797 label = words[w + 2];
798 else if (wordc_in == 2 && IS(words[w], "short"))
799 label = words[w + 1];
800 else if (wordc_in == 1
801 && strchr(words[w], '[') == NULL
802 && parse_reg(&tmplmod, words[w]) < 0)
806 opr->type = OPT_LABEL;
807 ret = check_segment_prefix(label);
812 strcpy(opr->name, label);
818 if (IS(words[w + 1], "ptr")) {
819 if (IS(words[w], "dword"))
820 opr->lmod = OPLM_DWORD;
821 else if (IS(words[w], "word"))
822 opr->lmod = OPLM_WORD;
823 else if (IS(words[w], "byte"))
824 opr->lmod = OPLM_BYTE;
825 else if (IS(words[w], "qword"))
826 opr->lmod = OPLM_QWORD;
828 aerr("type parsing failed\n");
830 wordc_in = wordc - w;
835 if (IS(words[w], "offset")) {
836 opr->type = OPT_OFFSET;
837 opr->lmod = OPLM_DWORD;
838 strcpy(opr->name, words[w + 1]);
839 pp = proto_parse(g_fhdr, opr->name, 1);
842 if (IS(words[w], "(offset")) {
843 p = strchr(words[w + 1], ')');
845 aerr("parse of bracketed offset failed\n");
847 opr->type = OPT_OFFSET;
848 strcpy(opr->name, words[w + 1]);
854 aerr("parse_operand 1 word expected\n");
856 ret = check_segment_prefix(words[w]);
859 memmove(words[w], words[w] + 3, strlen(words[w]) - 2);
860 if (ret == SEG_FS && IS(words[w], "0"))
863 strcpy(opr->name, words[w]);
865 if (words[w][0] == '[') {
866 opr->type = OPT_REGMEM;
867 ret = sscanf(words[w], "[%[^]]]", opr->name);
869 aerr("[] parse failure\n");
871 parse_indmode(opr->name, regmask_indirect, 1);
872 if (opr->lmod == OPLM_UNSPEC
873 && parse_stack_el(opr->name, NULL, NULL, 1))
876 struct parsed_equ *eq =
877 equ_find(NULL, parse_stack_el(opr->name, NULL, NULL, 1), &i);
879 opr->lmod = eq->lmod;
881 // might be unaligned access
882 g_func_lmods |= 1 << OPLM_BYTE;
886 else if (strchr(words[w], '[')) {
888 p = strchr(words[w], '[');
889 opr->type = OPT_REGMEM;
890 parse_indmode(p, regmask_indirect, 0);
891 strncpy(buf, words[w], p - words[w]);
892 buf[p - words[w]] = 0;
893 pp = proto_parse(g_fhdr, buf, 1);
896 else if (('0' <= words[w][0] && words[w][0] <= '9')
897 || words[w][0] == '-')
899 number = parse_number(words[w], 0);
900 opr->type = OPT_CONST;
902 printf_number(opr->name, sizeof(opr->name), number);
906 ret = parse_reg(&tmplmod, opr->name);
908 setup_reg_opr(opr, ret, tmplmod, regmask);
912 // most likely var in data segment
913 opr->type = OPT_LABEL;
914 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
918 if (pp->is_fptr || pp->is_func) {
919 opr->lmod = OPLM_DWORD;
923 tmplmod = OPLM_UNSPEC;
924 if (!guess_lmod_from_c_type(&tmplmod, &pp->type))
925 anote("unhandled C type '%s' for '%s'\n",
926 pp->type.name, opr->name);
928 if (opr->lmod == OPLM_UNSPEC) {
930 opr->type_from_var = 1;
932 else if (opr->lmod != tmplmod) {
933 opr->size_mismatch = 1;
934 if (tmplmod < opr->lmod)
937 opr->is_ptr = pp->type.is_ptr;
939 opr->is_array = pp->type.is_array;
943 if (opr->lmod == OPLM_UNSPEC)
944 guess_lmod_from_name(opr);
948 static const struct {
953 { "repe", OPF_REP|OPF_REPZ },
954 { "repz", OPF_REP|OPF_REPZ },
955 { "repne", OPF_REP|OPF_REPNZ },
956 { "repnz", OPF_REP|OPF_REPNZ },
957 { "lock", OPF_LOCK }, // ignored for now..
960 #define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
962 static const struct {
965 unsigned short minopr;
966 unsigned short maxopr;
969 unsigned char pfo_inv;
971 { "nop", OP_NOP, 0, 0, 0 },
972 { "push", OP_PUSH, 1, 1, 0 },
973 { "pop", OP_POP, 1, 1, OPF_DATA },
974 { "pusha",OP_PUSHA, 0, 0, 0 },
975 { "popa", OP_POPA, 0, 0, OPF_DATA },
976 { "leave",OP_LEAVE, 0, 0, OPF_DATA },
977 { "mov" , OP_MOV, 2, 2, OPF_DATA },
978 { "lea", OP_LEA, 2, 2, OPF_DATA },
979 { "movzx",OP_MOVZX, 2, 2, OPF_DATA },
980 { "movsx",OP_MOVSX, 2, 2, OPF_DATA },
981 { "xchg", OP_XCHG, 2, 2, OPF_DATA },
982 { "not", OP_NOT, 1, 1, OPF_DATA },
983 { "xlat", OP_XLAT, 0, 0, OPF_DATA },
984 { "cdq", OP_CDQ, 0, 0, OPF_DATA },
985 { "bswap",OP_BSWAP, 1, 1, OPF_DATA },
986 { "lodsb",OP_LODS, 0, 0, OPF_DATA },
987 { "lodsw",OP_LODS, 0, 0, OPF_DATA },
988 { "lodsd",OP_LODS, 0, 0, OPF_DATA },
989 { "stosb",OP_STOS, 0, 0, OPF_DATA },
990 { "stosw",OP_STOS, 0, 0, OPF_DATA },
991 { "stosd",OP_STOS, 0, 0, OPF_DATA },
992 { "movsb",OP_MOVS, 0, 0, OPF_DATA },
993 { "movsw",OP_MOVS, 0, 0, OPF_DATA },
994 { "movsd",OP_MOVS, 0, 0, OPF_DATA },
995 { "cmpsb",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
996 { "cmpsw",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
997 { "cmpsd",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
998 { "scasb",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
999 { "scasw",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
1000 { "scasd",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
1001 { "std", OP_STD, 0, 0, OPF_DATA }, // special flag
1002 { "cld", OP_CLD, 0, 0, OPF_DATA },
1003 { "add", OP_ADD, 2, 2, OPF_DATA|OPF_FLAGS },
1004 { "sub", OP_SUB, 2, 2, OPF_DATA|OPF_FLAGS },
1005 { "and", OP_AND, 2, 2, OPF_DATA|OPF_FLAGS },
1006 { "or", OP_OR, 2, 2, OPF_DATA|OPF_FLAGS },
1007 { "xor", OP_XOR, 2, 2, OPF_DATA|OPF_FLAGS },
1008 { "shl", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
1009 { "shr", OP_SHR, 2, 2, OPF_DATA|OPF_FLAGS },
1010 { "sal", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
1011 { "sar", OP_SAR, 2, 2, OPF_DATA|OPF_FLAGS },
1012 { "shld", OP_SHLD, 3, 3, OPF_DATA|OPF_FLAGS },
1013 { "shrd", OP_SHRD, 3, 3, OPF_DATA|OPF_FLAGS },
1014 { "rol", OP_ROL, 2, 2, OPF_DATA|OPF_FLAGS },
1015 { "ror", OP_ROR, 2, 2, OPF_DATA|OPF_FLAGS },
1016 { "rcl", OP_RCL, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1017 { "rcr", OP_RCR, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1018 { "adc", OP_ADC, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1019 { "sbb", OP_SBB, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1020 { "bsf", OP_BSF, 2, 2, OPF_DATA|OPF_FLAGS },
1021 { "bsr", OP_BSR, 2, 2, OPF_DATA|OPF_FLAGS },
1022 { "inc", OP_INC, 1, 1, OPF_DATA|OPF_FLAGS },
1023 { "dec", OP_DEC, 1, 1, OPF_DATA|OPF_FLAGS },
1024 { "neg", OP_NEG, 1, 1, OPF_DATA|OPF_FLAGS },
1025 { "mul", OP_MUL, 1, 1, OPF_DATA|OPF_FLAGS },
1026 { "imul", OP_IMUL, 1, 3, OPF_DATA|OPF_FLAGS },
1027 { "div", OP_DIV, 1, 1, OPF_DATA|OPF_FLAGS },
1028 { "idiv", OP_IDIV, 1, 1, OPF_DATA|OPF_FLAGS },
1029 { "test", OP_TEST, 2, 2, OPF_FLAGS },
1030 { "cmp", OP_CMP, 2, 2, OPF_FLAGS },
1031 { "retn", OP_RET, 0, 1, OPF_TAIL },
1032 { "call", OP_CALL, 1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
1033 { "jmp", OP_JMP, 1, 1, OPF_JMP },
1034 { "jecxz",OP_JECXZ, 1, 1, OPF_JMP|OPF_CJMP },
1035 { "loop", OP_LOOP, 1, 1, OPF_JMP|OPF_CJMP|OPF_DATA },
1036 { "jo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 0 }, // 70 OF=1
1037 { "jno", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 1 }, // 71 OF=0
1038 { "jc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72 CF=1
1039 { "jb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72
1040 { "jnc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73 CF=0
1041 { "jnb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1042 { "jae", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1043 { "jz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74 ZF=1
1044 { "je", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74
1045 { "jnz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75 ZF=0
1046 { "jne", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75
1047 { "jbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76 CF=1||ZF=1
1048 { "jna", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76
1049 { "ja", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77 CF=0&&ZF=0
1050 { "jnbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77
1051 { "js", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 0 }, // 78 SF=1
1052 { "jns", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 1 }, // 79 SF=0
1053 { "jp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a PF=1
1054 { "jpe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a
1055 { "jnp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b PF=0
1056 { "jpo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b
1057 { "jl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c SF!=OF
1058 { "jnge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c
1059 { "jge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d SF=OF
1060 { "jnl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d
1061 { "jle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e ZF=1||SF!=OF
1062 { "jng", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e
1063 { "jg", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f ZF=0&&SF=OF
1064 { "jnle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f
1065 { "seto", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 0 },
1066 { "setno", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 1 },
1067 { "setc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1068 { "setb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1069 { "setnc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1070 { "setae", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1071 { "setnb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1072 { "setz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1073 { "sete", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1074 { "setnz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1075 { "setne", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1076 { "setbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1077 { "setna", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1078 { "seta", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1079 { "setnbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1080 { "sets", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 0 },
1081 { "setns", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 1 },
1082 { "setp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1083 { "setpe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1084 { "setnp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1085 { "setpo", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1086 { "setl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1087 { "setnge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1088 { "setge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1089 { "setnl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1090 { "setle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1091 { "setng", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1092 { "setg", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1093 { "setnle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1095 { "fld", OP_FLD, 1, 1, OPF_FPUSH },
1096 { "fild", OP_FILD, 1, 1, OPF_FPUSH|OPF_FINT },
1097 { "fld1", OP_FLDc, 0, 0, OPF_FPUSH },
1098 { "fldl2t", OP_FLDc, 0, 0, OPF_FPUSH },
1099 { "fldl2e", OP_FLDc, 0, 0, OPF_FPUSH },
1100 { "fldpi", OP_FLDc, 0, 0, OPF_FPUSH },
1101 { "fldlg2", OP_FLDc, 0, 0, OPF_FPUSH },
1102 { "fldln2", OP_FLDc, 0, 0, OPF_FPUSH },
1103 { "fldz", OP_FLDc, 0, 0, OPF_FPUSH },
1104 { "fst", OP_FST, 1, 1, 0 },
1105 { "fstp", OP_FST, 1, 1, OPF_FPOP },
1106 { "fist", OP_FIST, 1, 1, OPF_FINT },
1107 { "fistp", OP_FIST, 1, 1, OPF_FPOP|OPF_FINT },
1108 { "fadd", OP_FADD, 0, 2, 0 },
1109 { "faddp", OP_FADD, 0, 2, OPF_FPOP },
1110 { "fdiv", OP_FDIV, 0, 2, 0 },
1111 { "fdivp", OP_FDIV, 0, 2, OPF_FPOP },
1112 { "fmul", OP_FMUL, 0, 2, 0 },
1113 { "fmulp", OP_FMUL, 0, 2, OPF_FPOP },
1114 { "fsub", OP_FSUB, 0, 2, 0 },
1115 { "fsubp", OP_FSUB, 0, 2, OPF_FPOP },
1116 { "fdivr", OP_FDIVR, 0, 2, 0 },
1117 { "fdivrp", OP_FDIVR, 0, 2, OPF_FPOP },
1118 { "fsubr", OP_FSUBR, 0, 2, 0 },
1119 { "fsubrp", OP_FSUBR, 0, 2, OPF_FPOP },
1120 { "fiadd", OP_FIADD, 1, 1, OPF_FINT },
1121 { "fidiv", OP_FIDIV, 1, 1, OPF_FINT },
1122 { "fimul", OP_FIMUL, 1, 1, OPF_FINT },
1123 { "fisub", OP_FISUB, 1, 1, OPF_FINT },
1124 { "fidivr", OP_FIDIVR, 1, 1, OPF_FINT },
1125 { "fisubr", OP_FISUBR, 1, 1, OPF_FINT },
1126 { "fcom", OP_FCOM, 0, 1, 0 },
1127 { "fcomp", OP_FCOM, 0, 1, OPF_FPOP },
1128 { "fcompp", OP_FCOM, 0, 0, OPF_FPOPP },
1129 { "fucom", OP_FCOM, 0, 1, 0 },
1130 { "fucomp", OP_FCOM, 0, 1, OPF_FPOP },
1131 { "fucompp",OP_FCOM, 0, 0, OPF_FPOPP },
1132 { "fnstsw", OP_FNSTSW, 1, 1, OPF_DATA },
1133 { "fchs", OP_FCHS, 0, 0, 0 },
1134 { "fcos", OP_FCOS, 0, 0, 0 },
1135 { "fpatan", OP_FPATAN, 0, 0, OPF_FPOP },
1136 { "fptan", OP_FPTAN, 0, 0, OPF_FPUSH },
1137 { "fsin", OP_FSIN, 0, 0, 0 },
1138 { "fsqrt", OP_FSQRT, 0, 0, 0 },
1139 { "fxch", OP_FXCH, 1, 1, 0 },
1140 { "fyl2x", OP_FYL2X, 0, 0, OPF_FPOP },
1142 { "emms", OP_EMMS, 0, 0, OPF_DATA },
1143 { "movq", OP_MOV, 2, 2, OPF_DATA },
1144 // pseudo-ops for lib calls
1145 { "_allshl",OPP_ALLSHL },
1146 { "_allshr",OPP_ALLSHR },
1147 { "_ftol", OPP_FTOL },
1148 { "_CIpow", OPP_CIPOW },
1149 { "abort", OPP_ABORT },
1154 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
1156 enum opr_lenmod lmod = OPLM_UNSPEC;
1157 int prefix_flags = 0;
1165 for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
1166 if (IS(words[w], pref_table[i].name)) {
1167 prefix_flags = pref_table[i].flags;
1174 aerr("lone prefix: '%s'\n", words[0]);
1179 for (i = 0; i < ARRAY_SIZE(op_table); i++) {
1180 if (IS(words[w], op_table[i].name))
1184 if (i == ARRAY_SIZE(op_table)) {
1186 aerr("unhandled op: '%s'\n", words[0]);
1191 op->op = op_table[i].op;
1192 op->flags = op_table[i].flags | prefix_flags;
1193 op->pfo = op_table[i].pfo;
1194 op->pfo_inv = op_table[i].pfo_inv;
1195 op->regmask_src = op->regmask_dst = 0;
1198 if (op->op == OP_UD2)
1201 for (opr = 0; opr < op_table[i].maxopr; opr++) {
1202 if (opr >= op_table[i].minopr && w >= wordc)
1205 regmask = regmask_ind = 0;
1206 w = parse_operand(&op->operand[opr], ®mask, ®mask_ind,
1207 words, wordc, w, op->flags);
1209 if (opr == 0 && (op->flags & OPF_DATA))
1210 op->regmask_dst = regmask;
1212 op->regmask_src |= regmask;
1213 op->regmask_src |= regmask_ind;
1215 if (op->operand[opr].lmod != OPLM_UNSPEC)
1216 g_func_lmods |= 1 << op->operand[opr].lmod;
1220 aerr("parse_op %s incomplete: %d/%d\n",
1221 words[0], w, wordc);
1224 op->operand_cnt = opr;
1225 if (!strncmp(op_table[i].name, "set", 3))
1226 op->operand[0].lmod = OPLM_BYTE;
1229 // first operand is not dst
1232 op->regmask_src |= op->regmask_dst;
1233 op->regmask_dst = 0;
1236 // first operand is src too
1249 op->regmask_src |= op->regmask_dst;
1254 op->regmask_src |= op->regmask_dst;
1255 op->regmask_dst |= op->regmask_src;
1261 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1262 && op->operand[0].lmod == op->operand[1].lmod
1263 && op->operand[0].reg == op->operand[1].reg
1264 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1266 op->regmask_src = 0;
1269 op->regmask_src |= op->regmask_dst;
1272 // ops with implicit argumets
1274 op->operand_cnt = 2;
1275 setup_reg_opr(&op->operand[0], xAX, OPLM_BYTE, &op->regmask_src);
1276 op->regmask_dst = op->regmask_src;
1277 setup_reg_opr(&op->operand[1], xBX, OPLM_DWORD, &op->regmask_src);
1281 op->operand_cnt = 2;
1282 setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
1283 setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
1289 if (words[op_w][4] == 'b')
1291 else if (words[op_w][4] == 'w')
1293 else if (words[op_w][4] == 'd')
1296 op->regmask_src = 0;
1297 setup_reg_opr(&op->operand[j++], op->op == OP_LODS ? xSI : xDI,
1298 OPLM_DWORD, &op->regmask_src);
1299 op->regmask_dst = op->regmask_src;
1300 setup_reg_opr(&op->operand[j++], xAX, lmod,
1301 op->op == OP_LODS ? &op->regmask_dst : &op->regmask_src);
1302 if (op->flags & OPF_REP) {
1303 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1304 op->regmask_dst |= 1 << xCX;
1306 op->operand_cnt = j;
1311 if (words[op_w][4] == 'b')
1313 else if (words[op_w][4] == 'w')
1315 else if (words[op_w][4] == 'd')
1318 op->regmask_src = 0;
1319 // note: lmod is not correct, don't have where to place it
1320 setup_reg_opr(&op->operand[j++], xDI, lmod, &op->regmask_src);
1321 setup_reg_opr(&op->operand[j++], xSI, OPLM_DWORD, &op->regmask_src);
1322 if (op->flags & OPF_REP)
1323 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1324 op->operand_cnt = j;
1325 op->regmask_dst = op->regmask_src;
1329 op->regmask_dst = 1 << xCX;
1332 op->operand_cnt = 2;
1333 op->regmask_src = 1 << xCX;
1334 op->operand[1].type = OPT_REG;
1335 op->operand[1].reg = xCX;
1336 op->operand[1].lmod = OPLM_DWORD;
1340 if (op->operand_cnt == 2) {
1341 if (op->operand[0].type != OPT_REG)
1342 aerr("reg expected\n");
1343 op->regmask_src |= 1 << op->operand[0].reg;
1345 if (op->operand_cnt != 1)
1350 if (op->operand[0].lmod == OPLM_UNSPEC)
1351 op->operand[0].lmod = OPLM_DWORD;
1352 op->regmask_src = mxAX | op->regmask_dst;
1353 op->regmask_dst = mxAX;
1354 if (op->operand[0].lmod != OPLM_BYTE)
1355 op->regmask_dst |= mxDX;
1360 // we could set up operands for edx:eax, but there is no real need to
1361 // (see is_opr_modified())
1362 if (op->operand[0].lmod == OPLM_UNSPEC)
1363 op->operand[0].lmod = OPLM_DWORD;
1364 op->regmask_src = mxAX | op->regmask_dst;
1365 op->regmask_dst = mxAX;
1366 if (op->operand[0].lmod != OPLM_BYTE) {
1367 op->regmask_src |= mxDX;
1368 op->regmask_dst |= mxDX;
1377 op->regmask_src |= op->regmask_dst;
1378 if (op->operand[1].lmod == OPLM_UNSPEC)
1379 op->operand[1].lmod = OPLM_BYTE;
1384 op->regmask_src |= op->regmask_dst;
1385 if (op->operand[2].lmod == OPLM_UNSPEC)
1386 op->operand[2].lmod = OPLM_BYTE;
1390 op->regmask_src |= op->regmask_dst;
1391 op->regmask_dst = 0;
1392 if (op->operand[0].lmod == OPLM_UNSPEC
1393 && (op->operand[0].type == OPT_CONST
1394 || op->operand[0].type == OPT_OFFSET
1395 || op->operand[0].type == OPT_LABEL))
1396 op->operand[0].lmod = OPLM_DWORD;
1402 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1403 && op->operand[0].lmod == op->operand[1].lmod
1404 && op->operand[0].reg == op->operand[1].reg
1405 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1407 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1408 op->regmask_src = op->regmask_dst = 0;
1413 if (op->operand[0].type == OPT_REG
1414 && op->operand[1].type == OPT_REGMEM)
1417 snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1418 if (IS(buf, op->operand[1].name))
1419 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1424 // needed because of OPF_DATA
1425 op->regmask_src |= op->regmask_dst;
1426 // trashed regs must be explicitly detected later
1427 op->regmask_dst = 0;
1431 op->regmask_dst = (1 << xBP) | (1 << xSP);
1432 op->regmask_src = 1 << xBP;
1437 op->regmask_dst |= mxST0;
1441 op->regmask_dst |= mxST0;
1442 if (IS(words[op_w] + 3, "1"))
1443 op->operand[0].val = X87_CONST_1;
1444 else if (IS(words[op_w] + 3, "l2t"))
1445 op->operand[0].val = X87_CONST_L2T;
1446 else if (IS(words[op_w] + 3, "l2e"))
1447 op->operand[0].val = X87_CONST_L2E;
1448 else if (IS(words[op_w] + 3, "pi"))
1449 op->operand[0].val = X87_CONST_PI;
1450 else if (IS(words[op_w] + 3, "lg2"))
1451 op->operand[0].val = X87_CONST_LG2;
1452 else if (IS(words[op_w] + 3, "ln2"))
1453 op->operand[0].val = X87_CONST_LN2;
1454 else if (IS(words[op_w] + 3, "z"))
1455 op->operand[0].val = X87_CONST_Z;
1457 aerr("fld what?\n");
1462 op->regmask_src |= mxST0;
1471 op->regmask_src |= mxST0;
1472 if (op->operand_cnt == 2)
1473 op->regmask_src |= op->regmask_dst;
1474 else if (op->operand_cnt == 1) {
1475 memcpy(&op->operand[1], &op->operand[0], sizeof(op->operand[1]));
1476 op->operand[0].type = OPT_REG;
1477 op->operand[0].lmod = OPLM_QWORD;
1478 op->operand[0].reg = xST0;
1479 op->regmask_dst |= mxST0;
1482 // IDA doesn't use this
1483 aerr("no operands?\n");
1497 op->regmask_src |= mxST0;
1498 op->regmask_dst |= mxST0;
1503 op->regmask_src |= mxST0 | mxST1;
1504 op->regmask_dst |= mxST0;
1512 op->regmask_src |= mxST0;
1513 if (op->operand_cnt == 0) {
1514 op->operand_cnt = 1;
1515 op->operand[0].type = OPT_REG;
1516 op->operand[0].lmod = OPLM_QWORD;
1517 op->operand[0].reg = xST1;
1518 op->regmask_src |= mxST1;
1526 if (op->operand[0].type == OPT_REG
1527 && op->operand[1].type == OPT_CONST)
1529 struct parsed_opr *op1 = &op->operand[1];
1530 if ((op->op == OP_AND && op1->val == 0)
1533 || (op->operand[0].lmod == OPLM_WORD && op1->val == 0xffff)
1534 || (op->operand[0].lmod == OPLM_BYTE && op1->val == 0xff))))
1536 op->regmask_src = 0;
1541 static const char *op_name(struct parsed_op *po)
1543 static char buf[16];
1547 if (po->op == OP_JCC || po->op == OP_SCC) {
1549 *p++ = (po->op == OP_JCC) ? 'j' : 's';
1552 strcpy(p, parsed_flag_op_names[po->pfo]);
1556 for (i = 0; i < ARRAY_SIZE(op_table); i++)
1557 if (op_table[i].op == po->op)
1558 return op_table[i].name;
1564 static const char *dump_op(struct parsed_op *po)
1566 static char out[128];
1573 snprintf(out, sizeof(out), "%s", op_name(po));
1574 for (i = 0; i < po->operand_cnt; i++) {
1578 snprintf(p, sizeof(out) - (p - out),
1579 po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1580 po->operand[i].name);
1586 static const char *lmod_type_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(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_u_ptr(struct parsed_op *po,
1623 enum opr_lenmod lmod)
1635 ferr(po, "invalid lmod: %d\n", lmod);
1636 return "(_invalid_)";
1640 static const char *lmod_cast_s(struct parsed_op *po,
1641 enum opr_lenmod lmod)
1653 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1654 return "(_invalid_)";
1658 static const char *lmod_cast(struct parsed_op *po,
1659 enum opr_lenmod lmod, int is_signed)
1662 lmod_cast_s(po, lmod) :
1663 lmod_cast_u(po, lmod);
1666 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1678 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1683 static const char *opr_name(struct parsed_op *po, int opr_num)
1685 if (opr_num >= po->operand_cnt)
1686 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1687 return po->operand[opr_num].name;
1690 static unsigned int opr_const(struct parsed_op *po, int opr_num)
1692 if (opr_num >= po->operand_cnt)
1693 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1694 if (po->operand[opr_num].type != OPT_CONST)
1695 ferr(po, "opr %d: const expected\n", opr_num);
1696 return po->operand[opr_num].val;
1699 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1701 if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
1702 ferr(po, "invalid reg: %d\n", popr->reg);
1703 return regs_r32[popr->reg];
1706 static int check_simple_cast(const char *cast, int *bits, int *is_signed)
1708 if (IS_START(cast, "(s8)") || IS_START(cast, "(u8)"))
1710 else if (IS_START(cast, "(s16)") || IS_START(cast, "(u16)"))
1712 else if (IS_START(cast, "(s32)") || IS_START(cast, "(u32)"))
1714 else if (IS_START(cast, "(s64)") || IS_START(cast, "(u64)"))
1719 *is_signed = cast[1] == 's' ? 1 : 0;
1723 static int check_deref_cast(const char *cast, int *bits)
1725 if (IS_START(cast, "*(u8 *)"))
1727 else if (IS_START(cast, "*(u16 *)"))
1729 else if (IS_START(cast, "*(u32 *)"))
1731 else if (IS_START(cast, "*(u64 *)"))
1739 // cast1 is the "final" cast
1740 static const char *simplify_cast(const char *cast1, const char *cast2)
1742 static char buf[256];
1750 if (IS(cast1, cast2))
1753 if (check_simple_cast(cast1, &bits1, &s1) == 0
1754 && check_simple_cast(cast2, &bits2, &s2) == 0)
1759 if (check_simple_cast(cast1, &bits1, &s1) == 0
1760 && check_deref_cast(cast2, &bits2) == 0)
1762 if (bits1 == bits2) {
1763 snprintf(buf, sizeof(buf), "*(%c%d *)", s1 ? 's' : 'u', bits1);
1768 if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1771 snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1775 static const char *simplify_cast_num(const char *cast, unsigned int val)
1777 if (IS(cast, "(u8)") && val < 0x100)
1779 if (IS(cast, "(s8)") && val < 0x80)
1781 if (IS(cast, "(u16)") && val < 0x10000)
1783 if (IS(cast, "(s16)") && val < 0x8000)
1785 if (IS(cast, "(s32)") && val < 0x80000000)
1791 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1800 namelen = strlen(name);
1802 p = strpbrk(name, "+-");
1806 ferr(po, "equ parse failed for '%s'\n", name);
1809 *extra_offs = strtol(p, &endp, 16);
1810 if (*endp != 0 || errno != 0)
1811 ferr(po, "equ parse failed for '%s'\n", name);
1814 for (i = 0; i < g_eqcnt; i++)
1815 if (strncmp(g_eqs[i].name, name, namelen) == 0
1816 && g_eqs[i].name[namelen] == 0)
1820 ferr(po, "unresolved equ name: '%s'\n", name);
1827 static int is_stack_access(struct parsed_op *po,
1828 const struct parsed_opr *popr)
1830 return (parse_stack_el(popr->name, NULL, NULL, 0)
1831 || (g_bp_frame && !(po->flags & OPF_EBP_S)
1832 && IS_START(popr->name, "ebp")));
1835 static void parse_stack_access(struct parsed_op *po,
1836 const char *name, char *ofs_reg, int *offset_out,
1837 int *stack_ra_out, const char **bp_arg_out, int is_lea)
1839 const char *bp_arg = "";
1840 const char *p = NULL;
1841 struct parsed_equ *eq;
1848 if (IS_START(name, "ebp-")
1849 || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1852 if (IS_START(p, "0x"))
1855 offset = strtoul(p, &endp, 16);
1858 if (*endp != 0 || errno != 0)
1859 ferr(po, "ebp- parse of '%s' failed\n", name);
1862 bp_arg = parse_stack_el(name, ofs_reg, NULL, 0);
1863 eq = equ_find(po, bp_arg, &offset);
1865 ferr(po, "detected but missing eq\n");
1866 offset += eq->offset;
1869 if (!strncmp(name, "ebp", 3))
1872 // yes it sometimes LEAs ra for compares..
1873 if (!is_lea && ofs_reg[0] == 0
1874 && stack_ra <= offset && offset < stack_ra + 4)
1876 ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1879 *offset_out = offset;
1881 *stack_ra_out = stack_ra;
1883 *bp_arg_out = bp_arg;
1886 static int parse_stack_esp_offset(struct parsed_op *po,
1887 const char *name, int *offset_out)
1889 char ofs_reg[16] = { 0, };
1890 struct parsed_equ *eq;
1896 if (strstr(name, "esp") == NULL)
1898 bp_arg = parse_stack_el(name, ofs_reg, &base_val, 0);
1899 if (bp_arg == NULL) {
1900 // just plain offset?
1901 if (!IS_START(name, "esp+"))
1904 offset = strtol(name + 4, &endp, 0);
1905 if (endp == NULL || *endp != 0 || errno != 0)
1907 *offset_out = offset;
1911 if (ofs_reg[0] != 0)
1913 eq = equ_find(po, bp_arg, &offset);
1915 ferr(po, "detected but missing eq\n");
1916 offset += eq->offset;
1917 *offset_out = base_val + offset;
1921 static int stack_frame_access(struct parsed_op *po,
1922 struct parsed_opr *popr, char *buf, size_t buf_size,
1923 const char *name, const char *cast, int is_src, int is_lea)
1925 enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1926 const char *prefix = "";
1927 const char *bp_arg = NULL;
1928 char ofs_reg[16] = { 0, };
1929 int i, arg_i, arg_s;
1936 if (g_bp_frame && (po->flags & OPF_EBP_S)
1937 && !(po->regmask_src & mxSP))
1938 ferr(po, "stack_frame_access while ebp is scratch\n");
1940 parse_stack_access(po, name, ofs_reg, &offset,
1941 &stack_ra, &bp_arg, is_lea);
1943 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1945 if (offset > stack_ra)
1947 arg_i = (offset - stack_ra - 4) / 4;
1948 if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1950 if (g_func_pp->is_vararg
1951 && arg_i == g_func_pp->argc_stack && is_lea)
1953 // should be va_list
1956 snprintf(buf, buf_size, "%sap", cast);
1959 ferr(po, "offset 0x%x (%s,%d) doesn't map to any arg\n",
1960 offset, bp_arg, arg_i);
1962 if (ofs_reg[0] != 0)
1963 ferr(po, "offset reg on arg access?\n");
1965 for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1966 if (g_func_pp->arg[i].reg != NULL)
1972 if (i == g_func_pp->argc)
1973 ferr(po, "arg %d not in prototype?\n", arg_i);
1975 popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
1982 ferr(po, "lea/byte to arg?\n");
1983 if (is_src && (offset & 3) == 0)
1984 snprintf(buf, buf_size, "%sa%d",
1985 simplify_cast(cast, "(u8)"), i + 1);
1987 snprintf(buf, buf_size, "%sBYTE%d(a%d)",
1988 cast, offset & 3, i + 1);
1993 ferr(po, "lea/word to arg?\n");
1998 ferr(po, "problematic arg store\n");
1999 snprintf(buf, buf_size, "%s((char *)&a%d + 1)",
2000 simplify_cast(cast, "*(u16 *)"), i + 1);
2003 ferr(po, "unaligned arg word load\n");
2005 else if (is_src && (offset & 2) == 0)
2006 snprintf(buf, buf_size, "%sa%d",
2007 simplify_cast(cast, "(u16)"), i + 1);
2009 snprintf(buf, buf_size, "%s%sWORD(a%d)",
2010 cast, (offset & 2) ? "HI" : "LO", i + 1);
2022 snprintf(buf, buf_size, "(u32)&a%d + %d",
2025 ferr(po, "unaligned arg store\n");
2027 // mov edx, [ebp+arg_4+2]; movsx ecx, dx
2028 snprintf(buf, buf_size, "%s(a%d >> %d)",
2029 prefix, i + 1, (offset & 3) * 8);
2033 snprintf(buf, buf_size, "%s%sa%d",
2034 prefix, is_lea ? "&" : "", i + 1);
2039 ferr_assert(po, !(offset & 7));
2042 snprintf(buf, buf_size, "%s%sa%d",
2043 prefix, is_lea ? "&" : "", i + 1);
2047 ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
2051 strcat(g_comment, " unaligned");
2054 guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
2055 if (tmp_lmod != OPLM_DWORD
2056 && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
2057 < lmod_bytes(po, popr->lmod) + (offset & 3))))
2059 ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
2060 i + 1, offset, g_func_pp->arg[i].type.name);
2062 // can't check this because msvc likes to reuse
2063 // arg space for scratch..
2064 //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
2065 // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
2069 if (g_stack_fsz == 0)
2070 ferr(po, "stack var access without stackframe\n");
2071 g_stack_frame_used = 1;
2073 sf_ofs = g_stack_fsz + offset;
2074 if (ofs_reg[0] == 0 && (offset > 0 || sf_ofs < 0))
2075 ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
2085 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2086 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2090 if ((sf_ofs & 1) || ofs_reg[0] != 0) {
2091 // known unaligned or possibly unaligned
2092 strcat(g_comment, " unaligned");
2094 prefix = "*(u16 *)&";
2095 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2096 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2099 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
2103 if ((sf_ofs & 3) || ofs_reg[0] != 0) {
2104 // known unaligned or possibly unaligned
2105 strcat(g_comment, " unaligned");
2107 prefix = "*(u32 *)&";
2108 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2109 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2112 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
2116 ferr_assert(po, !(sf_ofs & 7));
2117 ferr_assert(po, ofs_reg[0] == 0);
2118 // only used for x87 int64/float, float sets is_lea
2119 if (!is_lea && (po->flags & OPF_FINT))
2120 prefix = "*(s64 *)&";
2121 snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
2125 ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
2132 static void check_func_pp(struct parsed_op *po,
2133 const struct parsed_proto *pp, const char *pfx)
2135 enum opr_lenmod tmp_lmod;
2139 if (pp->argc_reg != 0) {
2140 if (!g_allow_user_icall && !pp->is_fastcall) {
2141 pp_print(buf, sizeof(buf), pp);
2142 ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
2144 if (pp->argc_stack > 0 && pp->argc_reg != 2)
2145 ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
2146 pfx, pp->argc_reg, pp->argc_stack);
2149 // fptrs must use 32bit args, callsite might have no information and
2150 // lack a cast to smaller types, which results in incorrectly masked
2151 // args passed (callee may assume masked args, it does on ARM)
2152 if (!pp->is_osinc) {
2153 for (i = 0; i < pp->argc; i++) {
2154 ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
2155 if (ret && tmp_lmod != OPLM_DWORD)
2156 ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
2157 i + 1, pp->arg[i].type.name);
2162 static const char *check_label_read_ref(struct parsed_op *po,
2163 const char *name, int *is_import)
2165 const struct parsed_proto *pp;
2167 pp = proto_parse(g_fhdr, name, 0);
2169 ferr(po, "proto_parse failed for ref '%s'\n", name);
2172 check_func_pp(po, pp, "ref");
2174 if (is_import != NULL)
2175 *is_import = pp->is_import;
2180 static void check_opr(struct parsed_op *po, struct parsed_opr *popr)
2182 if (popr->segment == SEG_FS)
2183 ferr(po, "fs: used\n");
2184 if (popr->segment == SEG_GS)
2185 ferr(po, "gs: used\n");
2188 static char *out_src_opr(char *buf, size_t buf_size,
2189 struct parsed_op *po, struct parsed_opr *popr, const char *cast,
2192 char tmp1[256], tmp2[256];
2199 check_opr(po, popr);
2204 switch (popr->type) {
2207 ferr(po, "lea from reg?\n");
2209 switch (popr->lmod) {
2211 snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2214 snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2217 snprintf(buf, buf_size, "%s%s",
2218 simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2221 if (popr->name[1] == 'h') // XXX..
2222 snprintf(buf, buf_size, "%s(%s >> 8)",
2223 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2225 snprintf(buf, buf_size, "%s%s",
2226 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2229 ferr(po, "invalid src lmod: %d\n", popr->lmod);
2234 if (is_stack_access(po, popr)) {
2235 stack_frame_access(po, popr, buf, buf_size,
2236 popr->name, cast, 1, is_lea);
2240 strcpy(expr, popr->name);
2241 if (strchr(expr, '[')) {
2242 // special case: '[' can only be left for label[reg] form
2243 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2245 ferr(po, "parse failure for '%s'\n", expr);
2246 if (tmp1[0] == '(') {
2247 // (off_4FFF50+3)[eax]
2248 p = strchr(tmp1 + 1, ')');
2249 if (p == NULL || p[1] != 0)
2250 ferr(po, "parse failure (2) for '%s'\n", expr);
2252 memmove(tmp1, tmp1 + 1, strlen(tmp1));
2254 snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2257 // XXX: do we need more parsing?
2259 snprintf(buf, buf_size, "%s", expr);
2263 snprintf(buf, buf_size, "%s(%s)",
2264 simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2268 name = check_label_read_ref(po, popr->name, &is_import);
2270 // for imported data, asm is loading the offset
2273 if (cast[0] == 0 && popr->is_ptr)
2277 snprintf(buf, buf_size, "(u32)&%s", name);
2278 else if (popr->size_lt)
2279 snprintf(buf, buf_size, "%s%s%s%s", cast,
2280 lmod_cast_u_ptr(po, popr->lmod),
2281 popr->is_array ? "" : "&", name);
2283 snprintf(buf, buf_size, "%s%s%s", cast, name,
2284 popr->is_array ? "[0]" : "");
2289 name = check_label_read_ref(po, popr->name, NULL);
2293 ferr(po, "lea an offset?\n");
2294 snprintf(buf, buf_size, "%s&%s", cast, name);
2299 ferr(po, "lea from const?\n");
2301 printf_number(tmp1, sizeof(tmp1), popr->val);
2302 if (popr->val == 0 && strchr(cast, '*'))
2303 snprintf(buf, buf_size, "NULL");
2305 snprintf(buf, buf_size, "%s%s",
2306 simplify_cast_num(cast, popr->val), tmp1);
2310 ferr(po, "invalid src type: %d\n", popr->type);
2316 // note: may set is_ptr (we find that out late for ebp frame..)
2317 static char *out_dst_opr(char *buf, size_t buf_size,
2318 struct parsed_op *po, struct parsed_opr *popr)
2320 check_opr(po, popr);
2322 switch (popr->type) {
2324 switch (popr->lmod) {
2326 snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2329 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2333 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2337 if (popr->name[1] == 'h') // XXX..
2338 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2340 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2343 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2348 if (is_stack_access(po, popr)) {
2349 stack_frame_access(po, popr, buf, buf_size,
2350 popr->name, "", 0, 0);
2354 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2357 if (popr->size_mismatch)
2358 snprintf(buf, buf_size, "%s%s%s",
2359 lmod_cast_u_ptr(po, popr->lmod),
2360 popr->is_array ? "" : "&", popr->name);
2362 snprintf(buf, buf_size, "%s%s", popr->name,
2363 popr->is_array ? "[0]" : "");
2367 ferr(po, "invalid dst type: %d\n", popr->type);
2373 static char *out_src_opr_u32(char *buf, size_t buf_size,
2374 struct parsed_op *po, struct parsed_opr *popr)
2376 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2379 static char *out_opr_float(char *buf, size_t buf_size,
2380 struct parsed_op *po, struct parsed_opr *popr, int is_src,
2381 int need_float_stack)
2383 const char *cast = NULL;
2390 switch (popr->type) {
2392 if (popr->reg < xST0 || popr->reg > xST7) {
2394 ferr_assert(po, po->op == OP_PUSH);
2395 ferr_assert(po, popr->lmod == OPLM_DWORD);
2396 snprintf(buf, buf_size, "*(float *)&%s", opr_reg_p(po, popr));
2400 if (need_float_stack) {
2401 if (popr->reg == xST0)
2402 snprintf(buf, buf_size, "f_st[f_stp & 7]");
2404 snprintf(buf, buf_size, "f_st[(f_stp + %d) & 7]",
2408 snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2412 if (popr->lmod == OPLM_QWORD && is_stack_access(po, popr)) {
2413 stack_frame_access(po, popr, buf, buf_size,
2414 popr->name, "", is_src, 0);
2420 switch (popr->lmod) {
2428 ferr(po, "unhandled lmod: %d\n", popr->lmod);
2431 out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2432 snprintf(buf, buf_size, "*(%s *)(%s)", cast, tmp);
2436 // only for func float args pushes
2437 ferr_assert(po, po->op == OP_PUSH);
2438 u.i = po->operand[0].val;
2439 if (ceilf(u.f) == u.f)
2440 snprintf(buf, buf_size, "%.1ff", u.f);
2442 snprintf(buf, buf_size, "%.8ff", u.f);
2446 ferr(po, "invalid float type: %d\n", popr->type);
2452 static char *out_src_opr_float(char *buf, size_t buf_size,
2453 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2455 return out_opr_float(buf, buf_size, po, popr, 1, need_float_stack);
2458 static char *out_dst_opr_float(char *buf, size_t buf_size,
2459 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2461 return out_opr_float(buf, buf_size, po, popr, 0, need_float_stack);
2464 static void out_test_for_cc(char *buf, size_t buf_size,
2465 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2466 enum opr_lenmod lmod, const char *expr)
2468 const char *cast, *scast;
2470 cast = lmod_cast_u(po, lmod);
2471 scast = lmod_cast_s(po, lmod);
2475 case PFO_BE: // CF==1||ZF==1; CF=0
2476 snprintf(buf, buf_size, "(%s%s %s 0)",
2477 cast, expr, is_inv ? "!=" : "==");
2481 case PFO_L: // SF!=OF; OF=0
2482 snprintf(buf, buf_size, "(%s%s %s 0)",
2483 scast, expr, is_inv ? ">=" : "<");
2486 case PFO_LE: // ZF==1||SF!=OF; OF=0
2487 snprintf(buf, buf_size, "(%s%s %s 0)",
2488 scast, expr, is_inv ? ">" : "<=");
2493 snprintf(buf, buf_size, "(%d)", !!is_inv);
2496 case PFO_P: // PF==1
2497 snprintf(buf, buf_size, "(%sdo_parity(%s))",
2498 is_inv ? "!" : "", expr);
2502 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2506 static void out_cmp_for_cc(char *buf, size_t buf_size,
2507 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2510 const char *cast, *scast, *cast_use;
2511 char buf1[256], buf2[256];
2512 enum opr_lenmod lmod;
2514 if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2515 ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2516 po->operand[0].lmod, po->operand[1].lmod);
2517 lmod = po->operand[0].lmod;
2519 cast = lmod_cast_u(po, lmod);
2520 scast = lmod_cast_s(po, lmod);
2536 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2539 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2540 if (po->op == OP_DEC)
2541 snprintf(buf2, sizeof(buf2), "1");
2544 snprintf(cast_op2, sizeof(cast_op2) - 1, "%s", cast_use);
2546 strcat(cast_op2, "-");
2547 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_op2, 0);
2552 // note: must be unsigned compare
2553 snprintf(buf, buf_size, "(%s %s %s)",
2554 buf1, is_inv ? ">=" : "<", buf2);
2558 snprintf(buf, buf_size, "(%s %s %s)",
2559 buf1, is_inv ? "!=" : "==", buf2);
2563 // note: must be unsigned compare
2564 snprintf(buf, buf_size, "(%s %s %s)",
2565 buf1, is_inv ? ">" : "<=", buf2);
2568 if (is_inv && lmod == OPLM_BYTE
2569 && po->operand[1].type == OPT_CONST
2570 && po->operand[1].val == 0xff)
2572 snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2573 snprintf(buf, buf_size, "(0)");
2577 // note: must be signed compare
2579 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2580 scast, buf1, buf2, is_inv ? ">=" : "<");
2584 snprintf(buf, buf_size, "(%s %s %s)",
2585 buf1, is_inv ? ">=" : "<", buf2);
2589 snprintf(buf, buf_size, "(%s %s %s)",
2590 buf1, is_inv ? ">" : "<=", buf2);
2598 static void out_cmp_test(char *buf, size_t buf_size,
2599 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2601 char buf1[256], buf2[256], buf3[256];
2603 if (po->op == OP_TEST) {
2604 if (IS(opr_name(po, 0), opr_name(po, 1))) {
2605 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2608 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2609 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2610 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2612 out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2613 po->operand[0].lmod, buf3);
2615 else if (po->op == OP_CMP) {
2616 out_cmp_for_cc(buf, buf_size, po, pfo, is_inv, 0);
2619 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2622 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2623 struct parsed_opr *popr2)
2625 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2626 ferr(po, "missing lmod for both operands\n");
2628 if (popr1->lmod == OPLM_UNSPEC)
2629 popr1->lmod = popr2->lmod;
2630 else if (popr2->lmod == OPLM_UNSPEC)
2631 popr2->lmod = popr1->lmod;
2632 else if (popr1->lmod != popr2->lmod) {
2633 if (popr1->type_from_var) {
2634 popr1->size_mismatch = 1;
2635 if (popr1->lmod < popr2->lmod)
2637 popr1->lmod = popr2->lmod;
2639 else if (popr2->type_from_var) {
2640 popr2->size_mismatch = 1;
2641 if (popr2->lmod < popr1->lmod)
2643 popr2->lmod = popr1->lmod;
2646 ferr(po, "conflicting lmods: %d vs %d\n",
2647 popr1->lmod, popr2->lmod);
2651 static const char *op_to_c(struct parsed_op *po)
2675 ferr(po, "op_to_c was supplied with %d\n", po->op);
2679 // last op in stream - unconditional branch or ret
2680 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2681 || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2682 && ops[_i].op != OP_CALL))
2684 #define check_i(po, i) \
2686 ferr(po, "bad " #i ": %d\n", i)
2688 // note: this skips over calls and rm'd stuff assuming they're handled
2689 // so it's intended to use at one of final passes
2690 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2691 int depth, int seen_noreturn, int flags_set)
2693 struct parsed_op *po;
2698 for (; i < opcnt; i++) {
2700 if (po->cc_scratch == magic)
2701 return ret; // already checked
2702 po->cc_scratch = magic;
2704 if (po->flags & OPF_TAIL) {
2705 if (po->op == OP_CALL) {
2706 if (po->pp != NULL && po->pp->is_noreturn)
2715 if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
2718 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2719 if (po->btj != NULL) {
2721 for (j = 0; j < po->btj->count; j++) {
2722 check_i(po, po->btj->d[j].bt_i);
2723 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2724 depth, seen_noreturn, flags_set);
2726 return ret; // dead end
2731 check_i(po, po->bt_i);
2732 if (po->flags & OPF_CJMP) {
2733 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2734 depth, seen_noreturn, flags_set);
2736 return ret; // dead end
2745 if ((po->op == OP_POP || po->op == OP_PUSH)
2746 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2751 if (po->op == OP_PUSH) {
2754 else if (po->op == OP_POP) {
2755 if (relevant && depth == 0) {
2756 po->flags |= flags_set;
2764 // for noreturn, assume msvc skipped stack cleanup
2765 return seen_noreturn ? 1 : -1;
2768 // scan for 'reg' pop backwards starting from i
2769 // intended to use for register restore search, so other reg
2770 // references are considered an error
2771 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2773 struct parsed_op *po;
2774 struct label_ref *lr;
2777 ops[i].cc_scratch = magic;
2781 if (g_labels[i] != NULL) {
2782 lr = &g_label_refs[i];
2783 for (; lr != NULL; lr = lr->next) {
2784 check_i(&ops[i], lr->i);
2785 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2789 if (i > 0 && LAST_OP(i - 1))
2797 if (ops[i].cc_scratch == magic)
2799 ops[i].cc_scratch = magic;
2802 if (po->op == OP_POP && po->operand[0].reg == reg) {
2803 if (po->flags & (OPF_RMD|OPF_DONE))
2806 po->flags |= set_flags;
2810 // this also covers the case where we reach corresponding push
2811 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2815 // nothing interesting on this path,
2816 // still return ret for something recursive calls could find
2820 static void find_reachable_exits(int i, int opcnt, int magic,
2821 int *exits, int *exit_count)
2823 struct parsed_op *po;
2826 for (; i < opcnt; i++)
2829 if (po->cc_scratch == magic)
2831 po->cc_scratch = magic;
2833 if (po->flags & OPF_TAIL) {
2834 ferr_assert(po, *exit_count < MAX_EXITS);
2835 exits[*exit_count] = i;
2840 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2841 if (po->flags & OPF_RMD)
2844 if (po->btj != NULL) {
2845 for (j = 0; j < po->btj->count; j++) {
2846 check_i(po, po->btj->d[j].bt_i);
2847 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2853 check_i(po, po->bt_i);
2854 if (po->flags & OPF_CJMP)
2855 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2863 // scan for 'reg' pop backwards starting from exits (all paths)
2864 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2866 static int exits[MAX_EXITS];
2867 static int exit_count;
2873 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2875 ferr_assert(&ops[i], exit_count > 0);
2878 for (j = 0; j < exit_count; j++) {
2880 ret = scan_for_rsave_pop_reg(e, i + opcnt * 16 + set_flags,
2886 if (ops[e].op == OP_CALL && ops[e].pp != NULL
2887 && ops[e].pp->is_noreturn)
2889 // assume stack cleanup was skipped
2898 // scan for one or more pop of push <const>
2899 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2900 int push_i, int is_probe)
2902 struct parsed_op *po;
2903 struct label_ref *lr;
2907 for (; i < opcnt; i++)
2910 if (po->cc_scratch == magic)
2911 return ret; // already checked
2912 po->cc_scratch = magic;
2914 if (po->flags & OPF_JMP) {
2915 if (po->flags & OPF_RMD)
2917 if (po->op == OP_CALL)
2920 if (po->btj != NULL) {
2921 for (j = 0; j < po->btj->count; j++) {
2922 check_i(po, po->btj->d[j].bt_i);
2923 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2931 check_i(po, po->bt_i);
2932 if (po->flags & OPF_CJMP) {
2933 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2944 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2947 if (g_labels[i] != NULL) {
2948 // all refs must be visited
2949 lr = &g_label_refs[i];
2950 for (; lr != NULL; lr = lr->next) {
2952 if (ops[lr->i].cc_scratch != magic)
2955 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2959 if (po->op == OP_POP)
2961 if (po->flags & (OPF_RMD|OPF_DONE))
2965 po->flags |= OPF_DONE;
2966 po->datap = &ops[push_i];
2975 static void scan_for_pop_const(int i, int opcnt, int magic)
2979 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
2981 ops[i].flags |= OPF_RMD | OPF_DONE;
2982 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
2986 // check if all branch targets within a marked path are also marked
2987 // note: the path checked must not be empty or end with a branch
2988 static int check_path_branches(int opcnt, int magic)
2990 struct parsed_op *po;
2993 for (i = 0; i < opcnt; i++) {
2995 if (po->cc_scratch != magic)
2998 if (po->flags & OPF_JMP) {
2999 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
3002 if (po->btj != NULL) {
3003 for (j = 0; j < po->btj->count; j++) {
3004 check_i(po, po->btj->d[j].bt_i);
3005 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
3010 check_i(po, po->bt_i);
3011 if (ops[po->bt_i].cc_scratch != magic)
3013 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
3021 // scan for multiple pushes for given pop
3022 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
3025 int reg = ops[pop_i].operand[0].reg;
3026 struct parsed_op *po;
3027 struct label_ref *lr;
3030 ops[i].cc_scratch = magic;
3034 if (g_labels[i] != NULL) {
3035 lr = &g_label_refs[i];
3036 for (; lr != NULL; lr = lr->next) {
3037 check_i(&ops[i], lr->i);
3038 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
3042 if (i > 0 && LAST_OP(i - 1))
3050 if (ops[i].cc_scratch == magic)
3052 ops[i].cc_scratch = magic;
3055 if (po->op == OP_CALL)
3057 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
3060 if (po->op == OP_PUSH)
3062 if (po->datap != NULL)
3064 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
3065 // leave this case for reg save/restore handlers
3069 po->flags |= OPF_PPUSH | OPF_DONE;
3070 po->datap = &ops[pop_i];
3079 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
3081 int magic = i + opcnt * 14;
3084 ret = scan_pushes_for_pop_r(i, magic, i, 1);
3086 ret = check_path_branches(opcnt, magic);
3088 ops[i].flags |= OPF_PPUSH | OPF_DONE;
3089 *regmask_pp |= 1 << ops[i].operand[0].reg;
3090 scan_pushes_for_pop_r(i, magic + 1, i, 0);
3095 static void scan_propagate_df(int i, int opcnt)
3097 struct parsed_op *po = &ops[i];
3100 for (; i < opcnt; i++) {
3102 if (po->flags & OPF_DF)
3103 return; // already resolved
3104 po->flags |= OPF_DF;
3106 if (po->op == OP_CALL)
3107 ferr(po, "call with DF set?\n");
3109 if (po->flags & OPF_JMP) {
3110 if (po->btj != NULL) {
3112 for (j = 0; j < po->btj->count; j++) {
3113 check_i(po, po->btj->d[j].bt_i);
3114 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
3119 if (po->flags & OPF_RMD)
3121 check_i(po, po->bt_i);
3122 if (po->flags & OPF_CJMP)
3123 scan_propagate_df(po->bt_i, opcnt);
3129 if (po->flags & OPF_TAIL)
3132 if (po->op == OP_CLD) {
3133 po->flags |= OPF_RMD | OPF_DONE;
3138 ferr(po, "missing DF clear?\n");
3141 // is operand 'opr' referenced by parsed_op 'po'?
3142 static int is_opr_referenced(const struct parsed_opr *opr,
3143 const struct parsed_op *po)
3147 if (opr->type == OPT_REG) {
3148 mask = po->regmask_dst | po->regmask_src;
3149 if (po->op == OP_CALL)
3150 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
3151 if ((1 << opr->reg) & mask)
3157 for (i = 0; i < po->operand_cnt; i++)
3158 if (IS(po->operand[0].name, opr->name))
3164 // is operand 'opr' read by parsed_op 'po'?
3165 static int is_opr_read(const struct parsed_opr *opr,
3166 const struct parsed_op *po)
3168 if (opr->type == OPT_REG) {
3169 if (po->regmask_src & (1 << opr->reg))
3179 // is operand 'opr' modified by parsed_op 'po'?
3180 static int is_opr_modified(const struct parsed_opr *opr,
3181 const struct parsed_op *po)
3185 if (opr->type == OPT_REG) {
3186 if (po->op == OP_CALL) {
3187 mask = po->regmask_dst;
3188 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
3189 if (mask & (1 << opr->reg))
3195 if (po->regmask_dst & (1 << opr->reg))
3201 return IS(po->operand[0].name, opr->name);
3204 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
3205 static int is_any_opr_modified(const struct parsed_op *po_test,
3206 const struct parsed_op *po, int c_mode)
3211 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
3214 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3217 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
3220 // in reality, it can wreck any register, but in decompiled C
3221 // version it can only overwrite eax or edx:eax
3222 mask = (1 << xAX) | (1 << xDX);
3226 if (po->op == OP_CALL
3227 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
3230 for (i = 0; i < po_test->operand_cnt; i++)
3231 if (IS(po_test->operand[i].name, po->operand[0].name))
3237 // scan for any po_test operand modification in range given
3238 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
3241 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3244 for (; i < opcnt; i++) {
3245 if (is_any_opr_modified(po_test, &ops[i], c_mode))
3252 // scan for po_test operand[0] modification in range given
3253 static int scan_for_mod_opr0(struct parsed_op *po_test,
3256 for (; i < opcnt; i++) {
3257 if (is_opr_modified(&po_test->operand[0], &ops[i]))
3264 static int try_resolve_const(int i, const struct parsed_opr *opr,
3265 int magic, unsigned int *val);
3267 static int scan_for_flag_set(int i, int opcnt, int magic,
3268 int *branched, int *setters, int *setter_cnt)
3270 struct label_ref *lr;
3274 if (ops[i].cc_scratch == magic) {
3275 // is this a problem?
3276 //ferr(&ops[i], "%s looped\n", __func__);
3279 ops[i].cc_scratch = magic;
3281 if (g_labels[i] != NULL) {
3284 lr = &g_label_refs[i];
3285 for (; lr->next; lr = lr->next) {
3286 check_i(&ops[i], lr->i);
3287 ret = scan_for_flag_set(lr->i, opcnt, magic,
3288 branched, setters, setter_cnt);
3293 check_i(&ops[i], lr->i);
3294 if (i > 0 && LAST_OP(i - 1)) {
3298 ret = scan_for_flag_set(lr->i, opcnt, magic,
3299 branched, setters, setter_cnt);
3305 if (ops[i].flags & OPF_FLAGS) {
3306 setters[*setter_cnt] = i;
3309 if (ops[i].flags & OPF_REP) {
3310 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
3313 ret = try_resolve_const(i, &opr, i + opcnt * 7, &uval);
3314 if (ret != 1 || uval == 0) {
3315 // can't treat it as full setter because of ecx=0 case,
3316 // also disallow delayed compare
3325 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3332 // scan back for cdq, if anything modifies edx, fail
3333 static int scan_for_cdq_edx(int i)
3336 if (g_labels[i] != NULL) {
3337 if (g_label_refs[i].next != NULL)
3339 if (i > 0 && LAST_OP(i - 1)) {
3340 i = g_label_refs[i].i;
3347 if (ops[i].op == OP_CDQ)
3350 if (ops[i].regmask_dst & (1 << xDX))
3357 static int scan_for_reg_clear(int i, int reg)
3360 if (g_labels[i] != NULL) {
3361 if (g_label_refs[i].next != NULL)
3363 if (i > 0 && LAST_OP(i - 1)) {
3364 i = g_label_refs[i].i;
3371 if (ops[i].op == OP_XOR
3372 && ops[i].operand[0].lmod == OPLM_DWORD
3373 && ops[i].operand[0].reg == ops[i].operand[1].reg
3374 && ops[i].operand[0].reg == reg)
3377 if (ops[i].regmask_dst & (1 << reg))
3384 static void patch_esp_adjust(struct parsed_op *po, int adj)
3386 ferr_assert(po, po->op == OP_ADD);
3387 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3388 ferr_assert(po, po->operand[1].type == OPT_CONST);
3390 // this is a bit of a hack, but deals with use of
3391 // single adj for multiple calls
3392 po->operand[1].val -= adj;
3393 po->flags |= OPF_RMD;
3394 if (po->operand[1].val == 0)
3395 po->flags |= OPF_DONE;
3396 ferr_assert(po, (int)po->operand[1].val >= 0);
3399 // scan for positive, constant esp adjust
3400 // multipath case is preliminary
3401 static int scan_for_esp_adjust(int i, int opcnt,
3402 int adj_expect, int *adj, int *is_multipath, int do_update)
3404 int adj_expect_unknown = 0;
3405 struct parsed_op *po;
3409 *adj = *is_multipath = 0;
3410 if (adj_expect < 0) {
3411 adj_expect_unknown = 1;
3412 adj_expect = 32 * 4; // enough?
3415 for (; i < opcnt && *adj < adj_expect; i++) {
3416 if (g_labels[i] != NULL)
3420 if (po->flags & OPF_DONE)
3423 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3424 if (po->operand[1].type != OPT_CONST)
3425 ferr(&ops[i], "non-const esp adjust?\n");
3426 *adj += po->operand[1].val;
3428 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3431 patch_esp_adjust(po, adj_expect);
3433 po->flags |= OPF_RMD;
3437 else if (po->op == OP_PUSH) {
3438 //if (first_pop == -1)
3439 // first_pop = -2; // none
3440 *adj -= lmod_bytes(po, po->operand[0].lmod);
3442 else if (po->op == OP_POP) {
3443 if (!(po->flags & OPF_DONE)) {
3444 // seems like msvc only uses 'pop ecx' for stack realignment..
3445 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3447 if (first_pop == -1 && *adj >= 0)
3450 if (do_update && *adj >= 0) {
3451 po->flags |= OPF_RMD;
3453 po->flags |= OPF_DONE | OPF_NOREGS;
3456 *adj += lmod_bytes(po, po->operand[0].lmod);
3457 if (*adj > adj_best)
3460 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3461 if (po->op == OP_JMP && po->btj == NULL) {
3467 if (po->op != OP_CALL)
3469 if (po->operand[0].type != OPT_LABEL)
3471 if (po->pp != NULL && po->pp->is_stdcall)
3473 if (adj_expect_unknown && first_pop >= 0)
3475 // assume it's another cdecl call
3479 if (first_pop >= 0) {
3480 // probably only 'pop ecx' was used
3488 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3490 struct parsed_op *po;
3494 ferr(ops, "%s: followed bad branch?\n", __func__);
3496 for (; i < opcnt; i++) {
3498 if (po->cc_scratch == magic)
3500 po->cc_scratch = magic;
3503 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3504 if (po->btj != NULL) {
3506 for (j = 0; j < po->btj->count; j++)
3507 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3511 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3512 if (!(po->flags & OPF_CJMP))
3515 if (po->flags & OPF_TAIL)
3520 static const struct parsed_proto *try_recover_pp(
3521 struct parsed_op *po, const struct parsed_opr *opr,
3522 int is_call, int *search_instead)
3524 const struct parsed_proto *pp = NULL;
3528 // maybe an arg of g_func?
3529 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3531 char ofs_reg[16] = { 0, };
3532 int arg, arg_s, arg_i;
3539 parse_stack_access(po, opr->name, ofs_reg,
3540 &offset, &stack_ra, NULL, 0);
3541 if (ofs_reg[0] != 0)
3542 ferr(po, "offset reg on arg access?\n");
3543 if (offset <= stack_ra) {
3544 // search who set the stack var instead
3545 if (search_instead != NULL)
3546 *search_instead = 1;
3550 arg_i = (offset - stack_ra - 4) / 4;
3551 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3552 if (g_func_pp->arg[arg].reg != NULL)
3558 if (arg == g_func_pp->argc)
3559 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3561 pp = g_func_pp->arg[arg].pp;
3564 ferr(po, "icall arg: arg%d has no pp\n", arg + 1);
3565 check_func_pp(po, pp, "icall arg");
3568 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3570 p = strchr(opr->name + 1, '[');
3571 memcpy(buf, opr->name, p - opr->name);
3572 buf[p - opr->name] = 0;
3573 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3575 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3576 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3579 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3582 check_func_pp(po, pp, "reg-fptr ref");
3588 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3589 int magic, const struct parsed_proto **pp_found, int *pp_i,
3592 const struct parsed_proto *pp = NULL;
3593 struct parsed_op *po;
3594 struct label_ref *lr;
3596 ops[i].cc_scratch = magic;
3599 if (g_labels[i] != NULL) {
3600 lr = &g_label_refs[i];
3601 for (; lr != NULL; lr = lr->next) {
3602 check_i(&ops[i], lr->i);
3603 scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3605 if (i > 0 && LAST_OP(i - 1))
3613 if (ops[i].cc_scratch == magic)
3615 ops[i].cc_scratch = magic;
3617 if (!(ops[i].flags & OPF_DATA))
3619 if (!is_opr_modified(opr, &ops[i]))
3621 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3622 // most probably trashed by some processing
3627 opr = &ops[i].operand[1];
3628 if (opr->type != OPT_REG)
3632 po = (i >= 0) ? &ops[i] : ops;
3635 // reached the top - can only be an arg-reg
3636 if (opr->type != OPT_REG || g_func_pp == NULL)
3639 for (i = 0; i < g_func_pp->argc; i++) {
3640 if (g_func_pp->arg[i].reg == NULL)
3642 if (IS(opr->name, g_func_pp->arg[i].reg))
3645 if (i == g_func_pp->argc)
3647 pp = g_func_pp->arg[i].pp;
3649 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3650 i + 1, g_func_pp->arg[i].reg);
3651 check_func_pp(po, pp, "icall reg-arg");
3654 pp = try_recover_pp(po, opr, 1, NULL);
3656 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3657 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3658 || (*pp_found)->is_stdcall != pp->is_stdcall
3659 //|| (*pp_found)->is_fptr != pp->is_fptr
3660 || (*pp_found)->argc != pp->argc
3661 || (*pp_found)->argc_reg != pp->argc_reg
3662 || (*pp_found)->argc_stack != pp->argc_stack)
3664 ferr(po, "icall: parsed_proto mismatch\n");
3674 static void add_label_ref(struct label_ref *lr, int op_i)
3676 struct label_ref *lr_new;
3683 lr_new = calloc(1, sizeof(*lr_new));
3685 lr_new->next = lr->next;
3689 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3691 struct parsed_op *po = &ops[i];
3692 struct parsed_data *pd;
3693 char label[NAMELEN], *p;
3696 p = strchr(po->operand[0].name, '[');
3700 len = p - po->operand[0].name;
3701 strncpy(label, po->operand[0].name, len);
3704 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3705 if (IS(g_func_pd[j].label, label)) {
3711 //ferr(po, "label '%s' not parsed?\n", label);
3714 if (pd->type != OPT_OFFSET)
3715 ferr(po, "label '%s' with non-offset data?\n", label);
3717 // find all labels, link
3718 for (j = 0; j < pd->count; j++) {
3719 for (l = 0; l < opcnt; l++) {
3720 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3721 add_label_ref(&g_label_refs[l], i);
3731 static void clear_labels(int count)
3735 for (i = 0; i < count; i++) {
3736 if (g_labels[i] != NULL) {
3743 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3748 for (i = 0; i < pp->argc; i++) {
3749 if (pp->arg[i].reg != NULL) {
3750 reg = char_array_i(regs_r32,
3751 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3753 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3754 pp->arg[i].reg, pp->name);
3755 regmask |= 1 << reg;
3762 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3767 if (pp->has_retreg) {
3768 for (i = 0; i < pp->argc; i++) {
3769 if (pp->arg[i].type.is_retreg) {
3770 reg = char_array_i(regs_r32,
3771 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3772 ferr_assert(ops, reg >= 0);
3773 regmask |= 1 << reg;
3778 if (strstr(pp->ret_type.name, "int64"))
3779 return regmask | (1 << xAX) | (1 << xDX);
3780 if (IS(pp->ret_type.name, "float")
3781 || IS(pp->ret_type.name, "double"))
3783 return regmask | mxST0;
3785 if (strcasecmp(pp->ret_type.name, "void") == 0)
3788 return regmask | mxAX;
3791 static int are_ops_same(struct parsed_op *po1, struct parsed_op *po2)
3793 return po1->op == po2->op && po1->operand_cnt == po2->operand_cnt
3794 && memcmp(po1->operand, po2->operand,
3795 sizeof(po1->operand[0]) * po1->operand_cnt) == 0;
3798 static void resolve_branches_parse_calls(int opcnt)
3800 static const struct {
3804 unsigned int regmask_src;
3805 unsigned int regmask_dst;
3807 { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3808 { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3809 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3810 // more precise? Wine gets away with just __ftol handler
3811 { "__ftol2", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3812 { "__CIpow", OPP_CIPOW, OPF_FPOP, mxST0|mxST1, mxST0 },
3814 const struct parsed_proto *pp_c;
3815 struct parsed_proto *pp;
3816 struct parsed_data *pd;
3817 struct parsed_op *po;
3818 const char *tmpname;
3823 for (i = 0; i < opcnt; i++)
3829 if (po->datap != NULL) {
3830 pp = calloc(1, sizeof(*pp));
3831 my_assert_not(pp, NULL);
3833 ret = parse_protostr(po->datap, pp);
3835 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3841 if (po->op == OP_CALL) {
3846 else if (po->operand[0].type == OPT_LABEL)
3848 tmpname = opr_name(po, 0);
3849 if (IS_START(tmpname, "loc_")) {
3851 ferr(po, "call to loc_*\n");
3852 // eliminate_seh() must take care of it
3855 if (IS(tmpname, "__alloca_probe"))
3857 if (IS(tmpname, "__SEH_prolog")) {
3858 ferr_assert(po, g_seh_found == 0);
3862 if (IS(tmpname, "__SEH_epilog"))
3865 // convert some calls to pseudo-ops
3866 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3867 if (!IS(tmpname, pseudo_ops[l].name))
3870 po->op = pseudo_ops[l].op;
3871 po->operand_cnt = 0;
3872 po->regmask_src = pseudo_ops[l].regmask_src;
3873 po->regmask_dst = pseudo_ops[l].regmask_dst;
3874 po->flags = pseudo_ops[l].flags;
3875 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3878 if (l < ARRAY_SIZE(pseudo_ops))
3881 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3882 if (!g_header_mode && pp_c == NULL)
3883 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3886 pp = proto_clone(pp_c);
3887 my_assert_not(pp, NULL);
3893 check_func_pp(po, pp, "fptr var call");
3894 if (pp->is_noreturn) {
3895 po->flags |= OPF_TAIL;
3896 po->flags &= ~OPF_ATAIL; // most likely...
3903 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3906 if (po->operand[0].type == OPT_REGMEM) {
3907 pd = try_resolve_jumptab(i, opcnt);
3915 for (l = 0; l < opcnt; l++) {
3916 if (g_labels[l] != NULL
3917 && IS(po->operand[0].name, g_labels[l]))
3919 if (l == i + 1 && po->op == OP_JMP) {
3920 // yet another alignment type..
3921 po->flags |= OPF_RMD|OPF_DONE;
3924 add_label_ref(&g_label_refs[l], i);
3930 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3933 if (po->operand[0].type == OPT_LABEL)
3937 ferr(po, "unhandled branch\n");
3941 po->flags |= OPF_TAIL;
3942 prev_op = i > 0 ? ops[i - 1].op : OP_UD2;
3943 if (prev_op == OP_POP)
3944 po->flags |= OPF_ATAIL;
3945 if (g_stack_fsz + g_bp_frame == 0 && prev_op != OP_PUSH
3946 && (g_func_pp == NULL || g_func_pp->argc_stack > 0))
3948 po->flags |= OPF_ATAIL;
3954 static int resolve_origin(int i, const struct parsed_opr *opr,
3955 int magic, int *op_i, int *is_caller);
3956 static void set_label(int i, const char *name);
3958 static void eliminate_seh_writes(int opcnt)
3960 const struct parsed_opr *opr;
3965 // assume all sf writes above g_seh_size to be seh related
3966 // (probably unsafe but oh well)
3967 for (i = 0; i < opcnt; i++) {
3968 if (ops[i].op != OP_MOV)
3970 opr = &ops[i].operand[0];
3971 if (opr->type != OPT_REGMEM)
3973 if (!is_stack_access(&ops[i], opr))
3977 parse_stack_access(&ops[i], opr->name, ofs_reg, &offset,
3979 if (offset < 0 && offset >= -g_seh_size)
3980 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3984 static void eliminate_seh_finally(int opcnt)
3986 const char *target_name = NULL;
3987 const char *return_name = NULL;
3988 int exits[MAX_EXITS];
3996 for (i = 0; i < opcnt; i++) {
3997 if (ops[i].op != OP_CALL)
3999 if (!IS_START(opr_name(&ops[i], 0), "loc_"))
4001 if (target_name != NULL)
4002 ferr(&ops[i], "multiple finally calls? (last was %s)\n",
4004 target_name = opr_name(&ops[i], 0);
4007 if (g_labels[i + 1] == NULL)
4008 set_label(i + 1, "seh_fin_done");
4009 return_name = g_labels[i + 1];
4017 // find finally code (bt_i is not set because it's call)
4018 for (i = 0; i < opcnt; i++) {
4019 if (g_labels[i] == NULL)
4021 if (!IS(g_labels[i], target_name))
4024 ferr_assert(&ops[i], target_i == -1);
4027 ferr_assert(&ops[0], target_i != -1);
4029 find_reachable_exits(target_i, opcnt, target_i + opcnt * 24,
4030 exits, &exit_count);
4031 ferr_assert(&ops[target_i], exit_count == 1);
4032 ferr_assert(&ops[target_i], ops[exits[0]].op == OP_RET);
4035 // convert to jumps, link
4036 ops[call_i].op = OP_JMP;
4037 ops[call_i].bt_i = target_i;
4038 add_label_ref(&g_label_refs[target_i], call_i);
4040 ops[tgend_i].op = OP_JMP;
4041 ops[tgend_i].flags &= ~OPF_TAIL;
4042 ops[tgend_i].flags |= OPF_JMP;
4043 ops[tgend_i].bt_i = return_i;
4044 ops[tgend_i].operand_cnt = 1;
4045 ops[tgend_i].operand[0].type = OPT_LABEL;
4046 snprintf(ops[tgend_i].operand[0].name, NAMELEN, "%s", return_name);
4047 add_label_ref(&g_label_refs[return_i], tgend_i);
4049 // rm seh finally entry code
4050 for (i = target_i - 1; i >= 0; i--) {
4051 if (g_labels[i] != NULL && g_label_refs[i].i != -1)
4053 if (ops[i].flags & OPF_CJMP)
4055 if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4058 for (i = target_i - 1; i >= 0; i--) {
4059 if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4061 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4065 static void eliminate_seh(int opcnt)
4069 for (i = 0; i < opcnt; i++) {
4070 if (ops[i].op != OP_MOV)
4072 if (ops[i].operand[0].segment != SEG_FS)
4074 if (!IS(opr_name(&ops[i], 0), "0"))
4077 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4078 if (ops[i].operand[1].reg == xSP) {
4079 for (j = i - 1; j >= 0; j--) {
4080 if (ops[j].op != OP_PUSH)
4082 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4084 if (ops[j].operand[0].val == ~0)
4086 if (ops[j].operand[0].type == OPT_REG) {
4088 ret = resolve_origin(j, &ops[j].operand[0],
4089 j + opcnt * 22, &k, NULL);
4091 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4095 ferr(ops, "missing seh terminator\n");
4099 ret = resolve_origin(i, &ops[i].operand[1],
4100 i + opcnt * 23, &k, NULL);
4102 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4106 eliminate_seh_writes(opcnt);
4107 eliminate_seh_finally(opcnt);
4110 static void eliminate_seh_calls(int opcnt)
4112 int epilog_found = 0;
4119 ferr_assert(&ops[i], ops[i].op == OP_PUSH
4120 && ops[i].operand[0].type == OPT_CONST);
4121 g_stack_fsz = g_seh_size + ops[i].operand[0].val;
4122 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4125 ferr_assert(&ops[i], ops[i].op == OP_PUSH
4126 && ops[i].operand[0].type == OPT_OFFSET);
4127 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4130 ferr_assert(&ops[i], ops[i].op == OP_CALL
4131 && IS(opr_name(&ops[i], 0), "__SEH_prolog"));
4132 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4134 for (i++; i < opcnt; i++) {
4135 if (ops[i].op != OP_CALL)
4137 if (!IS(opr_name(&ops[i], 0), "__SEH_epilog"))
4140 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4143 ferr_assert(ops, epilog_found);
4145 eliminate_seh_writes(opcnt);
4146 eliminate_seh_finally(opcnt);
4149 // check for prologue of many pushes and epilogue with pops
4150 static void check_simple_sequence(int opcnt, int *fsz)
4159 for (i = 0; i < opcnt && i < ARRAY_SIZE(seq); i++) {
4160 if (ops[i].op != OP_PUSH || ops[i].operand[0].type != OPT_REG)
4162 reg = ops[i].operand[0].reg;
4163 if (reg != xBX && reg != xSI && reg != xDI && reg != xBP)
4165 for (j = 0; j < i; j++)
4169 // probably something else is going on here
4177 for (; i < opcnt && seq_len > 0; i++) {
4178 if (!(ops[i].flags & OPF_TAIL))
4181 for (j = i - 1, seq_p = 0; j >= 0 && seq_p < seq_len; j--) {
4182 if (ops[j].op != OP_POP || ops[j].operand[0].type != OPT_REG)
4184 if (ops[j].operand[0].reg != seq[seq_p])
4188 found = seq_len = seq_p;
4193 for (i = 0; i < seq_len; i++)
4194 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4196 for (; i < opcnt && seq_len > 0; i++) {
4197 if (!(ops[i].flags & OPF_TAIL))
4200 for (j = i - 1, seq_p = 0; j >= 0 && seq_p < seq_len; j--) {
4201 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4206 // unlike pushes after sub esp,
4207 // IDA treats pushed like this as part of var area
4208 *fsz += seq_len * 4;
4211 static int scan_prologue(int i, int opcnt, int *ecx_push, int *esp_sub)
4216 for (; i < opcnt; i++)
4217 if (!(ops[i].flags & OPF_DONE))
4220 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4221 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4227 for (; i < opcnt; i++) {
4228 if (i > 0 && g_labels[i] != NULL)
4230 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
4232 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
4233 && ops[i].operand[1].type == OPT_CONST)
4235 g_stack_fsz += opr_const(&ops[i], 1);
4236 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4241 if (ops[i].op == OP_LEA && ops[i].operand[0].reg == xSP
4242 && ops[i].operand[1].type == OPT_REGMEM
4243 && IS_START(ops[i].operand[1].name, "esp-"))
4245 name = ops[i].operand[1].name;
4246 ret = sscanf(name, "esp-%x%n", &j, &len);
4247 ferr_assert(&ops[i], ret == 1 && len == strlen(name));
4249 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4254 if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
4255 && ops[i].operand[1].type == OPT_CONST)
4257 for (j = i + 1; j < opcnt; j++)
4258 if (!(ops[j].flags & OPF_DONE))
4260 if (ops[j].op == OP_CALL
4261 && IS(opr_name(&ops[j], 0), "__alloca_probe"))
4263 g_stack_fsz += opr_const(&ops[i], 1);
4264 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4265 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4276 static void scan_prologue_epilogue(int opcnt, int *stack_align)
4278 int ecx_push = 0, esp_sub = 0, pusha = 0;
4279 int sandard_epilogue;
4280 int found, ret, len;
4284 if (g_seh_found == 2) {
4285 eliminate_seh_calls(opcnt);
4289 eliminate_seh(opcnt);
4290 // ida treats seh as part of sf
4291 g_stack_fsz = g_seh_size;
4295 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
4296 && ops[1].op == OP_MOV
4297 && IS(opr_name(&ops[1], 0), "ebp")
4298 && IS(opr_name(&ops[1], 1), "esp"))
4301 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4302 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4304 for (i = 2; i < opcnt; i++)
4305 if (!(ops[i].flags & OPF_DONE))
4308 if (ops[i].op == OP_PUSHA) {
4309 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4314 if (ops[i].op == OP_AND && ops[i].operand[0].reg == xSP
4315 && ops[i].operand[1].type == OPT_CONST)
4317 l = ops[i].operand[1].val;
4319 if (j == -1 || (l >> j) != -1)
4320 ferr(&ops[i], "unhandled esp align: %x\n", l);
4321 if (stack_align != NULL)
4322 *stack_align = 1 << j;
4323 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4327 i = scan_prologue(i, opcnt, &ecx_push, &esp_sub);
4331 for (; i < opcnt; i++)
4332 if (ops[i].flags & OPF_TAIL)
4335 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4336 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4342 sandard_epilogue = 0;
4343 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
4345 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4346 // the standard epilogue is sometimes even used without a sf
4347 if (ops[j - 1].op == OP_MOV
4348 && IS(opr_name(&ops[j - 1], 0), "esp")
4349 && IS(opr_name(&ops[j - 1], 1), "ebp"))
4350 sandard_epilogue = 1;
4352 else if (ops[j].op == OP_LEAVE)
4354 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4355 sandard_epilogue = 1;
4357 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
4358 && ops[i].pp->is_noreturn)
4360 // on noreturn, msvc sometimes cleans stack, sometimes not
4365 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4366 ferr(&ops[j], "'pop ebp' expected\n");
4368 if (g_stack_fsz != 0 || sandard_epilogue) {
4369 if (ops[j].op == OP_LEAVE)
4371 else if (sandard_epilogue) // mov esp, ebp
4373 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4376 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4378 ferr(&ops[j], "esp restore expected\n");
4381 if (ecx_push && j >= 0 && ops[j].op == OP_POP
4382 && IS(opr_name(&ops[j], 0), "ecx"))
4384 ferr(&ops[j], "unexpected ecx pop\n");
4389 if (ops[j].op == OP_POPA)
4390 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4392 ferr(&ops[j], "popa expected\n");
4397 } while (i < opcnt);
4400 ferr(ops, "missing ebp epilogue\n");
4405 check_simple_sequence(opcnt, &push_fsz);
4406 i = scan_prologue(0, opcnt, &ecx_push, &esp_sub);
4408 if (ecx_push && !esp_sub) {
4409 // could actually be args for a call..
4410 for (; i < opcnt; i++)
4411 if (ops[i].op != OP_PUSH)
4414 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
4415 const struct parsed_proto *pp;
4416 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
4417 j = pp ? pp->argc_stack : 0;
4418 while (i > 0 && j > 0) {
4420 if (ops[i].op == OP_PUSH) {
4421 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
4426 ferr(&ops[i], "unhandled prologue\n");
4430 g_stack_fsz = g_seh_size;
4431 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4432 if (!(ops[i].flags & OPF_RMD))
4442 if (ecx_push || esp_sub)
4447 for (; i < opcnt; i++)
4448 if (ops[i].flags & OPF_TAIL)
4452 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4453 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4458 else if (i < opcnt && (ops[i].flags & OPF_ATAIL)) {
4459 // skip arg updates for arg-reuse tailcall
4460 for (; j >= 0; j--) {
4461 if (ops[j].op != OP_MOV)
4463 if (ops[j].operand[0].type != OPT_REGMEM)
4465 if (strstr(ops[j].operand[0].name, "arg_") == NULL)
4470 for (; j >= 0; j--) {
4471 if ((ops[j].flags & (OPF_RMD | OPF_DONE | OPF_NOREGS)) !=
4472 (OPF_RMD | OPF_DONE | OPF_NOREGS))
4476 if (ecx_push > 0 && !esp_sub) {
4477 for (l = 0; l < ecx_push && j >= 0; l++) {
4478 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
4480 else if (ops[j].op == OP_ADD
4481 && IS(opr_name(&ops[j], 0), "esp")
4482 && ops[j].operand[1].type == OPT_CONST)
4485 l += ops[j].operand[1].val / 4 - 1;
4490 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4493 if (l != ecx_push) {
4494 if (i < opcnt && ops[i].op == OP_CALL
4495 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4497 // noreturn tailcall with no epilogue
4502 ferr(&ops[j], "epilogue scan failed\n");
4509 if (ops[j].op == OP_ADD
4510 && IS(opr_name(&ops[j], 0), "esp")
4511 && ops[j].operand[1].type == OPT_CONST)
4513 if (ops[j].operand[1].val < g_stack_fsz)
4514 ferr(&ops[j], "esp adj is too low (need %d)\n", g_stack_fsz);
4516 ops[j].operand[1].val -= g_stack_fsz; // for stack arg scanner
4517 if (ops[j].operand[1].val == 0)
4518 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4521 else if (ops[j].op == OP_LEA && ops[j].operand[0].reg == xSP
4522 && ops[j].operand[1].type == OPT_REGMEM
4523 && IS_START(ops[j].operand[1].name, "esp+"))
4525 const char *name = ops[j].operand[1].name;
4526 ret = sscanf(name, "esp+%x%n", &l, &len);
4527 ferr_assert(&ops[j], ret == 1 && len == strlen(name));
4528 ferr_assert(&ops[j], l <= g_stack_fsz);
4529 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4532 else if (i < opcnt && ops[i].op == OP_CALL
4533 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4535 // noreturn tailcall with no epilogue
4539 ferr(&ops[j], "'add esp' expected\n");
4543 } while (i < opcnt);
4546 ferr(ops, "missing esp epilogue\n");
4549 if (g_stack_fsz != 0)
4550 // see check_simple_sequence
4551 g_stack_fsz += push_fsz;
4554 // find an instruction that changed opr before i op
4555 // *op_i must be set to -1 by the caller
4556 // *is_caller is set to 1 if one source is determined to be g_func arg
4557 // returns 1 if found, *op_i is then set to origin
4558 // returns -1 if multiple origins are found
4559 static int resolve_origin(int i, const struct parsed_opr *opr,
4560 int magic, int *op_i, int *is_caller)
4562 struct label_ref *lr;
4566 if (g_labels[i] != NULL) {
4567 lr = &g_label_refs[i];
4568 for (; lr != NULL; lr = lr->next) {
4569 check_i(&ops[i], lr->i);
4570 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4572 if (i > 0 && LAST_OP(i - 1))
4578 if (is_caller != NULL)
4583 if (ops[i].cc_scratch == magic)
4585 ops[i].cc_scratch = magic;
4587 if (!(ops[i].flags & OPF_DATA))
4589 if (!is_opr_modified(opr, &ops[i]))
4593 if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4604 // find an instruction that previously referenced opr
4605 // if multiple results are found - fail
4606 // *op_i must be set to -1 by the caller
4607 // returns 1 if found, *op_i is then set to referencer insn
4608 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4609 int magic, int *op_i)
4611 struct label_ref *lr;
4615 if (g_labels[i] != NULL) {
4616 lr = &g_label_refs[i];
4617 for (; lr != NULL; lr = lr->next) {
4618 check_i(&ops[i], lr->i);
4619 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4621 if (i > 0 && LAST_OP(i - 1))
4629 if (ops[i].cc_scratch == magic)
4631 ops[i].cc_scratch = magic;
4633 if (!is_opr_referenced(opr, &ops[i]))
4644 // adjust datap of all reachable 'op' insns when moving back
4645 // returns 1 if at least 1 op was found
4646 // returns -1 if path without an op was found
4647 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4649 struct label_ref *lr;
4652 if (ops[i].cc_scratch == magic)
4654 ops[i].cc_scratch = magic;
4657 if (g_labels[i] != NULL) {
4658 lr = &g_label_refs[i];
4659 for (; lr != NULL; lr = lr->next) {
4660 check_i(&ops[i], lr->i);
4661 ret |= adjust_prev_op(lr->i, op, magic, datap);
4663 if (i > 0 && LAST_OP(i - 1))
4671 if (ops[i].cc_scratch == magic)
4673 ops[i].cc_scratch = magic;
4675 if (ops[i].op != op)
4678 ops[i].datap = datap;
4683 // find next instruction that reads opr
4684 // *op_i must be set to -1 by the caller
4685 // on return, *op_i is set to first referencer insn
4686 // returns 1 if exactly 1 referencer is found
4687 static int find_next_read(int i, int opcnt,
4688 const struct parsed_opr *opr, int magic, int *op_i)
4690 struct parsed_op *po;
4693 for (; i < opcnt; i++)
4695 if (ops[i].cc_scratch == magic)
4697 ops[i].cc_scratch = magic;
4700 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4701 if (po->btj != NULL) {
4703 for (j = 0; j < po->btj->count; j++) {
4704 check_i(po, po->btj->d[j].bt_i);
4705 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4711 if (po->flags & OPF_RMD)
4713 check_i(po, po->bt_i);
4714 if (po->flags & OPF_CJMP) {
4715 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4724 if (!is_opr_read(opr, po)) {
4726 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4727 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4729 full_opr = po->operand[0].lmod >= opr->lmod;
4731 if (is_opr_modified(opr, po) && full_opr) {
4735 if (po->flags & OPF_TAIL)
4750 static int find_next_read_reg(int i, int opcnt, int reg,
4751 enum opr_lenmod lmod, int magic, int *op_i)
4753 struct parsed_opr opr = OPR_INIT(OPT_REG, lmod, reg);
4756 return find_next_read(i, opcnt, &opr, magic, op_i);
4759 // find next instruction that reads opr
4760 // *op_i must be set to -1 by the caller
4761 // on return, *op_i is set to first flag user insn
4762 // returns 1 if exactly 1 flag user is found
4763 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4765 struct parsed_op *po;
4768 for (; i < opcnt; i++)
4770 if (ops[i].cc_scratch == magic)
4772 ops[i].cc_scratch = magic;
4775 if (po->op == OP_CALL)
4777 if (po->flags & OPF_JMP) {
4778 if (po->btj != NULL) {
4780 for (j = 0; j < po->btj->count; j++) {
4781 check_i(po, po->btj->d[j].bt_i);
4782 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4788 if (po->flags & OPF_RMD)
4790 check_i(po, po->bt_i);
4791 if (po->flags & OPF_CJMP)
4798 if (!(po->flags & OPF_CC)) {
4799 if (po->flags & OPF_FLAGS)
4802 if (po->flags & OPF_TAIL)
4818 static int try_resolve_const(int i, const struct parsed_opr *opr,
4819 int magic, unsigned int *val)
4824 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4827 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4830 *val = ops[i].operand[1].val;
4837 static int resolve_used_bits(int i, int opcnt, int reg,
4838 int *mask, int *is_z_check)
4840 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4844 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4848 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4850 fnote(&ops[j], "(first read)\n");
4851 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4854 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4855 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4857 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4858 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4860 *mask = ops[j].operand[1].val;
4861 if (ops[j].operand[0].lmod == OPLM_BYTE
4862 && ops[j].operand[0].name[1] == 'h')
4866 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4869 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4871 *is_z_check = ops[k].pfo == PFO_Z;
4876 static const struct parsed_proto *resolve_deref(int i, int magic,
4877 struct parsed_opr *opr, int level)
4879 struct parsed_opr opr_s = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
4880 const struct parsed_proto *pp = NULL;
4881 int from_caller = 0;
4890 ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4891 if (ret != 2 || len != strlen(opr->name)) {
4892 ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4893 if (ret != 1 || len != strlen(opr->name))
4897 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4902 ret = resolve_origin(i, &opr_s, i + magic, &j, NULL);
4906 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4907 && strlen(ops[j].operand[1].name) == 3
4908 && ops[j].operand[0].lmod == OPLM_DWORD
4909 && ops[j].pp == NULL // no hint
4912 // allow one simple dereference (com/directx)
4913 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4914 ops[j].operand[1].name);
4918 ret = resolve_origin(j, &opr_s, j + magic, &k, NULL);
4923 if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
4926 if (ops[j].pp != NULL) {
4930 else if (ops[j].operand[1].type == OPT_REGMEM) {
4931 pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
4933 // maybe structure ptr in structure
4934 pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
4937 else if (ops[j].operand[1].type == OPT_LABEL)
4938 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4939 else if (ops[j].operand[1].type == OPT_REG) {
4942 ret = resolve_origin(j, &ops[j].operand[1], i + magic,
4944 if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
4945 for (k = 0; k < g_func_pp->argc; k++) {
4946 if (g_func_pp->arg[k].reg == NULL)
4948 if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
4949 pp = g_func_pp->arg[k].pp;
4958 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4960 ferr(&ops[j], "expected struct, got '%s %s'\n",
4961 pp->type.name, pp->name);
4965 return proto_lookup_struct(g_fhdr, pp->type.name, offset);
4968 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4969 int *pp_i, int *multi_src)
4971 const struct parsed_proto *pp = NULL;
4972 int search_advice = 0;
4977 switch (ops[i].operand[0].type) {
4979 // try to resolve struct member calls
4980 pp = resolve_deref(i, i + opcnt * 19, &ops[i].operand[0], 0);
4986 pp = try_recover_pp(&ops[i], &ops[i].operand[0],
4992 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
5000 static struct parsed_proto *process_call_early(int i, int opcnt,
5003 struct parsed_op *po = &ops[i];
5004 struct parsed_proto *pp;
5010 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
5014 // look for and make use of esp adjust
5016 if (!pp->is_stdcall && pp->argc_stack > 0)
5017 ret = scan_for_esp_adjust(i + 1, opcnt,
5018 pp->argc_stack * 4, &adj, &multipath, 0);
5020 if (pp->argc_stack > adj / 4)
5024 if (ops[ret].op == OP_POP) {
5025 for (j = 1; j < adj / 4; j++) {
5026 if (ops[ret + j].op != OP_POP
5027 || ops[ret + j].operand[0].reg != xCX)
5039 static struct parsed_proto *process_call(int i, int opcnt)
5041 struct parsed_op *po = &ops[i];
5042 const struct parsed_proto *pp_c;
5043 struct parsed_proto *pp;
5044 const char *tmpname;
5045 int call_i = -1, ref_i = -1;
5046 int adj = 0, multipath = 0;
5049 tmpname = opr_name(po, 0);
5054 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
5056 if (!pp_c->is_func && !pp_c->is_fptr)
5057 ferr(po, "call to non-func: %s\n", pp_c->name);
5058 pp = proto_clone(pp_c);
5059 my_assert_not(pp, NULL);
5061 // not resolved just to single func
5064 switch (po->operand[0].type) {
5066 // we resolved this call and no longer need the register
5067 po->regmask_src &= ~(1 << po->operand[0].reg);
5069 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
5070 && ops[call_i].operand[1].type == OPT_LABEL)
5072 // no other source users?
5073 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
5075 if (ret == 1 && call_i == ref_i) {
5076 // and nothing uses it after us?
5078 find_next_read(i + 1, opcnt, &po->operand[0],
5079 i + opcnt * 11, &ref_i);
5081 // then also don't need the source mov
5082 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
5094 pp = calloc(1, sizeof(*pp));
5095 my_assert_not(pp, NULL);
5098 ret = scan_for_esp_adjust(i + 1, opcnt,
5099 -1, &adj, &multipath, 0);
5100 if (ret < 0 || adj < 0) {
5101 if (!g_allow_regfunc)
5102 ferr(po, "non-__cdecl indirect call unhandled yet\n");
5103 pp->is_unresolved = 1;
5107 if (adj > ARRAY_SIZE(pp->arg))
5108 ferr(po, "esp adjust too large: %d\n", adj);
5109 pp->ret_type.name = strdup("int");
5110 pp->argc = pp->argc_stack = adj;
5111 for (arg = 0; arg < pp->argc; arg++)
5112 pp->arg[arg].type.name = strdup("int");
5117 // look for and make use of esp adjust
5120 if (!pp->is_stdcall && pp->argc_stack > 0) {
5121 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
5122 ret = scan_for_esp_adjust(i + 1, opcnt,
5123 adj_expect, &adj, &multipath, 0);
5126 if (pp->is_vararg) {
5127 if (adj / 4 < pp->argc_stack) {
5128 fnote(po, "(this call)\n");
5129 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
5130 adj, pp->argc_stack * 4);
5132 // modify pp to make it have varargs as normal args
5134 pp->argc += adj / 4 - pp->argc_stack;
5135 for (; arg < pp->argc; arg++) {
5136 pp->arg[arg].type.name = strdup("int");
5139 if (pp->argc > ARRAY_SIZE(pp->arg))
5140 ferr(po, "too many args for '%s'\n", tmpname);
5142 if (pp->argc_stack > adj / 4) {
5143 if (pp->is_noreturn)
5144 // assume no stack adjust was emited
5146 fnote(po, "(this call)\n");
5147 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
5148 tmpname, pp->argc_stack * 4, adj);
5151 scan_for_esp_adjust(i + 1, opcnt,
5152 pp->argc_stack * 4, &adj, &multipath, 1);
5154 else if (pp->is_vararg)
5155 ferr(po, "missing esp_adjust for vararg func '%s'\n",
5162 static void mark_float_arg(struct parsed_op *po,
5163 struct parsed_proto *pp, int arg, int *regmask_ffca)
5166 po->p_argnum = arg + 1;
5167 ferr_assert(po, pp->arg[arg].datap == NULL);
5168 pp->arg[arg].datap = po;
5169 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
5170 if (regmask_ffca != NULL)
5171 *regmask_ffca |= 1 << arg;
5174 static int check_for_stp(int i, int i_to)
5176 struct parsed_op *po;
5178 for (; i < i_to; i++) {
5180 if (po->op == OP_FST)
5182 if (g_labels[i] != NULL || (po->flags & OPF_JMP))
5184 if (po->op == OP_CALL || po->op == OP_PUSH || po->op == OP_POP)
5186 if (po->op == OP_ADD && po->operand[0].reg == xSP)
5193 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
5196 struct parsed_op *po;
5202 for (base_arg = 0; base_arg < pp->argc; base_arg++)
5203 if (pp->arg[base_arg].reg == NULL)
5206 for (j = i; j > 0; )
5208 ferr_assert(&ops[j], g_labels[j] == NULL);
5212 ferr_assert(po, po->op != OP_PUSH);
5213 if (po->op == OP_FST)
5215 if (po->operand[0].type != OPT_REGMEM)
5217 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
5220 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3)) {
5221 //ferr(po, "offset %d, %d args\n", offset, pp->argc_stack);
5225 arg = base_arg + offset / 4;
5226 mark_float_arg(po, pp, arg, regmask_ffca);
5228 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5229 && po->operand[1].type == OPT_CONST)
5231 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5236 for (arg = base_arg; arg < pp->argc; arg++) {
5237 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
5238 po = pp->arg[arg].datap;
5240 ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
5241 if (po->operand[0].lmod == OPLM_QWORD)
5248 static int collect_call_args_early(int i, struct parsed_proto *pp,
5249 int *regmask, int *regmask_ffca)
5251 struct parsed_op *po;
5256 for (arg = 0; arg < pp->argc; arg++)
5257 if (pp->arg[arg].reg == NULL)
5260 // first see if it can be easily done
5261 for (j = i; j > 0 && arg < pp->argc; )
5263 if (g_labels[j] != NULL)
5268 if (po->op == OP_CALL)
5270 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
5272 else if (po->op == OP_POP)
5274 else if (po->flags & OPF_CJMP)
5276 else if (po->op == OP_PUSH) {
5277 if (po->flags & (OPF_FARG|OPF_FARGNR))
5279 if (!g_header_mode) {
5280 ret = scan_for_mod(po, j + 1, i, 1);
5285 if (pp->arg[arg].type.is_va_list)
5289 for (arg++; arg < pp->argc; arg++)
5290 if (pp->arg[arg].reg == NULL)
5293 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5294 && po->operand[1].type == OPT_CONST)
5296 if (po->flags & (OPF_RMD|OPF_DONE))
5298 if (po->operand[1].val != pp->argc_stack * 4)
5299 ferr(po, "unexpected esp adjust: %d\n",
5300 po->operand[1].val * 4);
5301 ferr_assert(po, pp->argc - arg == pp->argc_stack);
5302 return collect_call_args_no_push(i, pp, regmask_ffca);
5310 for (arg = 0; arg < pp->argc; arg++)
5311 if (pp->arg[arg].reg == NULL)
5314 for (j = i; j > 0 && arg < pp->argc; )
5318 if (ops[j].op == OP_PUSH)
5320 ops[j].p_argnext = -1;
5321 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
5323 k = check_for_stp(j + 1, i);
5325 // push ecx; fstp dword ptr [esp]
5326 ret = parse_stack_esp_offset(&ops[k],
5327 ops[k].operand[0].name, &offset);
5328 if (ret == 0 && offset == 0) {
5329 if (!pp->arg[arg].type.is_float)
5330 ferr(&ops[i], "arg %d should be float\n", arg + 1);
5331 mark_float_arg(&ops[k], pp, arg, regmask_ffca);
5335 if (pp->arg[arg].datap == NULL) {
5336 pp->arg[arg].datap = &ops[j];
5337 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
5338 *regmask |= 1 << ops[j].operand[0].reg;
5341 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5342 ops[j].flags &= ~OPF_RSAVE;
5345 for (arg++; arg < pp->argc; arg++)
5346 if (pp->arg[arg].reg == NULL)
5354 static int sync_argnum(struct parsed_op *po, int argnum)
5356 struct parsed_op *po_tmp;
5358 // see if other branches don't have higher argnum
5359 for (po_tmp = po; po_tmp != NULL; ) {
5360 if (argnum < po_tmp->p_argnum)
5361 argnum = po_tmp->p_argnum;
5362 // note: p_argnext is active on current collect_call_args only
5363 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5366 // make all argnums consistent
5367 for (po_tmp = po; po_tmp != NULL; ) {
5368 if (po_tmp->p_argnum != 0)
5369 po_tmp->p_argnum = argnum;
5370 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5376 static int collect_call_args_r(struct parsed_op *po, int i,
5377 struct parsed_proto *pp, int *regmask, int *arg_grp,
5378 int arg, int argnum, int magic, int need_op_saving, int may_reuse)
5380 struct parsed_proto *pp_tmp;
5381 struct parsed_op *po_tmp;
5382 struct label_ref *lr;
5383 int need_to_save_current;
5384 int arg_grp_current = 0;
5385 int save_args_seen = 0;
5392 ferr(po, "dead label encountered\n");
5396 for (; arg < pp->argc; arg++, argnum++)
5397 if (pp->arg[arg].reg == NULL)
5399 magic = (magic & 0xffffff) | (arg << 24);
5401 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
5403 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
5404 if (ops[j].cc_scratch != magic) {
5405 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
5409 // ok: have already been here
5412 ops[j].cc_scratch = magic;
5414 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
5415 lr = &g_label_refs[j];
5416 if (lr->next != NULL)
5418 for (; lr->next; lr = lr->next) {
5419 check_i(&ops[j], lr->i);
5420 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5422 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5423 arg, argnum, magic, need_op_saving, may_reuse);
5428 check_i(&ops[j], lr->i);
5429 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5431 if (j > 0 && LAST_OP(j - 1)) {
5432 // follow last branch in reverse
5437 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5438 arg, argnum, magic, need_op_saving, may_reuse);
5444 if (ops[j].op == OP_CALL)
5446 if (pp->is_unresolved)
5451 ferr(po, "arg collect %d/%d hit unparsed call '%s'\n",
5452 arg, pp->argc, ops[j].operand[0].name);
5453 if (may_reuse && pp_tmp->argc_stack > 0)
5454 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
5455 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
5457 // esp adjust of 0 means we collected it before
5458 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
5459 && (ops[j].operand[1].type != OPT_CONST
5460 || ops[j].operand[1].val != 0))
5462 if (pp->is_unresolved)
5465 fnote(po, "(this call)\n");
5466 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
5467 arg, pp->argc, ops[j].operand[1].val);
5469 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
5471 if (pp->is_unresolved)
5474 fnote(po, "(this call)\n");
5475 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
5477 else if (ops[j].flags & OPF_CJMP)
5479 if (pp->is_unresolved)
5484 else if (ops[j].op == OP_PUSH
5485 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
5487 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
5490 ops[j].p_argnext = -1;
5491 po_tmp = pp->arg[arg].datap;
5493 ops[j].p_argnext = po_tmp - ops;
5494 pp->arg[arg].datap = &ops[j];
5496 argnum = sync_argnum(&ops[j], argnum);
5498 need_to_save_current = 0;
5500 if (ops[j].operand[0].type == OPT_REG)
5501 reg = ops[j].operand[0].reg;
5503 if (!need_op_saving) {
5504 ret = scan_for_mod(&ops[j], j + 1, i, 1);
5505 need_to_save_current = (ret >= 0);
5507 if (need_op_saving || need_to_save_current) {
5508 // mark this arg as one that needs operand saving
5509 pp->arg[arg].is_saved = 1;
5511 if (save_args_seen & (1 << (argnum - 1))) {
5514 if (arg_grp_current >= MAX_ARG_GRP)
5515 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
5519 else if (ops[j].p_argnum == 0)
5520 ops[j].flags |= OPF_RMD;
5522 // some PUSHes are reused by different calls on other branches,
5523 // but that can't happen if we didn't branch, so they
5524 // can be removed from future searches (handles nested calls)
5526 ops[j].flags |= OPF_FARGNR;
5528 ops[j].flags |= OPF_FARG;
5529 ops[j].flags &= ~OPF_RSAVE;
5531 // check for __VALIST
5532 if (!pp->is_unresolved && g_func_pp != NULL
5533 && pp->arg[arg].type.is_va_list)
5536 ret = resolve_origin(j, &ops[j].operand[0],
5537 magic + 1, &k, NULL);
5538 if (ret == 1 && k >= 0)
5540 if (ops[k].op == OP_LEA) {
5541 if (!g_func_pp->is_vararg)
5542 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
5545 snprintf(buf, sizeof(buf), "arg_%X",
5546 g_func_pp->argc_stack * 4);
5547 if (strstr(ops[k].operand[1].name, buf)
5548 || strstr(ops[k].operand[1].name, "arglist"))
5550 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
5551 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
5552 pp->arg[arg].is_saved = 0;
5556 ferr(&ops[k], "va_list arg detection failed\n");
5558 // check for va_list from g_func_pp arg too
5559 else if (ops[k].op == OP_MOV
5560 && is_stack_access(&ops[k], &ops[k].operand[1]))
5562 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5563 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5565 ops[k].flags |= OPF_RMD | OPF_DONE;
5566 ops[j].flags |= OPF_RMD;
5567 ops[j].p_argpass = ret + 1;
5568 pp->arg[arg].is_saved = 0;
5575 if (pp->arg[arg].is_saved) {
5576 ops[j].flags &= ~OPF_RMD;
5577 ops[j].p_argnum = argnum;
5580 // tracking reg usage
5582 *regmask |= 1 << reg;
5586 if (!pp->is_unresolved) {
5588 for (; arg < pp->argc; arg++, argnum++)
5589 if (pp->arg[arg].reg == NULL)
5592 magic = (magic & 0xffffff) | (arg << 24);
5595 if (ops[j].p_arggrp > arg_grp_current) {
5597 arg_grp_current = ops[j].p_arggrp;
5599 if (ops[j].p_argnum > 0)
5600 save_args_seen |= 1 << (ops[j].p_argnum - 1);
5603 if (arg < pp->argc) {
5604 ferr(po, "arg collect failed for '%s': %d/%d\n",
5605 pp->name, arg, pp->argc);
5609 if (arg_grp_current > *arg_grp)
5610 *arg_grp = arg_grp_current;
5615 static int collect_call_args(struct parsed_op *po, int i,
5616 struct parsed_proto *pp, int *regmask, int magic)
5618 // arg group is for cases when pushes for
5619 // multiple funcs are going on
5620 struct parsed_op *po_tmp;
5625 ret = collect_call_args_r(po, i, pp, regmask, &arg_grp,
5631 // propagate arg_grp
5632 for (a = 0; a < pp->argc; a++) {
5633 if (pp->arg[a].reg != NULL)
5636 po_tmp = pp->arg[a].datap;
5637 while (po_tmp != NULL) {
5638 po_tmp->p_arggrp = arg_grp;
5639 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5644 if (pp->is_unresolved) {
5646 pp->argc_stack += ret;
5647 for (a = 0; a < pp->argc; a++)
5648 if (pp->arg[a].type.name == NULL)
5649 pp->arg[a].type.name = strdup("int");
5655 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5656 int regmask_now, int *regmask,
5657 int regmask_save_now, int *regmask_save,
5658 int *regmask_init, int regmask_arg)
5660 struct parsed_op *po;
5668 for (; i < opcnt; i++)
5671 if (cbits[i >> 3] & (1 << (i & 7)))
5673 cbits[i >> 3] |= (1 << (i & 7));
5675 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5676 if (po->flags & (OPF_RMD|OPF_DONE))
5678 if (po->btj != NULL) {
5679 for (j = 0; j < po->btj->count; j++) {
5680 check_i(po, po->btj->d[j].bt_i);
5681 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5682 regmask_now, regmask, regmask_save_now, regmask_save,
5683 regmask_init, regmask_arg);
5688 check_i(po, po->bt_i);
5689 if (po->flags & OPF_CJMP)
5690 reg_use_pass(po->bt_i, opcnt, cbits,
5691 regmask_now, regmask, regmask_save_now, regmask_save,
5692 regmask_init, regmask_arg);
5698 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5699 && !g_func_pp->is_userstack
5700 && po->operand[0].type == OPT_REG)
5702 reg = po->operand[0].reg;
5703 ferr_assert(po, reg >= 0);
5706 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5707 if (regmask_now & (1 << reg)) {
5708 already_saved = regmask_save_now & (1 << reg);
5709 flags_set = OPF_RSAVE | OPF_DONE;
5712 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, 0);
5714 scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5715 reg, 0, 0, flags_set);
5718 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5720 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5725 ferr_assert(po, !already_saved);
5726 po->flags |= flags_set;
5728 if (regmask_now & (1 << reg)) {
5729 regmask_save_now |= (1 << reg);
5730 *regmask_save |= regmask_save_now;
5735 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5736 reg = po->operand[0].reg;
5737 ferr_assert(po, reg >= 0);
5739 if (regmask_save_now & (1 << reg))
5740 regmask_save_now &= ~(1 << reg);
5742 regmask_now &= ~(1 << reg);
5745 else if (po->op == OP_CALL) {
5746 if ((po->regmask_dst & (1 << xAX))
5747 && !(po->regmask_dst & (1 << xDX)))
5749 if (po->flags & OPF_TAIL)
5750 // don't need eax, will do "return f();" or "f(); return;"
5751 po->regmask_dst &= ~(1 << xAX);
5753 find_next_read_reg(i + 1, opcnt, xAX, OPLM_DWORD,
5754 i + opcnt * 17, &j);
5757 po->regmask_dst &= ~(1 << xAX);
5761 // not "full stack" mode and have something in stack
5762 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5763 ferr(po, "float stack is not empty on func call\n");
5766 if (po->flags & OPF_NOREGS)
5769 // if incomplete register is used, clear it on init to avoid
5770 // later use of uninitialized upper part in some situations
5771 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5772 && po->operand[0].lmod != OPLM_DWORD)
5774 reg = po->operand[0].reg;
5775 ferr_assert(po, reg >= 0);
5777 if (!(regmask_now & (1 << reg)))
5778 *regmask_init |= 1 << reg;
5781 regmask_op = po->regmask_src | po->regmask_dst;
5783 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5784 regmask_new &= ~(1 << xSP);
5785 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5786 regmask_new &= ~(1 << xBP);
5788 if (regmask_new != 0)
5789 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5791 if (regmask_op & (1 << xBP)) {
5792 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5793 if (po->regmask_dst & (1 << xBP))
5794 // compiler decided to drop bp frame and use ebp as scratch
5795 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5797 regmask_op &= ~(1 << xBP);
5801 if (po->flags & OPF_FPUSH) {
5802 if (regmask_now & mxST1)
5803 regmask_now |= mxSTa; // switch to "full stack" mode
5804 if (regmask_now & mxSTa)
5805 po->flags |= OPF_FSHIFT;
5806 if (!(regmask_now & mxST7_2)) {
5808 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5812 regmask_now |= regmask_op;
5813 *regmask |= regmask_now;
5816 if (po->flags & OPF_FPOPP) {
5817 if ((regmask_now & mxSTa) == 0)
5818 ferr(po, "float pop on empty stack?\n");
5819 if (regmask_now & mxST7_2)
5820 po->flags |= OPF_FSHIFT;
5821 if (!(regmask_now & mxST7_2))
5822 regmask_now &= ~mxST1_0;
5824 else if (po->flags & OPF_FPOP) {
5825 if ((regmask_now & mxSTa) == 0)
5826 ferr(po, "float pop on empty stack?\n");
5827 if (regmask_now & (mxST7_2 | mxST1))
5828 po->flags |= OPF_FSHIFT;
5829 if (!(regmask_now & mxST7_2)) {
5831 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5835 if (po->flags & OPF_TAIL) {
5836 if (!(regmask_now & mxST7_2)) {
5837 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5838 if (!(regmask_now & mxST0))
5839 ferr(po, "no st0 on float return, mask: %x\n",
5842 else if (regmask_now & mxST1_0)
5843 ferr(po, "float regs on tail: %x\n", regmask_now);
5846 // there is support for "conditional tailcall", sort of
5847 if (!(po->flags & OPF_CC))
5853 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5857 for (i = 0; i < pp->argc; i++)
5858 if (pp->arg[i].reg == NULL)
5862 memmove(&pp->arg[i + 1], &pp->arg[i],
5863 sizeof(pp->arg[0]) * pp->argc_stack);
5864 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5865 pp->arg[i].reg = strdup(reg);
5866 pp->arg[i].type.name = strdup("int");
5871 static void output_std_flag_z(FILE *fout, struct parsed_op *po,
5872 int *pfomask, const char *dst_opr_text)
5874 if (*pfomask & (1 << PFO_Z)) {
5875 fprintf(fout, "\n cond_z = (%s%s == 0);",
5876 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5877 *pfomask &= ~(1 << PFO_Z);
5881 static void output_std_flag_s(FILE *fout, struct parsed_op *po,
5882 int *pfomask, const char *dst_opr_text)
5884 if (*pfomask & (1 << PFO_S)) {
5885 fprintf(fout, "\n cond_s = (%s%s < 0);",
5886 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5887 *pfomask &= ~(1 << PFO_S);
5891 static void output_std_flags(FILE *fout, struct parsed_op *po,
5892 int *pfomask, const char *dst_opr_text)
5894 output_std_flag_z(fout, po, pfomask, dst_opr_text);
5895 output_std_flag_s(fout, po, pfomask, dst_opr_text);
5899 OPP_FORCE_NORETURN = (1 << 0),
5900 OPP_SIMPLE_ARGS = (1 << 1),
5901 OPP_ALIGN = (1 << 2),
5904 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
5907 const char *cconv = "";
5909 if (pp->is_fastcall)
5910 cconv = "__fastcall ";
5911 else if (pp->is_stdcall && pp->argc_reg == 0)
5912 cconv = "__stdcall ";
5914 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5916 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
5917 fprintf(fout, "noreturn ");
5920 static void output_pp(FILE *fout, const struct parsed_proto *pp,
5925 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5929 output_pp_attrs(fout, pp, flags);
5932 fprintf(fout, "%s", pp->name);
5937 for (i = 0; i < pp->argc; i++) {
5939 fprintf(fout, ", ");
5940 if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
5941 && !(flags & OPP_SIMPLE_ARGS))
5944 output_pp(fout, pp->arg[i].pp, 0);
5946 else if (pp->arg[i].type.is_retreg) {
5947 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
5950 fprintf(fout, "%s", pp->arg[i].type.name);
5952 fprintf(fout, " a%d", i + 1);
5955 if (pp->arg[i].type.is_64bit)
5958 if (pp->is_vararg) {
5960 fprintf(fout, ", ");
5961 fprintf(fout, "...");
5966 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
5972 snprintf(buf1, sizeof(buf1), "%d", grp);
5973 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
5978 static void gen_x_cleanup(int opcnt);
5980 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
5982 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
5983 struct parsed_opr *last_arith_dst = NULL;
5984 char buf1[256], buf2[256], buf3[256], cast[64];
5985 struct parsed_proto *pp, *pp_tmp;
5986 struct parsed_data *pd;
5987 int save_arg_vars[MAX_ARG_GRP] = { 0, };
5988 unsigned char cbits[MAX_OPS / 8];
5989 const char *float_type;
5990 const char *float_st0;
5991 const char *float_st1;
5992 int need_float_stack = 0;
5993 int need_float_sw = 0; // status word
5994 int need_tmp_var = 0;
5998 int label_pending = 0;
5999 int need_double = 0;
6000 int stack_align = 0;
6001 int stack_fsz_adj = 0;
6002 int regmask_save = 0; // used regs saved/restored in this func
6003 int regmask_arg; // regs from this function args (fastcall, etc)
6004 int regmask_ret; // regs needed on ret
6005 int regmask_now; // temp
6006 int regmask_init = 0; // regs that need zero initialization
6007 int regmask_pp = 0; // regs used in complex push-pop graph
6008 int regmask_ffca = 0; // float function call args
6009 int regmask = 0; // used regs
6019 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
6020 g_stack_frame_used = 0;
6022 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
6023 regmask_init = g_regmask_init;
6025 g_func_pp = proto_parse(fhdr, funcn, 0);
6026 if (g_func_pp == NULL)
6027 ferr(ops, "proto_parse failed for '%s'\n", funcn);
6029 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
6030 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
6033 // - resolve all branches
6034 // - parse calls with labels
6035 resolve_branches_parse_calls(opcnt);
6038 // - handle ebp/esp frame, remove ops related to it
6039 scan_prologue_epilogue(opcnt, &stack_align);
6041 // handle a case where sf size is unalignment, but is
6042 // placed in a way that elements are still aligned
6043 if (g_stack_fsz & 4) {
6044 for (i = 0; i < g_eqcnt; i++) {
6045 if (g_eqs[i].lmod != OPLM_QWORD)
6047 if (!(g_eqs[i].offset & 4)) {
6056 // - remove dead labels
6057 // - set regs needed at ret
6058 for (i = 0; i < opcnt; i++)
6060 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
6065 if (ops[i].op == OP_RET)
6066 ops[i].regmask_src |= regmask_ret;
6070 // - process trivial calls
6071 for (i = 0; i < opcnt; i++)
6074 if (po->flags & (OPF_RMD|OPF_DONE))
6077 if (po->op == OP_CALL)
6079 pp = process_call_early(i, opcnt, &j);
6081 if (!(po->flags & OPF_ATAIL)) {
6082 // since we know the args, try to collect them
6083 ret = collect_call_args_early(i, pp, ®mask, ®mask_ffca);
6091 // commit esp adjust
6092 if (ops[j].op != OP_POP)
6093 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
6095 for (l = 0; l < pp->argc_stack; l++)
6096 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
6100 if (strstr(pp->ret_type.name, "int64"))
6103 po->flags |= OPF_DONE;
6109 // - process calls, stage 2
6110 // - handle some push/pop pairs
6111 // - scan for STD/CLD, propagate DF
6112 // - try to resolve needed x87 status word bits
6113 for (i = 0; i < opcnt; i++)
6118 if (po->flags & OPF_RMD)
6121 if (po->op == OP_CALL)
6123 if (!(po->flags & OPF_DONE)) {
6124 pp = process_call(i, opcnt);
6126 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
6127 // since we know the args, collect them
6128 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
6130 // for unresolved, collect after other passes
6134 ferr_assert(po, pp != NULL);
6136 po->regmask_src |= get_pp_arg_regmask_src(pp);
6137 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
6139 if (po->regmask_dst & mxST0)
6140 po->flags |= OPF_FPUSH;
6142 if (strstr(pp->ret_type.name, "int64"))
6148 if (po->flags & OPF_DONE)
6153 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
6154 && po->operand[0].type == OPT_CONST)
6156 scan_for_pop_const(i, opcnt, i + opcnt * 12);
6161 scan_pushes_for_pop(i, opcnt, ®mask_pp);
6165 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
6166 scan_propagate_df(i + 1, opcnt);
6171 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
6172 ferr(po, "TODO: fnstsw to mem\n");
6173 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
6175 ferr(po, "fnstsw resolve failed\n");
6176 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
6177 (void *)(long)(mask | (z_check << 16)));
6179 ferr(po, "failed to find fcom: %d\n", ret);
6188 // - find POPs for PUSHes, rm both
6189 // - scan for all used registers
6190 memset(cbits, 0, sizeof(cbits));
6191 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
6192 0, ®mask_save, ®mask_init, regmask_arg);
6194 need_float_stack = !!(regmask & mxST7_2);
6197 // - find flag set ops for their users
6198 // - do unresolved calls
6199 // - declare indirect functions
6200 // - other op specific processing
6201 for (i = 0; i < opcnt; i++)
6204 if (po->flags & (OPF_RMD|OPF_DONE))
6207 if (po->flags & OPF_CC)
6209 int setters[16], cnt = 0, branched = 0;
6211 ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
6212 &branched, setters, &cnt);
6213 if (ret < 0 || cnt <= 0)
6214 ferr(po, "unable to trace flag setter(s)\n");
6215 if (cnt > ARRAY_SIZE(setters))
6216 ferr(po, "too many flag setters\n");
6218 for (j = 0; j < cnt; j++)
6220 tmp_op = &ops[setters[j]]; // flag setter
6223 // to get nicer code, we try to delay test and cmp;
6224 // if we can't because of operand modification, or if we
6225 // have arith op, or branch, make it calculate flags explicitly
6226 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
6228 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
6229 pfomask = 1 << po->pfo;
6231 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
6232 pfomask = 1 << po->pfo;
6235 // see if we'll be able to handle based on op result
6236 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
6237 && po->pfo != PFO_Z && po->pfo != PFO_S
6238 && po->pfo != PFO_P)
6240 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
6242 pfomask = 1 << po->pfo;
6245 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
6246 propagate_lmod(tmp_op, &tmp_op->operand[0],
6247 &tmp_op->operand[1]);
6248 if (tmp_op->operand[0].lmod == OPLM_DWORD)
6253 tmp_op->pfomask |= pfomask;
6254 cond_vars |= pfomask;
6256 // note: may overwrite, currently not a problem
6260 if (po->op == OP_RCL || po->op == OP_RCR
6261 || po->op == OP_ADC || po->op == OP_SBB)
6262 cond_vars |= 1 << PFO_C;
6268 cond_vars |= 1 << PFO_Z;
6272 if (po->operand[0].lmod == OPLM_DWORD)
6277 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
6282 // note: resolved non-reg calls are OPF_DONE already
6284 ferr_assert(po, pp != NULL);
6286 if (pp->is_unresolved) {
6287 int regmask_stack = 0;
6288 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
6290 // this is pretty rough guess:
6291 // see ecx and edx were pushed (and not their saved versions)
6292 for (arg = 0; arg < pp->argc; arg++) {
6293 if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
6296 tmp_op = pp->arg[arg].datap;
6298 ferr(po, "parsed_op missing for arg%d\n", arg);
6299 if (tmp_op->operand[0].type == OPT_REG)
6300 regmask_stack |= 1 << tmp_op->operand[0].reg;
6303 if (!((regmask_stack & (1 << xCX))
6304 && (regmask_stack & (1 << xDX))))
6306 if (pp->argc_stack != 0
6307 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
6309 pp_insert_reg_arg(pp, "ecx");
6310 pp->is_fastcall = 1;
6311 regmask_init |= 1 << xCX;
6312 regmask |= 1 << xCX;
6314 if (pp->argc_stack != 0
6315 || ((regmask | regmask_arg) & (1 << xDX)))
6317 pp_insert_reg_arg(pp, "edx");
6318 regmask_init |= 1 << xDX;
6319 regmask |= 1 << xDX;
6323 // note: __cdecl doesn't fall into is_unresolved category
6324 if (pp->argc_stack > 0)
6327 if (!(po->flags & OPF_TAIL)
6328 && !(g_sct_func_attr & SCTFA_NOWARN))
6330 // treat al write as overwrite to avoid many false positives
6331 if (IS(pp->ret_type.name, "void") || pp->ret_type.is_float) {
6332 find_next_read_reg(i + 1, opcnt, xAX, OPLM_BYTE,
6333 i + opcnt * 25, &j);
6335 fnote(po, "eax used after void/float ret call\n");
6336 fnote(&ops[j], "(used here)\n");
6339 if (!strstr(pp->ret_type.name, "int64")) {
6340 find_next_read_reg(i + 1, opcnt, xDX, OPLM_BYTE,
6341 i + opcnt * 26, &j);
6342 // indirect calls are often guessed, don't warn
6343 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j])) {
6344 fnote(po, "edx used after 32bit ret call\n");
6345 fnote(&ops[j], "(used here)\n");
6349 // msvc often relies on callee not modifying 'this'
6350 for (arg = 0; arg < pp->argc; arg++) {
6351 if (pp->arg[arg].reg && IS(pp->arg[arg].reg, "ecx")) {
6357 find_next_read_reg(i + 1, opcnt, xCX, OPLM_BYTE,
6358 i + opcnt * 27, &j);
6359 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j])) {
6360 fnote(po, "ecx used after call\n");
6361 fnote(&ops[j], "(used here)\n");
6368 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
6370 // <var> = offset <something>
6371 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
6372 && !IS_START(po->operand[1].name, "off_"))
6374 if (!po->operand[0].pp->is_fptr)
6375 ferr(po, "%s not declared as fptr when it should be\n",
6376 po->operand[0].name);
6377 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
6378 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
6379 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
6380 fnote(po, "var: %s\n", buf1);
6381 fnote(po, "func: %s\n", buf2);
6382 ferr(po, "^ mismatch\n");
6390 if (po->operand[0].lmod == OPLM_DWORD) {
6391 // 32bit division is common, look for it
6392 if (po->op == OP_DIV)
6393 ret = scan_for_reg_clear(i, xDX);
6395 ret = scan_for_cdq_edx(i);
6397 po->flags |= OPF_32BIT;
6406 po->flags |= OPF_RMD | OPF_DONE;
6416 if (po->operand[0].lmod == OPLM_QWORD)
6426 find_next_read_reg(i + 1, opcnt, xDX, OPLM_DWORD,
6427 i + opcnt * 18, &j);
6429 po->flags |= OPF_32BIT;
6436 // this might need it's own pass...
6437 if (po->op != OP_FST && po->p_argnum > 0)
6438 save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
6440 // correct for "full stack" mode late enable
6441 if ((po->flags & (OPF_PPUSH|OPF_FPOP|OPF_FPOPP))
6442 && need_float_stack)
6443 po->flags |= OPF_FSHIFT;
6446 float_type = need_double ? "double" : "float";
6447 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
6448 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
6450 // output starts here
6453 fprintf(fout, "// had SEH\n");
6455 // define userstack size
6456 if (g_func_pp->is_userstack) {
6457 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
6458 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
6459 fprintf(fout, "#endif\n");
6462 // the function itself
6463 ferr_assert(ops, !g_func_pp->is_fptr);
6464 output_pp(fout, g_func_pp,
6465 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
6466 fprintf(fout, "\n{\n");
6468 // declare indirect functions
6469 for (i = 0; i < opcnt; i++) {
6471 if (po->flags & OPF_RMD)
6474 if (po->op == OP_CALL) {
6477 ferr(po, "NULL pp\n");
6479 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
6480 if (pp->name[0] != 0) {
6481 if (IS_START(pp->name, "guess"))
6484 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
6485 memcpy(pp->name, "i_", 2);
6487 // might be declared already
6489 for (j = 0; j < i; j++) {
6490 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
6491 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
6501 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
6504 output_pp(fout, pp, OPP_SIMPLE_ARGS);
6505 fprintf(fout, ";\n");
6510 // output LUTs/jumptables
6511 for (i = 0; i < g_func_pd_cnt; i++) {
6513 fprintf(fout, " static const ");
6514 if (pd->type == OPT_OFFSET) {
6515 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
6517 for (j = 0; j < pd->count; j++) {
6519 fprintf(fout, ", ");
6520 fprintf(fout, "&&%s", pd->d[j].u.label);
6524 fprintf(fout, "%s %s[] =\n { ",
6525 lmod_type_u(ops, pd->lmod), pd->label);
6527 for (j = 0; j < pd->count; j++) {
6529 fprintf(fout, ", ");
6530 fprintf(fout, "%u", pd->d[j].u.val);
6533 fprintf(fout, " };\n");
6537 // declare stack frame, va_arg
6540 fprintf(fout, " // stack_fsz_adj %d\n", stack_fsz_adj);
6542 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
6543 if (g_func_lmods & (1 << OPLM_WORD))
6544 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
6545 if (g_func_lmods & (1 << OPLM_BYTE))
6546 fprintf(fout, " u8 b[%d];", g_stack_fsz);
6547 if (g_func_lmods & (1 << OPLM_QWORD))
6548 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
6550 if (stack_align > 8)
6551 ferr(ops, "unhandled stack align of %d\n", stack_align);
6552 else if (stack_align == 8)
6553 fprintf(fout, " u64 align;");
6554 fprintf(fout, " } sf;\n");
6558 if (g_func_pp->is_userstack) {
6559 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
6560 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
6564 if (g_func_pp->is_vararg) {
6565 fprintf(fout, " va_list ap;\n");
6569 // declare arg-registers
6570 for (i = 0; i < g_func_pp->argc; i++) {
6571 if (g_func_pp->arg[i].reg != NULL) {
6572 reg = char_array_i(regs_r32,
6573 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
6574 if (regmask & (1 << reg)) {
6575 if (g_func_pp->arg[i].type.is_retreg)
6576 fprintf(fout, " u32 %s = *r_%s;\n",
6577 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
6579 fprintf(fout, " u32 %s = (u32)a%d;\n",
6580 g_func_pp->arg[i].reg, i + 1);
6583 if (g_func_pp->arg[i].type.is_retreg)
6584 ferr(ops, "retreg '%s' is unused?\n",
6585 g_func_pp->arg[i].reg);
6586 fprintf(fout, " // %s = a%d; // unused\n",
6587 g_func_pp->arg[i].reg, i + 1);
6593 // declare normal registers
6594 regmask_now = regmask & ~regmask_arg & ~g_regmask_rm;
6595 regmask_now &= ~(1 << xSP);
6596 if (regmask_now & 0x00ff) {
6597 for (reg = 0; reg < 8; reg++) {
6598 if (regmask_now & (1 << reg)) {
6599 fprintf(fout, " u32 %s", regs_r32[reg]);
6600 if (regmask_init & (1 << reg))
6601 fprintf(fout, " = 0");
6602 fprintf(fout, ";\n");
6608 if (regmask_now & 0xff00) {
6609 for (reg = 8; reg < 16; reg++) {
6610 if (regmask_now & (1 << reg)) {
6611 fprintf(fout, " mmxr %s", regs_r32[reg]);
6612 if (regmask_init & (1 << reg))
6613 fprintf(fout, " = { 0, }");
6614 fprintf(fout, ";\n");
6620 if (need_float_stack) {
6621 fprintf(fout, " %s f_st[8];\n", float_type);
6622 fprintf(fout, " int f_stp = 0;\n");
6626 if (regmask_now & 0xff0000) {
6627 for (reg = 16; reg < 24; reg++) {
6628 if (regmask_now & (1 << reg)) {
6629 fprintf(fout, " %s f_st%d", float_type, reg - 16);
6630 if (regmask_init & (1 << reg))
6631 fprintf(fout, " = 0");
6632 fprintf(fout, ";\n");
6639 if (need_float_sw) {
6640 fprintf(fout, " u16 f_sw;\n");
6645 for (reg = 0; reg < 8; reg++) {
6646 if (regmask_save & (1 << reg)) {
6647 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
6653 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6654 if (save_arg_vars[i] == 0)
6656 for (reg = 0; reg < 32; reg++) {
6657 if (save_arg_vars[i] & (1 << reg)) {
6658 fprintf(fout, " u32 %s;\n",
6659 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
6666 for (reg = 0; reg < 32; reg++) {
6667 if (regmask_ffca & (1 << reg)) {
6668 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
6674 // declare push-pop temporaries
6676 for (reg = 0; reg < 8; reg++) {
6677 if (regmask_pp & (1 << reg)) {
6678 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
6685 for (i = 0; i < 8; i++) {
6686 if (cond_vars & (1 << i)) {
6687 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
6694 fprintf(fout, " u32 tmp;\n");
6699 fprintf(fout, " u64 tmp64;\n");
6704 fprintf(fout, "\n");
6706 // do stack clear, if needed
6707 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6709 if (g_stack_clear_len != 0) {
6710 if (g_stack_clear_len <= 4) {
6711 for (i = 0; i < g_stack_clear_len; i++)
6712 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6713 fprintf(fout, "0;\n");
6716 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6717 g_stack_clear_start, g_stack_clear_len * 4);
6721 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6724 if (g_func_pp->is_vararg) {
6725 if (g_func_pp->argc_stack == 0)
6726 ferr(ops, "vararg func without stack args?\n");
6727 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
6731 for (i = 0; i < opcnt; i++)
6733 if (g_labels[i] != NULL) {
6734 fprintf(fout, "\n%s:\n", g_labels[i]);
6737 delayed_flag_op = NULL;
6738 last_arith_dst = NULL;
6742 if (po->flags & OPF_RMD)
6747 #define assert_operand_cnt(n_) \
6748 if (po->operand_cnt != n_) \
6749 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6751 // conditional/flag using op?
6752 if (po->flags & OPF_CC)
6758 // we go through all this trouble to avoid using parsed_flag_op,
6759 // which makes generated code much nicer
6760 if (delayed_flag_op != NULL)
6762 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6763 po->pfo, po->pfo_inv);
6766 else if (last_arith_dst != NULL
6767 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6768 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6771 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6772 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6773 last_arith_dst->lmod, buf3);
6776 else if (tmp_op != NULL) {
6777 // use preprocessed flag calc results
6778 if (!(tmp_op->pfomask & (1 << po->pfo)))
6779 ferr(po, "not prepared for pfo %d\n", po->pfo);
6781 // note: pfo_inv was not yet applied
6782 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6783 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6786 ferr(po, "all methods of finding comparison failed\n");
6789 if (po->flags & OPF_JMP) {
6790 fprintf(fout, " if %s", buf1);
6792 else if (po->op == OP_RCL || po->op == OP_RCR
6793 || po->op == OP_ADC || po->op == OP_SBB)
6796 fprintf(fout, " cond_%s = %s;\n",
6797 parsed_flag_op_names[po->pfo], buf1);
6799 else if (po->flags & OPF_DATA) { // SETcc
6800 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6801 fprintf(fout, " %s = %s;", buf2, buf1);
6804 ferr(po, "unhandled conditional op\n");
6808 pfomask = po->pfomask;
6813 assert_operand_cnt(2);
6814 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6815 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6816 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
6817 fprintf(fout, " %s = %s;", buf1,
6818 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6823 assert_operand_cnt(2);
6824 po->operand[1].lmod = OPLM_DWORD; // always
6825 fprintf(fout, " %s = %s;",
6826 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6827 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6832 assert_operand_cnt(2);
6833 fprintf(fout, " %s = %s;",
6834 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6835 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6839 assert_operand_cnt(2);
6840 switch (po->operand[1].lmod) {
6842 strcpy(buf3, "(s8)");
6845 strcpy(buf3, "(s16)");
6848 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6850 fprintf(fout, " %s = %s;",
6851 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6852 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6857 assert_operand_cnt(2);
6858 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6859 fprintf(fout, " tmp = %s;",
6860 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6861 fprintf(fout, " %s = %s;",
6862 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6863 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6864 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6865 fprintf(fout, " %s = %stmp;",
6866 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6867 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
6868 snprintf(g_comment, sizeof(g_comment), "xchg");
6872 assert_operand_cnt(1);
6873 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6874 fprintf(fout, " %s = ~%s;", buf1, buf1);
6878 assert_operand_cnt(2);
6879 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6880 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6881 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6882 strcpy(g_comment, "xlat");
6886 assert_operand_cnt(2);
6887 fprintf(fout, " %s = (s32)%s >> 31;",
6888 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6889 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6890 strcpy(g_comment, "cdq");
6894 assert_operand_cnt(1);
6895 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6896 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
6900 if (po->flags & OPF_REP) {
6901 assert_operand_cnt(3);
6906 assert_operand_cnt(2);
6907 fprintf(fout, " %s = %sesi; esi %c= %d;",
6908 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6909 lmod_cast_u_ptr(po, po->operand[1].lmod),
6910 (po->flags & OPF_DF) ? '-' : '+',
6911 lmod_bytes(po, po->operand[1].lmod));
6912 strcpy(g_comment, "lods");
6917 if (po->flags & OPF_REP) {
6918 assert_operand_cnt(3);
6919 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
6920 (po->flags & OPF_DF) ? '-' : '+',
6921 lmod_bytes(po, po->operand[1].lmod));
6922 fprintf(fout, " %sedi = eax;",
6923 lmod_cast_u_ptr(po, po->operand[1].lmod));
6924 strcpy(g_comment, "rep stos");
6927 assert_operand_cnt(2);
6928 fprintf(fout, " %sedi = eax; edi %c= %d;",
6929 lmod_cast_u_ptr(po, po->operand[1].lmod),
6930 (po->flags & OPF_DF) ? '-' : '+',
6931 lmod_bytes(po, po->operand[1].lmod));
6932 strcpy(g_comment, "stos");
6937 j = lmod_bytes(po, po->operand[0].lmod);
6938 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6939 l = (po->flags & OPF_DF) ? '-' : '+';
6940 if (po->flags & OPF_REP) {
6941 assert_operand_cnt(3);
6943 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
6946 " %sedi = %sesi;", buf1, buf1);
6947 strcpy(g_comment, "rep movs");
6950 assert_operand_cnt(2);
6951 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
6952 buf1, buf1, l, j, l, j);
6953 strcpy(g_comment, "movs");
6958 // repe ~ repeat while ZF=1
6959 j = lmod_bytes(po, po->operand[0].lmod);
6960 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6961 l = (po->flags & OPF_DF) ? '-' : '+';
6962 if (po->flags & OPF_REP) {
6963 assert_operand_cnt(3);
6965 " while (ecx != 0) {\n");
6966 if (pfomask & (1 << PFO_C)) {
6969 " cond_c = %sesi < %sedi;\n", buf1, buf1);
6970 pfomask &= ~(1 << PFO_C);
6973 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
6974 buf1, buf1, l, j, l, j);
6977 " if (cond_z %s 0) break;\n",
6978 (po->flags & OPF_REPZ) ? "==" : "!=");
6981 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
6982 (po->flags & OPF_REPZ) ? "e" : "ne");
6985 assert_operand_cnt(2);
6987 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
6988 buf1, buf1, l, j, l, j);
6989 strcpy(g_comment, "cmps");
6991 pfomask &= ~(1 << PFO_Z);
6992 last_arith_dst = NULL;
6993 delayed_flag_op = NULL;
6997 // only does ZF (for now)
6998 // repe ~ repeat while ZF=1
6999 j = lmod_bytes(po, po->operand[1].lmod);
7000 l = (po->flags & OPF_DF) ? '-' : '+';
7001 if (po->flags & OPF_REP) {
7002 assert_operand_cnt(3);
7004 " while (ecx != 0) {\n");
7006 " cond_z = (%seax == %sedi); edi %c= %d;\n",
7007 lmod_cast_u(po, po->operand[1].lmod),
7008 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
7011 " if (cond_z %s 0) break;\n",
7012 (po->flags & OPF_REPZ) ? "==" : "!=");
7015 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
7016 (po->flags & OPF_REPZ) ? "e" : "ne");
7019 assert_operand_cnt(2);
7020 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
7021 lmod_cast_u(po, po->operand[1].lmod),
7022 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
7023 strcpy(g_comment, "scas");
7025 pfomask &= ~(1 << PFO_Z);
7026 last_arith_dst = NULL;
7027 delayed_flag_op = NULL;
7030 // arithmetic w/flags
7032 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
7033 goto dualop_arith_const;
7034 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7038 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7039 if (po->operand[1].type == OPT_CONST) {
7040 j = lmod_bytes(po, po->operand[0].lmod);
7041 if (((1ull << j * 8) - 1) == po->operand[1].val)
7042 goto dualop_arith_const;
7047 assert_operand_cnt(2);
7048 fprintf(fout, " %s %s= %s;",
7049 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7051 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7052 output_std_flags(fout, po, &pfomask, buf1);
7053 last_arith_dst = &po->operand[0];
7054 delayed_flag_op = NULL;
7058 // and 0, or ~0 used instead mov
7059 assert_operand_cnt(2);
7060 fprintf(fout, " %s = %s;",
7061 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7062 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
7063 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7064 output_std_flags(fout, po, &pfomask, buf1);
7065 last_arith_dst = &po->operand[0];
7066 delayed_flag_op = NULL;
7071 assert_operand_cnt(2);
7072 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7073 if (pfomask & (1 << PFO_C)) {
7074 if (po->operand[1].type == OPT_CONST) {
7075 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7076 j = po->operand[1].val;
7079 if (po->op == OP_SHL)
7083 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
7087 ferr(po, "zero shift?\n");
7091 pfomask &= ~(1 << PFO_C);
7093 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
7094 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7095 if (po->operand[1].type != OPT_CONST)
7096 fprintf(fout, " & 0x1f");
7098 output_std_flags(fout, po, &pfomask, buf1);
7099 last_arith_dst = &po->operand[0];
7100 delayed_flag_op = NULL;
7104 assert_operand_cnt(2);
7105 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7106 fprintf(fout, " %s = %s%s >> %s;", buf1,
7107 lmod_cast_s(po, po->operand[0].lmod), buf1,
7108 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7109 output_std_flags(fout, po, &pfomask, buf1);
7110 last_arith_dst = &po->operand[0];
7111 delayed_flag_op = NULL;
7116 assert_operand_cnt(3);
7117 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7118 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7119 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
7120 if (po->operand[2].type != OPT_CONST) {
7121 // no handling for "undefined" case, hopefully not needed
7122 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
7125 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7126 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7127 if (po->op == OP_SHLD) {
7128 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
7129 buf1, buf3, buf1, buf2, l, buf3);
7130 strcpy(g_comment, "shld");
7133 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
7134 buf1, buf3, buf1, buf2, l, buf3);
7135 strcpy(g_comment, "shrd");
7137 output_std_flags(fout, po, &pfomask, buf1);
7138 last_arith_dst = &po->operand[0];
7139 delayed_flag_op = NULL;
7144 assert_operand_cnt(2);
7145 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7146 if (po->operand[1].type == OPT_CONST) {
7147 j = po->operand[1].val;
7148 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
7149 fprintf(fout, po->op == OP_ROL ?
7150 " %s = (%s << %d) | (%s >> %d);" :
7151 " %s = (%s >> %d) | (%s << %d);",
7152 buf1, buf1, j, buf1,
7153 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
7157 output_std_flags(fout, po, &pfomask, buf1);
7158 last_arith_dst = &po->operand[0];
7159 delayed_flag_op = NULL;
7164 assert_operand_cnt(2);
7165 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7166 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7167 if (po->operand[1].type == OPT_CONST) {
7168 j = po->operand[1].val % l;
7170 ferr(po, "zero rotate\n");
7171 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
7172 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
7173 if (po->op == OP_RCL) {
7175 " %s = (%s << %d) | (cond_c << %d)",
7176 buf1, buf1, j, j - 1);
7178 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
7182 " %s = (%s >> %d) | (cond_c << %d)",
7183 buf1, buf1, j, l - j);
7185 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
7187 fprintf(fout, ";\n");
7188 fprintf(fout, " cond_c = tmp;");
7192 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
7193 output_std_flags(fout, po, &pfomask, buf1);
7194 last_arith_dst = &po->operand[0];
7195 delayed_flag_op = NULL;
7199 assert_operand_cnt(2);
7200 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7201 if (IS(opr_name(po, 0), opr_name(po, 1))) {
7202 // special case for XOR
7203 int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
7204 for (j = 0; j <= PFO_LE; j++) {
7205 if (pfomask & (1 << j)) {
7206 fprintf(fout, " cond_%s = %d;\n",
7207 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
7208 pfomask &= ~(1 << j);
7211 fprintf(fout, " %s = 0;",
7212 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7213 last_arith_dst = &po->operand[0];
7214 delayed_flag_op = NULL;
7220 assert_operand_cnt(2);
7221 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7222 if (pfomask & (1 << PFO_C)) {
7223 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7224 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7225 if (po->operand[0].lmod == OPLM_DWORD) {
7226 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
7227 fprintf(fout, " cond_c = tmp64 >> 32;\n");
7228 fprintf(fout, " %s = (u32)tmp64;",
7229 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7230 strcat(g_comment, " add64");
7233 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
7234 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
7235 fprintf(fout, " %s += %s;",
7236 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7239 pfomask &= ~(1 << PFO_C);
7240 output_std_flags(fout, po, &pfomask, buf1);
7241 last_arith_dst = &po->operand[0];
7242 delayed_flag_op = NULL;
7245 if (pfomask & (1 << PFO_LE)) {
7246 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
7247 fprintf(fout, " cond_%s = %s;\n",
7248 parsed_flag_op_names[PFO_LE], buf1);
7249 pfomask &= ~(1 << PFO_LE);
7254 assert_operand_cnt(2);
7255 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7256 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
7257 for (j = 0; j <= PFO_LE; j++) {
7258 if (!(pfomask & (1 << j)))
7260 if (j == PFO_Z || j == PFO_S)
7263 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7264 fprintf(fout, " cond_%s = %s;\n",
7265 parsed_flag_op_names[j], buf1);
7266 pfomask &= ~(1 << j);
7273 assert_operand_cnt(2);
7274 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7275 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7276 if (po->op == OP_SBB
7277 && IS(po->operand[0].name, po->operand[1].name))
7279 // avoid use of unitialized var
7280 fprintf(fout, " %s = -cond_c;", buf1);
7281 // carry remains what it was
7282 pfomask &= ~(1 << PFO_C);
7285 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
7286 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7288 output_std_flags(fout, po, &pfomask, buf1);
7289 last_arith_dst = &po->operand[0];
7290 delayed_flag_op = NULL;
7295 // on SKL, if src is 0, dst is left unchanged
7296 assert_operand_cnt(2);
7297 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7298 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7299 output_std_flag_z(fout, po, &pfomask, buf2);
7300 if (po->op == OP_BSF)
7301 snprintf(buf3, sizeof(buf3), "__builtin_ffs(%s) - 1", buf2);
7303 snprintf(buf3, sizeof(buf3), "31 - __builtin_clz(%s)", buf2);
7304 fprintf(fout, " if (%s) %s = %s;", buf2, buf1, buf3);
7305 last_arith_dst = &po->operand[0];
7306 delayed_flag_op = NULL;
7307 strcat(g_comment, po->op == OP_BSF ? " bsf" : " bsr");
7311 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
7312 for (j = 0; j <= PFO_LE; j++) {
7313 if (!(pfomask & (1 << j)))
7315 if (j == PFO_Z || j == PFO_S || j == PFO_C)
7318 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7319 fprintf(fout, " cond_%s = %s;\n",
7320 parsed_flag_op_names[j], buf1);
7321 pfomask &= ~(1 << j);
7327 if (pfomask & (1 << PFO_C))
7328 // carry is unaffected by inc/dec.. wtf?
7329 ferr(po, "carry propagation needed\n");
7331 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7332 if (po->operand[0].type == OPT_REG) {
7333 strcpy(buf2, po->op == OP_INC ? "++" : "--");
7334 fprintf(fout, " %s%s;", buf1, buf2);
7337 strcpy(buf2, po->op == OP_INC ? "+" : "-");
7338 fprintf(fout, " %s %s= 1;", buf1, buf2);
7340 output_std_flags(fout, po, &pfomask, buf1);
7341 last_arith_dst = &po->operand[0];
7342 delayed_flag_op = NULL;
7346 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7347 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
7348 fprintf(fout, " %s = -%s%s;", buf1,
7349 lmod_cast_s(po, po->operand[0].lmod), buf2);
7350 last_arith_dst = &po->operand[0];
7351 delayed_flag_op = NULL;
7352 if (pfomask & PFOB_C) {
7353 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
7356 output_std_flags(fout, po, &pfomask, buf1);
7360 if (po->operand_cnt == 2) {
7361 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7364 if (po->operand_cnt == 3)
7365 ferr(po, "TODO imul3\n");
7368 assert_operand_cnt(1);
7369 switch (po->operand[0].lmod) {
7371 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
7372 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
7373 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
7374 fprintf(fout, " edx = tmp64 >> 32;\n");
7375 fprintf(fout, " eax = tmp64;");
7378 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
7379 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
7380 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
7384 ferr(po, "TODO: unhandled mul type\n");
7387 last_arith_dst = NULL;
7388 delayed_flag_op = NULL;
7393 assert_operand_cnt(1);
7394 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7395 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
7396 po->op == OP_IDIV));
7397 switch (po->operand[0].lmod) {
7399 if (po->flags & OPF_32BIT)
7400 snprintf(buf2, sizeof(buf2), "%seax", cast);
7402 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7403 snprintf(buf2, sizeof(buf2), "%stmp64",
7404 (po->op == OP_IDIV) ? "(s64)" : "");
7406 if (po->operand[0].type == OPT_REG
7407 && po->operand[0].reg == xDX)
7409 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
7410 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
7413 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
7414 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
7418 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
7419 snprintf(buf2, sizeof(buf2), "%stmp",
7420 (po->op == OP_IDIV) ? "(s32)" : "");
7421 if (po->operand[0].type == OPT_REG
7422 && po->operand[0].reg == xDX)
7424 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
7426 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
7430 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
7432 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
7435 strcat(g_comment, " div16");
7438 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
7440 last_arith_dst = NULL;
7441 delayed_flag_op = NULL;
7446 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7448 for (j = 0; j < 8; j++) {
7449 if (pfomask & (1 << j)) {
7450 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
7451 fprintf(fout, " cond_%s = %s;",
7452 parsed_flag_op_names[j], buf1);
7459 last_arith_dst = NULL;
7460 delayed_flag_op = po;
7464 // SETcc - should already be handled
7467 // note: we reuse OP_Jcc for SETcc, only flags differ
7469 fprintf(fout, "\n goto %s;", po->operand[0].name);
7473 fprintf(fout, " if (ecx == 0)\n");
7474 fprintf(fout, " goto %s;", po->operand[0].name);
7475 strcat(g_comment, " jecxz");
7479 fprintf(fout, " if (--ecx != 0)\n");
7480 fprintf(fout, " goto %s;", po->operand[0].name);
7481 strcat(g_comment, " loop");
7485 assert_operand_cnt(1);
7486 last_arith_dst = NULL;
7487 delayed_flag_op = NULL;
7489 if (po->operand[0].type == OPT_REGMEM) {
7490 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
7493 ferr(po, "parse failure for jmp '%s'\n",
7494 po->operand[0].name);
7495 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
7498 else if (po->operand[0].type != OPT_LABEL)
7499 ferr(po, "unhandled jmp type\n");
7501 fprintf(fout, " goto %s;", po->operand[0].name);
7505 assert_operand_cnt(1);
7507 my_assert_not(pp, NULL);
7510 if (po->flags & OPF_CC) {
7511 // we treat conditional branch to another func
7512 // (yes such code exists..) as conditional tailcall
7514 fprintf(fout, " {\n");
7517 if (pp->is_fptr && !pp->is_arg) {
7518 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
7519 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7522 if (pp->is_fptr && (pp->is_unresolved || pp->is_guessed)) {
7523 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
7524 buf3, asmfn, po->asmln, pp->name);
7527 fprintf(fout, "%s", buf3);
7528 if (strstr(pp->ret_type.name, "int64")) {
7529 if (po->flags & OPF_TAIL)
7530 ferr(po, "int64 and tail?\n");
7531 fprintf(fout, "tmp64 = ");
7533 else if (!IS(pp->ret_type.name, "void")) {
7534 if (po->flags & OPF_TAIL) {
7535 if (regmask_ret & mxAX) {
7536 fprintf(fout, "return ");
7537 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
7538 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
7540 else if (regmask_ret & mxST0)
7541 ferr(po, "float tailcall\n");
7543 else if (po->regmask_dst & mxAX) {
7544 fprintf(fout, "eax = ");
7545 if (pp->ret_type.is_ptr)
7546 fprintf(fout, "(u32)");
7548 else if (po->regmask_dst & mxST0) {
7549 ferr_assert(po, po->flags & OPF_FPUSH);
7550 if (need_float_stack)
7551 fprintf(fout, "f_st[--f_stp & 7] = ");
7553 fprintf(fout, "f_st0 = ");
7557 if (pp->name[0] == 0)
7558 ferr(po, "missing pp->name\n");
7559 fprintf(fout, "%s%s(", pp->name,
7560 pp->has_structarg ? "_sa" : "");
7562 if (po->flags & OPF_ATAIL) {
7564 g_func_pp->is_stdcall && g_func_pp->argc_stack > 0;
7565 check_compat |= pp->argc_stack > 0;
7567 && (pp->argc_stack != g_func_pp->argc_stack
7568 || pp->is_stdcall != g_func_pp->is_stdcall))
7569 ferr(po, "incompatible arg-reuse tailcall\n");
7570 if (g_func_pp->has_retreg)
7571 ferr(po, "TODO: retreg+tailcall\n");
7573 for (arg = j = 0; arg < pp->argc; arg++) {
7575 fprintf(fout, ", ");
7578 if (pp->arg[arg].type.is_ptr)
7579 snprintf(cast, sizeof(cast), "(%s)",
7580 pp->arg[arg].type.name);
7582 if (pp->arg[arg].reg != NULL) {
7583 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7587 for (; j < g_func_pp->argc; j++)
7588 if (g_func_pp->arg[j].reg == NULL)
7590 fprintf(fout, "%sa%d", cast, j + 1);
7595 for (arg = 0; arg < pp->argc; arg++) {
7597 fprintf(fout, ", ");
7600 if (pp->arg[arg].type.is_ptr)
7601 snprintf(cast, sizeof(cast), "(%s)",
7602 pp->arg[arg].type.name);
7604 if (pp->arg[arg].reg != NULL) {
7605 if (pp->arg[arg].type.is_retreg)
7606 fprintf(fout, "&%s", pp->arg[arg].reg);
7607 else if (IS(pp->arg[arg].reg, "ebp")
7608 && g_bp_frame && !(po->flags & OPF_EBP_S))
7610 // rare special case
7611 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
7612 strcat(g_comment, " bp_ref");
7615 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7620 tmp_op = pp->arg[arg].datap;
7622 ferr(po, "parsed_op missing for arg%d\n", arg);
7624 if (tmp_op->flags & OPF_VAPUSH) {
7625 fprintf(fout, "ap");
7627 else if (tmp_op->op == OP_FST) {
7628 fprintf(fout, "fs_%d", tmp_op->p_argnum);
7629 if (tmp_op->operand[0].lmod == OPLM_QWORD)
7632 else if (pp->arg[arg].type.is_64bit) {
7633 ferr_assert(po, tmp_op->p_argpass == 0);
7634 ferr_assert(po, !pp->arg[arg].is_saved);
7635 ferr_assert(po, !pp->arg[arg].type.is_float);
7636 ferr_assert(po, cast[0] == 0);
7637 out_src_opr(buf1, sizeof(buf1),
7638 tmp_op, &tmp_op->operand[0], cast, 0);
7639 tmp_op = pp->arg[++arg].datap;
7640 ferr_assert(po, tmp_op != NULL);
7641 out_src_opr(buf2, sizeof(buf2),
7642 tmp_op, &tmp_op->operand[0], cast, 0);
7643 fprintf(fout, "((u64)(%s) << 32) | (%s)",
7646 else if (tmp_op->p_argpass != 0) {
7647 ferr_assert(po, !pp->arg[arg].type.is_float);
7648 fprintf(fout, "a%d", tmp_op->p_argpass);
7650 else if (pp->arg[arg].is_saved) {
7651 ferr_assert(po, tmp_op->p_argnum > 0);
7652 ferr_assert(po, !pp->arg[arg].type.is_float);
7653 fprintf(fout, "%s%s", cast,
7654 saved_arg_name(buf1, sizeof(buf1),
7655 tmp_op->p_arggrp, tmp_op->p_argnum));
7657 else if (pp->arg[arg].type.is_float) {
7658 ferr_assert(po, !pp->arg[arg].type.is_64bit);
7660 out_src_opr_float(buf1, sizeof(buf1),
7661 tmp_op, &tmp_op->operand[0], need_float_stack));
7665 out_src_opr(buf1, sizeof(buf1),
7666 tmp_op, &tmp_op->operand[0], cast, 0));
7670 fprintf(fout, ");");
7672 if (strstr(pp->ret_type.name, "int64")) {
7673 fprintf(fout, "\n");
7674 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7675 fprintf(fout, "%seax = tmp64;", buf3);
7678 if (pp->is_unresolved) {
7679 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
7681 strcat(g_comment, buf2);
7684 if (po->flags & OPF_TAIL) {
7686 if (i == opcnt - 1 || pp->is_noreturn)
7688 else if (IS(pp->ret_type.name, "void"))
7690 else if (!(regmask_ret & (1 << xAX)))
7692 // else already handled as 'return f()'
7695 fprintf(fout, "\n%sreturn;", buf3);
7696 strcat(g_comment, " ^ tailcall");
7699 strcat(g_comment, " tailcall");
7701 if ((regmask_ret & (1 << xAX))
7702 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7704 ferr(po, "int func -> void func tailcall?\n");
7707 if (pp->is_noreturn)
7708 strcat(g_comment, " noreturn");
7709 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7710 strcat(g_comment, " argframe");
7711 if (po->flags & OPF_CC)
7712 strcat(g_comment, " cond");
7714 if (po->flags & OPF_CC)
7715 fprintf(fout, "\n }");
7717 delayed_flag_op = NULL;
7718 last_arith_dst = NULL;
7722 if (g_func_pp->is_vararg)
7723 fprintf(fout, " va_end(ap);\n");
7724 if (g_func_pp->has_retreg) {
7725 for (arg = 0; arg < g_func_pp->argc; arg++)
7726 if (g_func_pp->arg[arg].type.is_retreg)
7727 fprintf(fout, " *r_%s = %s;\n",
7728 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7731 if (regmask_ret & mxST0) {
7732 fprintf(fout, " return %s;", float_st0);
7734 else if (!(regmask_ret & mxAX)) {
7735 if (i != opcnt - 1 || label_pending)
7736 fprintf(fout, " return;");
7738 else if (g_func_pp->ret_type.is_ptr) {
7739 fprintf(fout, " return (%s)eax;",
7740 g_func_pp->ret_type.name);
7742 else if (IS(g_func_pp->ret_type.name, "__int64"))
7743 fprintf(fout, " return ((u64)edx << 32) | eax;");
7745 fprintf(fout, " return eax;");
7747 last_arith_dst = NULL;
7748 delayed_flag_op = NULL;
7752 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7753 if (po->p_argnum != 0) {
7754 // special case - saved func arg
7755 fprintf(fout, " %s = %s;",
7756 saved_arg_name(buf2, sizeof(buf2),
7757 po->p_arggrp, po->p_argnum), buf1);
7760 else if (po->flags & OPF_RSAVE) {
7761 fprintf(fout, " s_%s = %s;", buf1, buf1);
7764 else if (po->flags & OPF_PPUSH) {
7766 ferr_assert(po, tmp_op != NULL);
7767 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7768 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7771 else if (g_func_pp->is_userstack) {
7772 fprintf(fout, " *(--esp) = %s;", buf1);
7775 if (!(g_ida_func_attr & IDAFA_NORETURN))
7776 ferr(po, "stray push encountered\n");
7781 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7782 if (po->flags & OPF_RSAVE) {
7783 fprintf(fout, " %s = s_%s;", buf1, buf1);
7786 else if (po->flags & OPF_PPUSH) {
7787 // push/pop graph / non-const
7788 ferr_assert(po, po->datap == NULL);
7789 fprintf(fout, " %s = pp_%s;", buf1, buf1);
7792 else if (po->datap != NULL) {
7795 fprintf(fout, " %s = %s;", buf1,
7796 out_src_opr(buf2, sizeof(buf2),
7797 tmp_op, &tmp_op->operand[0],
7798 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7801 else if (g_func_pp->is_userstack) {
7802 fprintf(fout, " %s = *esp++;", buf1);
7806 ferr(po, "stray pop encountered\n");
7816 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7817 fprintf(fout, " tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
7818 po->op == OPP_ALLSHL ? "<<" : ">>");
7819 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
7820 strcat(g_comment, po->op == OPP_ALLSHL
7821 ? " allshl" : " allshr");
7826 if (need_float_stack) {
7827 out_src_opr_float(buf1, sizeof(buf1),
7828 po, &po->operand[0], 1);
7829 if (po->regmask_src & mxSTa) {
7830 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7834 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
7837 if (po->flags & OPF_FSHIFT)
7838 fprintf(fout, " f_st1 = f_st0;");
7839 if (po->operand[0].type == OPT_REG
7840 && po->operand[0].reg == xST0)
7842 strcat(g_comment, " fld st");
7845 fprintf(fout, " f_st0 = %s;",
7846 out_src_opr_float(buf1, sizeof(buf1),
7847 po, &po->operand[0], 0));
7849 strcat(g_comment, " fld");
7853 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7854 lmod_cast(po, po->operand[0].lmod, 1), 0);
7855 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7856 if (need_float_stack) {
7857 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
7860 if (po->flags & OPF_FSHIFT)
7861 fprintf(fout, " f_st1 = f_st0;");
7862 fprintf(fout, " f_st0 = %s;", buf2);
7864 strcat(g_comment, " fild");
7868 if (need_float_stack)
7869 fprintf(fout, " f_st[--f_stp & 7] = ");
7871 if (po->flags & OPF_FSHIFT)
7872 fprintf(fout, " f_st1 = f_st0;");
7873 fprintf(fout, " f_st0 = ");
7875 switch (po->operand[0].val) {
7876 case X87_CONST_1: fprintf(fout, "1.0;"); break;
7877 case X87_CONST_L2T: fprintf(fout, "3.321928094887362;"); break;
7878 case X87_CONST_L2E: fprintf(fout, "M_LOG2E;"); break;
7879 case X87_CONST_PI: fprintf(fout, "M_PI;"); break;
7880 case X87_CONST_LG2: fprintf(fout, "0.301029995663981;"); break;
7881 case X87_CONST_LN2: fprintf(fout, "M_LN2;"); break;
7882 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
7883 default: ferr_assert(po, 0); break;
7888 if (po->flags & OPF_FARG) {
7889 // store to stack as func arg
7890 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7894 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7896 dead_dst = po->operand[0].type == OPT_REG
7897 && po->operand[0].reg == xST0;
7900 fprintf(fout, " %s = %s;", buf1, float_st0);
7901 if (po->flags & OPF_FSHIFT) {
7902 if (need_float_stack)
7903 fprintf(fout, " f_stp++;");
7905 fprintf(fout, " f_st0 = f_st1;");
7907 if (dead_dst && !(po->flags & OPF_FSHIFT))
7910 strcat(g_comment, " fst");
7914 fprintf(fout, " %s = %s%s;",
7915 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7916 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7917 if (po->flags & OPF_FSHIFT) {
7918 if (need_float_stack)
7919 fprintf(fout, " f_stp++;");
7921 fprintf(fout, " f_st0 = f_st1;");
7923 strcat(g_comment, " fist");
7930 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7932 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7934 dead_dst = (po->flags & OPF_FPOP)
7935 && po->operand[0].type == OPT_REG
7936 && po->operand[0].reg == xST0;
7938 case OP_FADD: j = '+'; break;
7939 case OP_FDIV: j = '/'; break;
7940 case OP_FMUL: j = '*'; break;
7941 case OP_FSUB: j = '-'; break;
7942 default: j = 'x'; break;
7944 if (need_float_stack) {
7946 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7947 if (po->flags & OPF_FSHIFT)
7948 fprintf(fout, " f_stp++;");
7951 if (po->flags & OPF_FSHIFT) {
7952 // note: assumes only 2 regs handled
7954 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
7956 fprintf(fout, " f_st0 = f_st1;");
7959 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7961 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7966 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7968 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7970 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
7972 dead_dst = (po->flags & OPF_FPOP)
7973 && po->operand[0].type == OPT_REG
7974 && po->operand[0].reg == xST0;
7975 j = po->op == OP_FDIVR ? '/' : '-';
7976 if (need_float_stack) {
7978 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7979 if (po->flags & OPF_FSHIFT)
7980 fprintf(fout, " f_stp++;");
7983 if (po->flags & OPF_FSHIFT) {
7985 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
7987 fprintf(fout, " f_st0 = f_st1;");
7990 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7992 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
8000 case OP_FIADD: j = '+'; break;
8001 case OP_FIDIV: j = '/'; break;
8002 case OP_FIMUL: j = '*'; break;
8003 case OP_FISUB: j = '-'; break;
8004 default: j = 'x'; break;
8006 fprintf(fout, " %s %c= (%s)%s;", float_st0,
8008 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
8009 lmod_cast(po, po->operand[0].lmod, 1), 0));
8014 fprintf(fout, " %s = %s %c %s;", float_st0,
8015 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
8017 po->op == OP_FIDIVR ? '/' : '-', float_st0);
8022 ferr_assert(po, po->datap != NULL);
8023 mask = (long)po->datap & 0xffff;
8024 z_check = ((long)po->datap >> 16) & 1;
8025 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8027 if (mask == 0x0100 || mask == 0x0500) { // C0 -> <
8028 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
8031 else if (mask == 0x4000 || mask == 0x4400) { // C3 -> =
8032 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
8035 else if (mask == 0x4100) { // C3, C0
8037 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
8039 strcat(g_comment, " z_chk_det");
8042 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
8043 "(%s < %s ? 0x0100 : 0);",
8044 float_st0, buf1, float_st0, buf1);
8048 ferr(po, "unhandled sw mask: %x\n", mask);
8049 if (po->flags & OPF_FSHIFT) {
8050 if (need_float_stack) {
8051 if (po->flags & OPF_FPOPP)
8052 fprintf(fout, " f_stp += 2;");
8054 fprintf(fout, " f_stp++;");
8057 ferr_assert(po, !(po->flags & OPF_FPOPP));
8058 fprintf(fout, " f_st0 = f_st1;");
8065 fprintf(fout, " %s = f_sw;",
8066 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
8070 fprintf(fout, " %s = -%s;", float_st0, float_st0);
8074 fprintf(fout, " %s = cos%s(%s);", float_st0,
8075 need_double ? "" : "f", float_st0);
8079 if (need_float_stack) {
8080 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
8081 need_double ? "" : "f", float_st1, float_st0);
8082 fprintf(fout, " f_stp++;");
8085 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
8086 need_double ? "" : "f");
8091 if (need_float_stack) {
8092 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
8093 float_st1, need_double ? "" : "f", float_st0);
8094 fprintf(fout, " f_stp++;");
8097 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
8098 need_double ? "" : "f");
8100 strcat(g_comment, " fyl2x");
8104 fprintf(fout, " %s = sin%s(%s);", float_st0,
8105 need_double ? "" : "f", float_st0);
8109 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
8110 need_double ? "" : "f", float_st0);
8114 dead_dst = po->operand[0].type == OPT_REG
8115 && po->operand[0].reg == xST0;
8117 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8119 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
8120 float_st0, float_st0, buf1, buf1);
8121 strcat(g_comment, " fxch");
8128 ferr_assert(po, po->flags & OPF_32BIT);
8129 fprintf(fout, " eax = (s32)%s;", float_st0);
8130 if (po->flags & OPF_FSHIFT) {
8131 if (need_float_stack)
8132 fprintf(fout, " f_stp++;");
8134 fprintf(fout, " f_st0 = f_st1;");
8136 strcat(g_comment, " ftol");
8140 if (need_float_stack) {
8141 fprintf(fout, " %s = pow%s(%s, %s);", float_st1,
8142 need_double ? "" : "f", float_st1, float_st0);
8143 fprintf(fout, " f_stp++;");
8146 fprintf(fout, " f_st0 = pow%s(f_st1, f_st0);",
8147 need_double ? "" : "f");
8149 strcat(g_comment, " CIpow");
8153 fprintf(fout, " do_skip_code_abort();");
8158 fprintf(fout, " do_emms();");
8163 ferr(po, "unhandled op type %d, flags %x\n",
8168 if (g_comment[0] != 0) {
8169 char *p = g_comment;
8170 while (my_isblank(*p))
8172 fprintf(fout, " // %s", p);
8177 fprintf(fout, "\n");
8179 // some sanity checking
8180 if (po->flags & OPF_REP) {
8181 if (po->op != OP_STOS && po->op != OP_MOVS
8182 && po->op != OP_CMPS && po->op != OP_SCAS)
8183 ferr(po, "unexpected rep\n");
8184 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
8185 && (po->op == OP_CMPS || po->op == OP_SCAS))
8186 ferr(po, "cmps/scas with plain rep\n");
8188 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
8189 && po->op != OP_CMPS && po->op != OP_SCAS)
8190 ferr(po, "unexpected repz/repnz\n");
8193 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
8195 // see is delayed flag stuff is still valid
8196 if (delayed_flag_op != NULL && delayed_flag_op != po) {
8197 if (is_any_opr_modified(delayed_flag_op, po, 0))
8198 delayed_flag_op = NULL;
8201 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
8202 if (is_opr_modified(last_arith_dst, po))
8203 last_arith_dst = NULL;
8210 if (g_stack_fsz && !g_stack_frame_used)
8211 fprintf(fout, " (void)sf;\n");
8213 fprintf(fout, "}\n\n");
8215 gen_x_cleanup(opcnt);
8218 static void gen_x_cleanup(int opcnt)
8222 for (i = 0; i < opcnt; i++) {
8223 struct label_ref *lr, *lr_del;
8225 lr = g_label_refs[i].next;
8226 while (lr != NULL) {
8231 g_label_refs[i].i = -1;
8232 g_label_refs[i].next = NULL;
8234 if (ops[i].op == OP_CALL) {
8236 proto_release(ops[i].pp);
8242 struct func_proto_dep;
8244 struct func_prototype {
8248 int regmask_dep; // likely register args
8249 int regmask_use; // used registers
8250 int has_ret:3; // -1, 0, 1: unresolved, no, yes
8251 unsigned int has_ret64:1;
8252 unsigned int dep_resolved:1;
8253 unsigned int is_stdcall:1;
8254 unsigned int eax_pass:1; // returns without touching eax
8255 struct func_proto_dep *dep_func;
8257 const struct parsed_proto *pp; // seed pp, if any
8260 struct func_proto_dep {
8262 struct func_prototype *proto;
8263 int regmask_live; // .. at the time of call
8264 unsigned int ret_dep:1; // return from this is caller's return
8265 unsigned int has_ret:1; // found from eax use after return
8266 unsigned int has_ret64:1;
8269 static struct func_prototype *hg_fp;
8270 static int hg_fp_cnt;
8272 static struct scanned_var {
8274 enum opr_lenmod lmod;
8275 unsigned int is_seeded:1;
8276 unsigned int is_c_str:1;
8277 const struct parsed_proto *pp; // seed pp, if any
8279 static int hg_var_cnt;
8281 static char **hg_refs;
8282 static int hg_ref_cnt;
8284 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8287 static struct func_prototype *hg_fp_add(const char *funcn)
8289 struct func_prototype *fp;
8291 if ((hg_fp_cnt & 0xff) == 0) {
8292 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
8293 my_assert_not(hg_fp, NULL);
8294 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
8297 fp = &hg_fp[hg_fp_cnt];
8298 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
8300 fp->argc_stack = -1;
8306 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
8311 for (i = 0; i < fp->dep_func_cnt; i++)
8312 if (IS(fp->dep_func[i].name, name))
8313 return &fp->dep_func[i];
8318 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
8321 if (hg_fp_find_dep(fp, name))
8324 if ((fp->dep_func_cnt & 0xff) == 0) {
8325 fp->dep_func = realloc(fp->dep_func,
8326 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
8327 my_assert_not(fp->dep_func, NULL);
8328 memset(&fp->dep_func[fp->dep_func_cnt], 0,
8329 sizeof(fp->dep_func[0]) * 0x100);
8331 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
8335 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
8337 const struct func_prototype *p1 = p1_, *p2 = p2_;
8338 return strcmp(p1->name, p2->name);
8342 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
8344 const struct func_prototype *p1 = p1_, *p2 = p2_;
8345 return p1->id - p2->id;
8349 static void hg_ref_add(const char *name)
8351 if ((hg_ref_cnt & 0xff) == 0) {
8352 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
8353 my_assert_not(hg_refs, NULL);
8354 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
8357 hg_refs[hg_ref_cnt] = strdup(name);
8358 my_assert_not(hg_refs[hg_ref_cnt], NULL);
8362 // recursive register dep pass
8363 // - track saved regs (part 2)
8364 // - try to figure out arg-regs
8365 // - calculate reg deps
8366 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
8367 struct func_prototype *fp, int regmask_save, int regmask_dst,
8368 int *regmask_dep, int *regmask_use, int *has_ret)
8370 struct func_proto_dep *dep;
8371 struct parsed_op *po;
8372 int from_caller = 0;
8377 for (; i < opcnt; i++)
8379 if (cbits[i >> 3] & (1 << (i & 7)))
8381 cbits[i >> 3] |= (1 << (i & 7));
8385 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
8386 if (po->flags & OPF_RMD)
8389 if (po->btj != NULL) {
8391 for (j = 0; j < po->btj->count; j++) {
8392 check_i(po, po->btj->d[j].bt_i);
8393 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
8394 regmask_save, regmask_dst, regmask_dep, regmask_use,
8400 check_i(po, po->bt_i);
8401 if (po->flags & OPF_CJMP) {
8402 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
8403 regmask_save, regmask_dst, regmask_dep, regmask_use,
8412 if (po->flags & OPF_FARG)
8413 /* (just calculate register deps) */;
8414 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
8416 reg = po->operand[0].reg;
8417 ferr_assert(po, reg >= 0);
8419 if (po->flags & OPF_RSAVE) {
8420 regmask_save |= 1 << reg;
8423 if (po->flags & OPF_DONE)
8426 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0, 0);
8428 regmask_save |= 1 << reg;
8429 po->flags |= OPF_RMD;
8430 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, OPF_RMD);
8434 else if (po->flags & OPF_RMD)
8436 else if (po->op == OP_CALL) {
8437 po->regmask_dst |= 1 << xAX;
8439 dep = hg_fp_find_dep(fp, po->operand[0].name);
8441 dep->regmask_live = regmask_save | regmask_dst;
8442 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8443 dep->regmask_live |= 1 << xBP;
8446 else if (po->op == OP_RET) {
8447 if (po->operand_cnt > 0) {
8449 if (fp->argc_stack >= 0
8450 && fp->argc_stack != po->operand[0].val / 4)
8451 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
8452 fp->argc_stack = po->operand[0].val / 4;
8456 if (!fp->eax_pass && (po->flags & OPF_TAIL)) {
8457 if (po->op == OP_CALL) {
8462 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
8465 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
8468 if (ret != 1 && from_caller) {
8469 // unresolved eax - probably void func
8474 if (j >= 0 && ops[j].op == OP_CALL) {
8475 if (ops[j].pp != NULL && !ops[j].pp->is_unresolved) {
8476 int call_has_ret = !IS(ops[j].pp->ret_type.name, "void");
8477 if (ops[j].pp->is_noreturn) {
8478 // could be some fail path
8480 *has_ret = call_has_ret;
8483 *has_ret = call_has_ret;
8486 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
8498 l = regmask_save | regmask_dst;
8499 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8502 l = po->regmask_src & ~l;
8505 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
8506 l, regmask_dst, regmask_save, po->flags);
8509 *regmask_use |= (po->regmask_src | po->regmask_dst)
8511 regmask_dst |= po->regmask_dst;
8513 if (po->flags & OPF_TAIL) {
8514 if (!(po->flags & OPF_CC)) // not cond. tailcall
8520 static void gen_hdr(const char *funcn, int opcnt)
8522 unsigned char cbits[MAX_OPS / 8];
8523 const struct parsed_proto *pp_c;
8524 struct parsed_proto *pp;
8525 struct func_prototype *fp;
8526 struct func_proto_dep *dep;
8527 struct parsed_op *po;
8528 int regmask_dummy = 0;
8531 int max_bp_offset = 0;
8536 pp_c = proto_parse(g_fhdr, funcn, 1);
8538 // already in seed, will add to hg_fp later
8541 fp = hg_fp_add(funcn);
8543 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
8544 g_stack_frame_used = 0;
8548 // - resolve all branches
8549 // - parse calls with labels
8550 resolve_branches_parse_calls(opcnt);
8553 // - handle ebp/esp frame, remove ops related to it
8554 scan_prologue_epilogue(opcnt, NULL);
8557 // - remove dead labels
8559 for (i = 0; i < opcnt; i++)
8561 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8567 if (po->flags & (OPF_RMD|OPF_DONE))
8570 if (po->op == OP_CALL) {
8571 if (po->operand[0].type == OPT_LABEL)
8572 hg_fp_add_dep(fp, opr_name(po, 0));
8573 else if (po->pp != NULL)
8574 hg_fp_add_dep(fp, po->pp->name);
8579 // - handle push <const>/pop pairs
8580 for (i = 0; i < opcnt; i++)
8583 if (po->flags & (OPF_RMD|OPF_DONE))
8586 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
8587 scan_for_pop_const(i, opcnt, i + opcnt * 13);
8591 // - process trivial calls
8592 for (i = 0; i < opcnt; i++)
8595 if (po->flags & (OPF_RMD|OPF_DONE))
8598 if (po->op == OP_CALL)
8600 pp = process_call_early(i, opcnt, &j);
8602 if (!(po->flags & OPF_ATAIL))
8603 // since we know the args, try to collect them
8604 if (collect_call_args_early(i, pp, NULL, NULL) != 0)
8610 // commit esp adjust
8611 if (ops[j].op != OP_POP)
8612 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
8614 for (l = 0; l < pp->argc_stack; l++)
8615 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
8619 po->flags |= OPF_DONE;
8625 // - track saved regs (simple)
8627 for (i = 0; i < opcnt; i++)
8630 if (po->flags & (OPF_RMD|OPF_DONE))
8633 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
8634 && po->operand[0].reg != xCX)
8636 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
8638 // regmask_save |= 1 << po->operand[0].reg; // do it later
8639 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
8640 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
8643 else if (po->op == OP_CALL)
8645 pp = process_call(i, opcnt);
8647 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
8648 // since we know the args, collect them
8649 ret = collect_call_args(po, i, pp, ®mask_dummy,
8652 if (!(po->flags & OPF_TAIL)
8653 && po->operand[0].type == OPT_LABEL)
8655 dep = hg_fp_find_dep(fp, opr_name(po, 0));
8656 ferr_assert(po, dep != NULL);
8657 // treat al write as overwrite to avoid many false positives
8658 find_next_read_reg(i + 1, opcnt, xAX, OPLM_BYTE,
8659 i + opcnt * 25, &j);
8662 find_next_read_reg(i + 1, opcnt, xDX, OPLM_BYTE,
8663 i + opcnt * 26, &j);
8664 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j]))
8671 memset(cbits, 0, (opcnt + 7) / 8);
8672 regmask_dep = regmask_use = 0;
8675 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0,
8676 ®mask_dep, ®mask_use, &has_ret);
8678 // find unreachable code - must be fixed in IDA
8679 for (i = 0; i < opcnt; i++)
8681 if (cbits[i >> 3] & (1 << (i & 7)))
8684 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
8685 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
8687 // the compiler sometimes still generates code after
8688 // noreturn OS functions
8691 if (!(ops[i].flags & OPF_RMD)
8692 && ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
8694 ferr(&ops[i], "unreachable code\n");
8698 for (i = 0; i < g_eqcnt; i++) {
8699 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
8700 max_bp_offset = g_eqs[i].offset;
8703 if (fp->argc_stack < 0) {
8704 max_bp_offset = (max_bp_offset + 3) & ~3;
8705 fp->argc_stack = max_bp_offset / 4;
8706 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
8710 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
8711 fp->regmask_use = regmask_use;
8712 fp->has_ret = has_ret;
8714 printf("// has_ret %d, regmask_dep %x\n",
8715 fp->has_ret, fp->regmask_dep);
8716 output_hdr_fp(stdout, fp, 1);
8717 if (IS(funcn, "sub_10007F72")) exit(1);
8720 gen_x_cleanup(opcnt);
8723 static void hg_fp_resolve_deps(struct func_prototype *fp)
8725 struct func_prototype fp_s;
8726 struct func_proto_dep *dep;
8730 // this thing is recursive, so mark first..
8731 fp->dep_resolved = 1;
8733 for (i = 0; i < fp->dep_func_cnt; i++) {
8734 dep = &fp->dep_func[i];
8736 strcpy(fp_s.name, dep->name);
8737 dep->proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8738 sizeof(hg_fp[0]), hg_fp_cmp_name);
8739 if (dep->proto != NULL) {
8740 if (!dep->proto->dep_resolved)
8741 hg_fp_resolve_deps(dep->proto);
8743 regmask_dep = ~dep->regmask_live
8744 & dep->proto->regmask_dep;
8745 fp->regmask_dep |= regmask_dep;
8746 // printf("dep %s %s |= %x\n", fp->name,
8747 // fp->dep_func[i].name, regmask_dep);
8749 if (dep->has_ret && (dep->proto->regmask_use & mxAX))
8750 dep->proto->has_ret = 1;
8751 if (dep->has_ret64 && (dep->proto->regmask_use & mxDX))
8752 dep->proto->has_ret64 = 1;
8753 if (fp->has_ret == -1 && dep->ret_dep)
8754 fp->has_ret = dep->proto->has_ret;
8759 // make all thiscall/edx arg functions referenced from .data fastcall
8760 static void do_func_refs_from_data(void)
8762 struct func_prototype *fp, fp_s;
8765 for (i = 0; i < hg_ref_cnt; i++) {
8766 strcpy(fp_s.name, hg_refs[i]);
8767 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8768 sizeof(hg_fp[0]), hg_fp_cmp_name);
8772 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
8773 fp->regmask_dep |= mxCX | mxDX;
8777 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8780 const struct parsed_proto *pp;
8781 char *p, namebuf[NAMELEN];
8787 for (; count > 0; count--, fp++) {
8788 if (fp->has_ret == -1)
8789 fprintf(fout, "// ret unresolved\n");
8791 fprintf(fout, "// dep:");
8792 for (j = 0; j < fp->dep_func_cnt; j++) {
8793 fprintf(fout, " %s/", fp->dep_func[j].name);
8794 if (fp->dep_func[j].proto != NULL)
8795 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8796 fp->dep_func[j].proto->has_ret);
8798 fprintf(fout, "\n");
8801 p = strchr(fp->name, '@');
8803 memcpy(namebuf, fp->name, p - fp->name);
8804 namebuf[p - fp->name] = 0;
8812 pp = proto_parse(g_fhdr, name, 1);
8813 if (pp != NULL && pp->is_include)
8816 if (fp->pp != NULL) {
8817 // part of seed, output later
8821 regmask_dep = fp->regmask_dep;
8822 argc_normal = fp->argc_stack;
8824 fprintf(fout, "%-5s",
8825 fp->pp ? fp->pp->ret_type.name :
8826 fp->has_ret64 ? "__int64" :
8827 fp->has_ret ? "int" : "void");
8828 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
8829 && (regmask_dep & ~mxCX) == 0)
8831 fprintf(fout, "/*__thiscall*/ ");
8835 else if ((regmask_dep == (mxCX | mxDX)
8836 && (fp->is_stdcall || fp->argc_stack == 0))
8837 || (regmask_dep == mxCX && fp->argc_stack == 0))
8839 fprintf(fout, " __fastcall ");
8840 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8846 else if (regmask_dep && !fp->is_stdcall) {
8847 fprintf(fout, "/*__usercall*/ ");
8849 else if (regmask_dep) {
8850 fprintf(fout, "/*__userpurge*/ ");
8852 else if (fp->is_stdcall)
8853 fprintf(fout, " __stdcall ");
8855 fprintf(fout, " __cdecl ");
8857 fprintf(fout, "%s(", name);
8860 for (j = 0; j < xSP; j++) {
8861 if (regmask_dep & (1 << j)) {
8864 fprintf(fout, ", ");
8866 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8868 fprintf(fout, "int");
8869 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
8873 for (j = 0; j < argc_normal; j++) {
8876 fprintf(fout, ", ");
8877 if (fp->pp != NULL) {
8878 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8879 if (!fp->pp->arg[arg - 1].type.is_ptr)
8883 fprintf(fout, "int ");
8884 fprintf(fout, "a%d", arg);
8887 fprintf(fout, ");\n");
8891 static void output_hdr(FILE *fout)
8893 static const char *lmod_c_names[] = {
8894 [OPLM_UNSPEC] = "???",
8895 [OPLM_BYTE] = "uint8_t",
8896 [OPLM_WORD] = "uint16_t",
8897 [OPLM_DWORD] = "uint32_t",
8898 [OPLM_QWORD] = "uint64_t",
8900 const struct scanned_var *var;
8901 struct func_prototype *fp;
8902 char line[256] = { 0, };
8906 // add stuff from headers
8907 for (i = 0; i < pp_cache_size; i++) {
8908 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
8909 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
8911 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
8912 fp = hg_fp_add(name);
8913 fp->pp = &pp_cache[i];
8914 fp->argc_stack = fp->pp->argc_stack;
8915 fp->is_stdcall = fp->pp->is_stdcall;
8916 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
8917 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
8921 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
8922 for (i = 0; i < hg_fp_cnt; i++)
8923 hg_fp_resolve_deps(&hg_fp[i]);
8925 // adjust functions referenced from data segment
8926 do_func_refs_from_data();
8928 // final adjustments
8929 for (i = 0; i < hg_fp_cnt; i++) {
8930 if (hg_fp[i].eax_pass && (hg_fp[i].regmask_dep & mxAX))
8931 hg_fp[i].has_ret = 1;
8934 // note: messes up .proto ptr, don't use
8935 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
8938 for (i = 0; i < hg_var_cnt; i++) {
8941 if (var->pp != NULL)
8944 else if (var->is_c_str)
8945 fprintf(fout, "extern %-8s %s[];", "char", var->name);
8947 fprintf(fout, "extern %-8s %s;",
8948 lmod_c_names[var->lmod], var->name);
8951 fprintf(fout, " // seeded");
8952 fprintf(fout, "\n");
8955 fprintf(fout, "\n");
8957 // output function prototypes
8958 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
8961 fprintf(fout, "\n// - seed -\n");
8964 while (fgets(line, sizeof(line), g_fhdr))
8965 fwrite(line, 1, strlen(line), fout);
8968 // '=' needs special treatment
8970 static char *next_word_s(char *w, size_t wsize, char *s)
8977 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
8979 for (i = 1; i < wsize - 1; i++) {
8981 printf("warning: missing closing quote: \"%s\"\n", s);
8990 for (; i < wsize - 1; i++) {
8991 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
8997 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
8998 printf("warning: '%s' truncated\n", w);
9003 static int cmpstringp(const void *p1, const void *p2)
9005 return strcmp(*(char * const *)p1, *(char * const *)p2);
9008 static int is_xref_needed(char *p, char **rlist, int rlist_len)
9013 if (strstr(p, "..."))
9014 // unable to determine, assume needed
9017 if (*p == '.') // .text, .data, ...
9018 // ref from other data or non-function -> no
9021 p2 = strpbrk(p, "+:\r\n\x18");
9024 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9025 // referenced from removed code
9031 static int ida_xrefs_show_need(FILE *fasm, char *p,
9032 char **rlist, int rlist_len)
9038 p = strrchr(p, ';');
9039 if (p != NULL && *p == ';') {
9040 if (IS_START(p + 2, "sctref"))
9042 if (IS_START(p + 2, "DATA XREF: ")) {
9044 if (is_xref_needed(p, rlist, rlist_len))
9052 if (!my_fgets(line, sizeof(line), fasm))
9054 // non-first line is always indented
9055 if (!my_isblank(line[0]))
9058 // should be no content, just comment
9063 p = strrchr(p, ';');
9066 if (IS_START(p, "sctref")) {
9071 // it's printed once, but no harm to check again
9072 if (IS_START(p, "DATA XREF: "))
9075 if (is_xref_needed(p, rlist, rlist_len)) {
9080 fseek(fasm, pos, SEEK_SET);
9084 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
9086 struct scanned_var *var;
9087 char line[256] = { 0, };
9096 // skip to next data section
9097 while (my_fgets(line, sizeof(line), fasm))
9102 if (*p == 0 || *p == ';')
9105 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
9106 if (*p == 0 || *p == ';')
9109 if (*p != 's' || !IS_START(p, "segment para public"))
9115 if (p == NULL || !IS_START(p, "segment para public"))
9119 if (!IS_START(p, "'DATA'"))
9123 while (my_fgets(line, sizeof(line), fasm))
9128 no_identifier = my_isblank(*p);
9131 if (*p == 0 || *p == ';')
9134 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9135 words[wordc][0] = 0;
9136 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9137 if (*p == 0 || *p == ';') {
9143 if (wordc == 2 && IS(words[1], "ends"))
9148 if (no_identifier) {
9149 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
9150 hg_ref_add(words[2]);
9154 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
9155 // when this starts, we don't need anything from this section
9159 // check refs comment(s)
9160 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
9163 if ((hg_var_cnt & 0xff) == 0) {
9164 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
9165 * (hg_var_cnt + 0x100));
9166 my_assert_not(hg_vars, NULL);
9167 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
9170 var = &hg_vars[hg_var_cnt++];
9171 snprintf(var->name, sizeof(var->name), "%s", words[0]);
9173 // maybe already in seed header?
9174 var->pp = proto_parse(g_fhdr, var->name, 1);
9175 if (var->pp != NULL) {
9176 if (var->pp->is_fptr) {
9177 var->lmod = OPLM_DWORD;
9180 else if (var->pp->is_func)
9182 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
9183 aerr("unhandled C type '%s' for '%s'\n",
9184 var->pp->type.name, var->name);
9190 if (IS(words[1], "dd")) {
9191 var->lmod = OPLM_DWORD;
9192 if (wordc >= 4 && IS(words[2], "offset"))
9193 hg_ref_add(words[3]);
9195 else if (IS(words[1], "dw"))
9196 var->lmod = OPLM_WORD;
9197 else if (IS(words[1], "db")) {
9198 var->lmod = OPLM_BYTE;
9199 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
9200 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
9204 else if (IS(words[1], "dq"))
9205 var->lmod = OPLM_QWORD;
9206 //else if (IS(words[1], "dt"))
9208 aerr("type '%s' not known\n", words[1]);
9216 static void set_label(int i, const char *name)
9222 p = strchr(name, ':');
9226 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
9227 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
9228 g_labels[i] = realloc(g_labels[i], len + 1);
9229 my_assert_not(g_labels[i], NULL);
9230 memcpy(g_labels[i], name, len);
9231 g_labels[i][len] = 0;
9240 static struct chunk_item *func_chunks;
9241 static int func_chunk_cnt;
9242 static int func_chunk_alloc;
9244 static void add_func_chunk(FILE *fasm, const char *name, int line)
9246 if (func_chunk_cnt >= func_chunk_alloc) {
9247 func_chunk_alloc *= 2;
9248 func_chunks = realloc(func_chunks,
9249 func_chunk_alloc * sizeof(func_chunks[0]));
9250 my_assert_not(func_chunks, NULL);
9252 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
9253 func_chunks[func_chunk_cnt].name = strdup(name);
9254 func_chunks[func_chunk_cnt].asmln = line;
9258 static int cmp_chunks(const void *p1, const void *p2)
9260 const struct chunk_item *c1 = p1, *c2 = p2;
9261 return strcmp(c1->name, c2->name);
9264 static void scan_ahead_for_chunks(FILE *fasm)
9274 oldpos = ftell(fasm);
9277 while (my_fgets(line, sizeof(line), fasm))
9288 // get rid of random tabs
9289 for (i = 0; line[i] != 0; i++)
9290 if (line[i] == '\t')
9293 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9296 next_word(words[0], sizeof(words[0]), p);
9297 if (words[0][0] == 0)
9298 aerr("missing name for func chunk?\n");
9300 add_func_chunk(fasm, words[0], asmln);
9302 else if (IS_START(p, "; sctend"))
9308 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9309 words[wordc][0] = 0;
9310 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9311 if (*p == 0 || *p == ';') {
9317 if (wordc == 2 && IS(words[1], "ends"))
9321 fseek(fasm, oldpos, SEEK_SET);
9325 int main(int argc, char *argv[])
9327 FILE *fout, *fasm, *frlist;
9328 struct parsed_data *pd = NULL;
9330 char **rlist = NULL;
9332 int rlist_alloc = 0;
9333 int func_chunks_used = 0;
9334 int func_chunks_sorted = 0;
9335 int func_chunk_i = -1;
9336 long func_chunk_ret = 0;
9337 int func_chunk_ret_ln = 0;
9338 int scanned_ahead = 0;
9340 char words[20][256];
9341 enum opr_lenmod lmod;
9342 char *sctproto = NULL;
9344 int pending_endp = 0;
9346 int skip_code_end = 0;
9347 int skip_warned = 0;
9360 for (arg = 1; arg < argc; arg++) {
9361 if (IS(argv[arg], "-v"))
9363 else if (IS(argv[arg], "-rf"))
9364 g_allow_regfunc = 1;
9365 else if (IS(argv[arg], "-uc"))
9366 g_allow_user_icall = 1;
9367 else if (IS(argv[arg], "-m"))
9369 else if (IS(argv[arg], "-hdr"))
9370 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
9375 if (argc < arg + 3) {
9376 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
9377 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
9379 " -hdr - header generation mode\n"
9380 " -rf - allow unannotated indirect calls\n"
9381 " -uc - allow ind. calls/refs to __usercall\n"
9382 " -m - allow multiple .text sections\n"
9383 "[rlist] is a file with function names to skip,"
9391 asmfn = argv[arg++];
9392 fasm = fopen(asmfn, "r");
9393 my_assert_not(fasm, NULL);
9395 hdrfn = argv[arg++];
9396 g_fhdr = fopen(hdrfn, "r");
9397 my_assert_not(g_fhdr, NULL);
9400 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
9401 my_assert_not(rlist, NULL);
9402 // needs special handling..
9403 rlist[rlist_len++] = "__alloca_probe";
9405 func_chunk_alloc = 32;
9406 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
9407 my_assert_not(func_chunks, NULL);
9409 memset(words, 0, sizeof(words));
9411 for (; arg < argc; arg++) {
9414 frlist = fopen(argv[arg], "r");
9415 my_assert_not(frlist, NULL);
9417 while (my_fgets(line, sizeof(line), frlist)) {
9419 if (*p == 0 || *p == ';')
9422 if (IS_START(p, "#if 0")
9423 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
9427 else if (IS_START(p, "#endif"))
9434 p = next_word(words[0], sizeof(words[0]), p);
9435 if (words[0][0] == 0)
9438 if (rlist_len >= rlist_alloc) {
9439 rlist_alloc = rlist_alloc * 2 + 64;
9440 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
9441 my_assert_not(rlist, NULL);
9443 rlist[rlist_len++] = strdup(words[0]);
9451 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
9453 fout = fopen(argv[arg_out], "w");
9454 my_assert_not(fout, NULL);
9457 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
9458 my_assert_not(g_eqs, NULL);
9460 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
9461 g_label_refs[i].i = -1;
9462 g_label_refs[i].next = NULL;
9466 scan_variables(fasm, rlist, rlist_len);
9468 while (my_fgets(line, sizeof(line), fasm))
9477 // get rid of random tabs
9478 for (i = 0; line[i] != 0; i++)
9479 if (line[i] == '\t')
9484 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
9485 goto do_pending_endp; // eww..
9487 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
9489 static const char *attrs[] = {
9498 // parse IDA's attribute-list comment
9499 g_ida_func_attr = 0;
9502 for (; *p != 0; p = sskip(p)) {
9503 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9504 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9505 g_ida_func_attr |= 1 << i;
9506 p += strlen(attrs[i]);
9510 if (i == ARRAY_SIZE(attrs)) {
9511 anote("unparsed IDA attr: %s\n", p);
9514 if (IS(attrs[i], "fpd=")) {
9515 p = next_word(words[0], sizeof(words[0]), p);
9520 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
9522 static const char *attrs[] = {
9529 // parse manual attribute-list comment
9530 g_sct_func_attr = 0;
9533 for (; *p != 0; p = sskip(p)) {
9534 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9535 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9536 g_sct_func_attr |= 1 << i;
9537 p += strlen(attrs[i]);
9544 // clear_sf=start,len (in dwords)
9545 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
9546 &g_stack_clear_len, &j);
9548 // clear_regmask=<mask>
9549 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
9551 // rm_regmask=<mask>
9552 ret = sscanf(p, "=%x%n", &g_regmask_rm, &j) + 1;
9554 anote("unparsed attr value: %s\n", p);
9559 else if (i == ARRAY_SIZE(attrs)) {
9560 anote("unparsed sct attr: %s\n", p);
9565 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9568 next_word(words[0], sizeof(words[0]), p);
9569 if (words[0][0] == 0)
9570 aerr("missing name for func chunk?\n");
9572 if (!scanned_ahead) {
9573 add_func_chunk(fasm, words[0], asmln);
9574 func_chunks_sorted = 0;
9577 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
9579 if (func_chunk_i >= 0) {
9580 if (func_chunk_i < func_chunk_cnt
9581 && IS(func_chunks[func_chunk_i].name, g_func))
9583 // move on to next chunk
9584 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9586 aerr("seek failed for '%s' chunk #%d\n",
9587 g_func, func_chunk_i);
9588 asmln = func_chunks[func_chunk_i].asmln;
9592 if (func_chunk_ret == 0)
9593 aerr("no return from chunk?\n");
9594 fseek(fasm, func_chunk_ret, SEEK_SET);
9595 asmln = func_chunk_ret_ln;
9601 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
9602 func_chunks_used = 1;
9604 if (IS_START(g_func, "sub_")) {
9605 unsigned long addr = strtoul(p, NULL, 16);
9606 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
9607 if (addr > f_addr && !scanned_ahead) {
9608 //anote("scan_ahead caused by '%s', addr %lx\n",
9610 scan_ahead_for_chunks(fasm);
9612 func_chunks_sorted = 0;
9620 for (i = wordc; i < ARRAY_SIZE(words); i++)
9622 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9623 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9624 if (*p == 0 || *p == ';') {
9629 if (*p != 0 && *p != ';')
9630 aerr("too many words\n");
9632 if (skip_code_end) {
9637 // allow asm patches in comments
9639 // skip IDA's forced non-removable comment
9640 if (!IS_START(p, "; sct") && (p2 = strchr(p + 1, ';')))
9643 if (*p == ';' && IS_START(p, "; sct")) {
9644 if (IS_START(p, "; sctpatch:")) {
9646 if (*p == 0 || *p == ';')
9648 goto parse_words; // lame
9650 if (IS_START(p, "; sctproto:")) {
9651 sctproto = strdup(p + 11);
9653 else if (IS_START(p, "; sctend")) {
9658 else if (IS_START(p, "; sctskip_start")) {
9659 if (in_func && !g_skip_func) {
9661 ops[pi].op = OPP_ABORT;
9662 ops[pi].asmln = asmln;
9668 else if (IS_START(p, "; sctskip_end")) {
9676 awarn("wordc == 0?\n");
9680 // don't care about this:
9681 if (words[0][0] == '.'
9682 || IS(words[0], "include")
9683 || IS(words[0], "assume") || IS(words[1], "segment")
9684 || IS(words[0], "align"))
9690 // do delayed endp processing to collect switch jumptables
9692 if (in_func && !g_skip_func && !end && wordc >= 2
9693 && ((words[0][0] == 'd' && words[0][2] == 0)
9694 || (words[1][0] == 'd' && words[1][2] == 0)))
9697 if (words[1][0] == 'd' && words[1][2] == 0) {
9699 if (g_func_pd_cnt >= pd_alloc) {
9700 pd_alloc = pd_alloc * 2 + 16;
9701 g_func_pd = realloc(g_func_pd,
9702 sizeof(g_func_pd[0]) * pd_alloc);
9703 my_assert_not(g_func_pd, NULL);
9705 pd = &g_func_pd[g_func_pd_cnt];
9707 memset(pd, 0, sizeof(*pd));
9708 strcpy(pd->label, words[0]);
9709 pd->type = OPT_CONST;
9710 pd->lmod = lmod_from_directive(words[1]);
9716 anote("skipping alignment byte?\n");
9719 lmod = lmod_from_directive(words[0]);
9720 if (lmod != pd->lmod)
9721 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
9724 if (pd->count_alloc < pd->count + wordc) {
9725 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
9726 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
9727 my_assert_not(pd->d, NULL);
9729 for (; i < wordc; i++) {
9730 if (IS(words[i], "offset")) {
9731 pd->type = OPT_OFFSET;
9734 p = strchr(words[i], ',');
9737 if (pd->type == OPT_OFFSET)
9738 pd->d[pd->count].u.label = strdup(words[i]);
9740 pd->d[pd->count].u.val = parse_number(words[i], 0);
9741 pd->d[pd->count].bt_i = -1;
9747 if (in_func && !g_skip_func) {
9749 gen_hdr(g_func, pi);
9751 gen_func(fout, g_fhdr, g_func, pi);
9756 g_ida_func_attr = 0;
9757 g_sct_func_attr = 0;
9758 g_stack_clear_start = 0;
9759 g_stack_clear_len = 0;
9766 func_chunks_used = 0;
9769 memset(&ops, 0, pi * sizeof(ops[0]));
9774 for (i = 0; i < g_func_pd_cnt; i++) {
9776 if (pd->type == OPT_OFFSET) {
9777 for (j = 0; j < pd->count; j++)
9778 free(pd->d[j].u.label);
9793 if (IS(words[1], "proc")) {
9795 aerr("proc '%s' while in_func '%s'?\n",
9798 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9800 strcpy(g_func, words[0]);
9801 set_label(0, words[0]);
9806 if (IS(words[1], "endp"))
9809 aerr("endp '%s' while not in_func?\n", words[0]);
9810 if (!IS(g_func, words[0]))
9811 aerr("endp '%s' while in_func '%s'?\n",
9814 aerr("endp '%s' while skipping code\n", words[0]);
9816 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
9817 && ops[0].op == OP_JMP && ops[0].operand[0].segment)
9823 if (!g_skip_func && func_chunks_used) {
9824 // start processing chunks
9825 struct chunk_item *ci, key = { g_func, 0 };
9827 func_chunk_ret = ftell(fasm);
9828 func_chunk_ret_ln = asmln;
9829 if (!func_chunks_sorted) {
9830 qsort(func_chunks, func_chunk_cnt,
9831 sizeof(func_chunks[0]), cmp_chunks);
9832 func_chunks_sorted = 1;
9834 ci = bsearch(&key, func_chunks, func_chunk_cnt,
9835 sizeof(func_chunks[0]), cmp_chunks);
9837 aerr("'%s' needs chunks, but none found\n", g_func);
9838 func_chunk_i = ci - func_chunks;
9839 for (; func_chunk_i > 0; func_chunk_i--)
9840 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
9843 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9845 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
9846 asmln = func_chunks[func_chunk_i].asmln;
9854 if (wordc == 2 && IS(words[1], "ends")) {
9858 goto do_pending_endp;
9862 // scan for next text segment
9863 while (my_fgets(line, sizeof(line), fasm)) {
9866 if (*p == 0 || *p == ';')
9869 if (strstr(p, "segment para public 'CODE' use32"))
9876 p = strchr(words[0], ':');
9878 set_label(pi, words[0]);
9882 if (!in_func || g_skip_func || skip_code) {
9883 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
9885 anote("skipping from '%s'\n", g_labels[pi]);
9889 g_labels[pi] = NULL;
9893 if (wordc > 1 && IS(words[1], "="))
9896 aerr("unhandled equ, wc=%d\n", wordc);
9897 if (g_eqcnt >= eq_alloc) {
9899 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
9900 my_assert_not(g_eqs, NULL);
9903 len = strlen(words[0]);
9904 if (len > sizeof(g_eqs[0].name) - 1)
9905 aerr("equ name too long: %d\n", len);
9906 strcpy(g_eqs[g_eqcnt].name, words[0]);
9908 if (!IS(words[3], "ptr"))
9909 aerr("unhandled equ\n");
9910 if (IS(words[2], "dword"))
9911 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
9912 else if (IS(words[2], "word"))
9913 g_eqs[g_eqcnt].lmod = OPLM_WORD;
9914 else if (IS(words[2], "byte"))
9915 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
9916 else if (IS(words[2], "qword"))
9917 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
9919 aerr("bad lmod: '%s'\n", words[2]);
9921 g_eqs[g_eqcnt].offset = parse_number(words[4], 0);
9926 if (pi >= ARRAY_SIZE(ops))
9927 aerr("too many ops\n");
9929 parse_op(&ops[pi], words, wordc);
9931 ops[pi].datap = sctproto;
9946 // vim:ts=2:shiftwidth=2:expandtab