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 %d (%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 static int scan_prologue(int i, int opcnt, int *ecx_push, int *esp_sub)
4153 for (; i < opcnt; i++)
4154 if (!(ops[i].flags & OPF_DONE))
4157 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4158 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4164 for (; i < opcnt; i++) {
4165 if (i > 0 && g_labels[i] != NULL)
4167 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
4169 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
4170 && ops[i].operand[1].type == OPT_CONST)
4172 g_stack_fsz += opr_const(&ops[i], 1);
4173 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4178 if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
4179 && ops[i].operand[1].type == OPT_CONST)
4181 for (j = i + 1; j < opcnt; j++)
4182 if (!(ops[j].flags & OPF_DONE))
4184 if (ops[j].op == OP_CALL
4185 && IS(opr_name(&ops[j], 0), "__alloca_probe"))
4187 g_stack_fsz += opr_const(&ops[i], 1);
4188 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4189 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4200 static void scan_prologue_epilogue(int opcnt, int *stack_align)
4202 int ecx_push = 0, esp_sub = 0, pusha = 0;
4203 int sandard_epilogue;
4207 if (g_seh_found == 2) {
4208 eliminate_seh_calls(opcnt);
4212 eliminate_seh(opcnt);
4213 // ida treats seh as part of sf
4214 g_stack_fsz = g_seh_size;
4218 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
4219 && ops[1].op == OP_MOV
4220 && IS(opr_name(&ops[1], 0), "ebp")
4221 && IS(opr_name(&ops[1], 1), "esp"))
4224 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4225 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4227 for (i = 2; i < opcnt; i++)
4228 if (!(ops[i].flags & OPF_DONE))
4231 if (ops[i].op == OP_PUSHA) {
4232 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4237 if (ops[i].op == OP_AND && ops[i].operand[0].reg == xSP
4238 && ops[i].operand[1].type == OPT_CONST)
4240 l = ops[i].operand[1].val;
4242 if (j == -1 || (l >> j) != -1)
4243 ferr(&ops[i], "unhandled esp align: %x\n", l);
4244 if (stack_align != NULL)
4245 *stack_align = 1 << j;
4246 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4250 i = scan_prologue(i, opcnt, &ecx_push, &esp_sub);
4254 for (; i < opcnt; i++)
4255 if (ops[i].flags & OPF_TAIL)
4258 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4259 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4265 sandard_epilogue = 0;
4266 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
4268 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4269 // the standard epilogue is sometimes even used without a sf
4270 if (ops[j - 1].op == OP_MOV
4271 && IS(opr_name(&ops[j - 1], 0), "esp")
4272 && IS(opr_name(&ops[j - 1], 1), "ebp"))
4273 sandard_epilogue = 1;
4275 else if (ops[j].op == OP_LEAVE)
4277 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4278 sandard_epilogue = 1;
4280 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
4281 && ops[i].pp->is_noreturn)
4283 // on noreturn, msvc sometimes cleans stack, sometimes not
4288 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4289 ferr(&ops[j], "'pop ebp' expected\n");
4291 if (g_stack_fsz != 0 || sandard_epilogue) {
4292 if (ops[j].op == OP_LEAVE)
4294 else if (sandard_epilogue) // mov esp, ebp
4296 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4299 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4301 ferr(&ops[j], "esp restore expected\n");
4304 if (ecx_push && j >= 0 && ops[j].op == OP_POP
4305 && IS(opr_name(&ops[j], 0), "ecx"))
4307 ferr(&ops[j], "unexpected ecx pop\n");
4312 if (ops[j].op == OP_POPA)
4313 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4315 ferr(&ops[j], "popa expected\n");
4320 } while (i < opcnt);
4323 ferr(ops, "missing ebp epilogue\n");
4328 i = scan_prologue(0, opcnt, &ecx_push, &esp_sub);
4330 if (ecx_push && !esp_sub) {
4331 // could actually be args for a call..
4332 for (; i < opcnt; i++)
4333 if (ops[i].op != OP_PUSH)
4336 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
4337 const struct parsed_proto *pp;
4338 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
4339 j = pp ? pp->argc_stack : 0;
4340 while (i > 0 && j > 0) {
4342 if (ops[i].op == OP_PUSH) {
4343 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
4348 ferr(&ops[i], "unhandled prologue\n");
4352 g_stack_fsz = g_seh_size;
4353 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4354 if (!(ops[i].flags & OPF_RMD))
4364 if (ecx_push || esp_sub)
4369 for (; i < opcnt; i++)
4370 if (ops[i].flags & OPF_TAIL)
4374 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4375 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4380 else if (i < opcnt && (ops[i].flags & OPF_ATAIL)) {
4381 // skip arg updates for arg-reuse tailcall
4382 for (; j >= 0; j--) {
4383 if (ops[j].op != OP_MOV)
4385 if (ops[j].operand[0].type != OPT_REGMEM)
4387 if (strstr(ops[j].operand[0].name, "arg_") == NULL)
4392 if (ecx_push > 0 && !esp_sub) {
4393 for (l = 0; l < ecx_push && j >= 0; l++) {
4394 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
4396 else if (ops[j].op == OP_ADD
4397 && IS(opr_name(&ops[j], 0), "esp")
4398 && ops[j].operand[1].type == OPT_CONST)
4401 l += ops[j].operand[1].val / 4 - 1;
4406 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4409 if (l != ecx_push) {
4410 if (i < opcnt && ops[i].op == OP_CALL
4411 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4413 // noreturn tailcall with no epilogue
4418 ferr(&ops[j], "epilogue scan failed\n");
4425 if (ops[j].op != OP_ADD
4426 || !IS(opr_name(&ops[j], 0), "esp")
4427 || ops[j].operand[1].type != OPT_CONST)
4429 if (i < opcnt && ops[i].op == OP_CALL
4430 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4432 // noreturn tailcall with no epilogue
4437 ferr(&ops[j], "'add esp' expected\n");
4440 if (ops[j].operand[1].val < g_stack_fsz)
4441 ferr(&ops[j], "esp adj is too low (need %d)\n", g_stack_fsz);
4443 ops[j].operand[1].val -= g_stack_fsz; // for stack arg scanner
4444 if (ops[j].operand[1].val == 0)
4445 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4450 } while (i < opcnt);
4453 ferr(ops, "missing esp epilogue\n");
4457 // find an instruction that changed opr before i op
4458 // *op_i must be set to -1 by the caller
4459 // *is_caller is set to 1 if one source is determined to be g_func arg
4460 // returns 1 if found, *op_i is then set to origin
4461 // returns -1 if multiple origins are found
4462 static int resolve_origin(int i, const struct parsed_opr *opr,
4463 int magic, int *op_i, int *is_caller)
4465 struct label_ref *lr;
4469 if (g_labels[i] != NULL) {
4470 lr = &g_label_refs[i];
4471 for (; lr != NULL; lr = lr->next) {
4472 check_i(&ops[i], lr->i);
4473 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4475 if (i > 0 && LAST_OP(i - 1))
4481 if (is_caller != NULL)
4486 if (ops[i].cc_scratch == magic)
4488 ops[i].cc_scratch = magic;
4490 if (!(ops[i].flags & OPF_DATA))
4492 if (!is_opr_modified(opr, &ops[i]))
4496 if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4507 // find an instruction that previously referenced opr
4508 // if multiple results are found - fail
4509 // *op_i must be set to -1 by the caller
4510 // returns 1 if found, *op_i is then set to referencer insn
4511 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4512 int magic, int *op_i)
4514 struct label_ref *lr;
4518 if (g_labels[i] != NULL) {
4519 lr = &g_label_refs[i];
4520 for (; lr != NULL; lr = lr->next) {
4521 check_i(&ops[i], lr->i);
4522 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4524 if (i > 0 && LAST_OP(i - 1))
4532 if (ops[i].cc_scratch == magic)
4534 ops[i].cc_scratch = magic;
4536 if (!is_opr_referenced(opr, &ops[i]))
4547 // adjust datap of all reachable 'op' insns when moving back
4548 // returns 1 if at least 1 op was found
4549 // returns -1 if path without an op was found
4550 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4552 struct label_ref *lr;
4555 if (ops[i].cc_scratch == magic)
4557 ops[i].cc_scratch = magic;
4560 if (g_labels[i] != NULL) {
4561 lr = &g_label_refs[i];
4562 for (; lr != NULL; lr = lr->next) {
4563 check_i(&ops[i], lr->i);
4564 ret |= adjust_prev_op(lr->i, op, magic, datap);
4566 if (i > 0 && LAST_OP(i - 1))
4574 if (ops[i].cc_scratch == magic)
4576 ops[i].cc_scratch = magic;
4578 if (ops[i].op != op)
4581 ops[i].datap = datap;
4586 // find next instruction that reads opr
4587 // *op_i must be set to -1 by the caller
4588 // on return, *op_i is set to first referencer insn
4589 // returns 1 if exactly 1 referencer is found
4590 static int find_next_read(int i, int opcnt,
4591 const struct parsed_opr *opr, int magic, int *op_i)
4593 struct parsed_op *po;
4596 for (; i < opcnt; i++)
4598 if (ops[i].cc_scratch == magic)
4600 ops[i].cc_scratch = magic;
4603 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4604 if (po->btj != NULL) {
4606 for (j = 0; j < po->btj->count; j++) {
4607 check_i(po, po->btj->d[j].bt_i);
4608 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4614 if (po->flags & OPF_RMD)
4616 check_i(po, po->bt_i);
4617 if (po->flags & OPF_CJMP) {
4618 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4627 if (!is_opr_read(opr, po)) {
4629 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4630 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4632 full_opr = po->operand[0].lmod >= opr->lmod;
4634 if (is_opr_modified(opr, po) && full_opr) {
4638 if (po->flags & OPF_TAIL)
4653 static int find_next_read_reg(int i, int opcnt, int reg,
4654 enum opr_lenmod lmod, int magic, int *op_i)
4656 struct parsed_opr opr = OPR_INIT(OPT_REG, lmod, reg);
4659 return find_next_read(i, opcnt, &opr, magic, op_i);
4662 // find next instruction that reads opr
4663 // *op_i must be set to -1 by the caller
4664 // on return, *op_i is set to first flag user insn
4665 // returns 1 if exactly 1 flag user is found
4666 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4668 struct parsed_op *po;
4671 for (; i < opcnt; i++)
4673 if (ops[i].cc_scratch == magic)
4675 ops[i].cc_scratch = magic;
4678 if (po->op == OP_CALL)
4680 if (po->flags & OPF_JMP) {
4681 if (po->btj != NULL) {
4683 for (j = 0; j < po->btj->count; j++) {
4684 check_i(po, po->btj->d[j].bt_i);
4685 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4691 if (po->flags & OPF_RMD)
4693 check_i(po, po->bt_i);
4694 if (po->flags & OPF_CJMP)
4701 if (!(po->flags & OPF_CC)) {
4702 if (po->flags & OPF_FLAGS)
4705 if (po->flags & OPF_TAIL)
4721 static int try_resolve_const(int i, const struct parsed_opr *opr,
4722 int magic, unsigned int *val)
4727 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4730 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4733 *val = ops[i].operand[1].val;
4740 static int resolve_used_bits(int i, int opcnt, int reg,
4741 int *mask, int *is_z_check)
4743 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4747 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4751 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4753 fnote(&ops[j], "(first read)\n");
4754 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4757 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4758 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4760 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4761 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4763 *mask = ops[j].operand[1].val;
4764 if (ops[j].operand[0].lmod == OPLM_BYTE
4765 && ops[j].operand[0].name[1] == 'h')
4769 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4772 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4774 *is_z_check = ops[k].pfo == PFO_Z;
4779 static const struct parsed_proto *resolve_deref(int i, int magic,
4780 struct parsed_opr *opr, int level)
4782 struct parsed_opr opr_s = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
4783 const struct parsed_proto *pp = NULL;
4784 int from_caller = 0;
4793 ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4794 if (ret != 2 || len != strlen(opr->name)) {
4795 ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4796 if (ret != 1 || len != strlen(opr->name))
4800 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4805 ret = resolve_origin(i, &opr_s, i + magic, &j, NULL);
4809 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4810 && strlen(ops[j].operand[1].name) == 3
4811 && ops[j].operand[0].lmod == OPLM_DWORD
4812 && ops[j].pp == NULL // no hint
4815 // allow one simple dereference (com/directx)
4816 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4817 ops[j].operand[1].name);
4821 ret = resolve_origin(j, &opr_s, j + magic, &k, NULL);
4826 if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
4829 if (ops[j].pp != NULL) {
4833 else if (ops[j].operand[1].type == OPT_REGMEM) {
4834 pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
4836 // maybe structure ptr in structure
4837 pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
4840 else if (ops[j].operand[1].type == OPT_LABEL)
4841 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4842 else if (ops[j].operand[1].type == OPT_REG) {
4845 ret = resolve_origin(j, &ops[j].operand[1], i + magic,
4847 if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
4848 for (k = 0; k < g_func_pp->argc; k++) {
4849 if (g_func_pp->arg[k].reg == NULL)
4851 if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
4852 pp = g_func_pp->arg[k].pp;
4861 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4863 ferr(&ops[j], "expected struct, got '%s %s'\n",
4864 pp->type.name, pp->name);
4868 return proto_lookup_struct(g_fhdr, pp->type.name, offset);
4871 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4872 int *pp_i, int *multi_src)
4874 const struct parsed_proto *pp = NULL;
4875 int search_advice = 0;
4880 switch (ops[i].operand[0].type) {
4882 // try to resolve struct member calls
4883 pp = resolve_deref(i, i + opcnt * 19, &ops[i].operand[0], 0);
4889 pp = try_recover_pp(&ops[i], &ops[i].operand[0],
4895 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4903 static struct parsed_proto *process_call_early(int i, int opcnt,
4906 struct parsed_op *po = &ops[i];
4907 struct parsed_proto *pp;
4913 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4917 // look for and make use of esp adjust
4919 if (!pp->is_stdcall && pp->argc_stack > 0)
4920 ret = scan_for_esp_adjust(i + 1, opcnt,
4921 pp->argc_stack * 4, &adj, &multipath, 0);
4923 if (pp->argc_stack > adj / 4)
4927 if (ops[ret].op == OP_POP) {
4928 for (j = 1; j < adj / 4; j++) {
4929 if (ops[ret + j].op != OP_POP
4930 || ops[ret + j].operand[0].reg != xCX)
4942 static struct parsed_proto *process_call(int i, int opcnt)
4944 struct parsed_op *po = &ops[i];
4945 const struct parsed_proto *pp_c;
4946 struct parsed_proto *pp;
4947 const char *tmpname;
4948 int call_i = -1, ref_i = -1;
4949 int adj = 0, multipath = 0;
4952 tmpname = opr_name(po, 0);
4957 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4959 if (!pp_c->is_func && !pp_c->is_fptr)
4960 ferr(po, "call to non-func: %s\n", pp_c->name);
4961 pp = proto_clone(pp_c);
4962 my_assert_not(pp, NULL);
4964 // not resolved just to single func
4967 switch (po->operand[0].type) {
4969 // we resolved this call and no longer need the register
4970 po->regmask_src &= ~(1 << po->operand[0].reg);
4972 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4973 && ops[call_i].operand[1].type == OPT_LABEL)
4975 // no other source users?
4976 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4978 if (ret == 1 && call_i == ref_i) {
4979 // and nothing uses it after us?
4981 find_next_read(i + 1, opcnt, &po->operand[0],
4982 i + opcnt * 11, &ref_i);
4984 // then also don't need the source mov
4985 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4997 pp = calloc(1, sizeof(*pp));
4998 my_assert_not(pp, NULL);
5001 ret = scan_for_esp_adjust(i + 1, opcnt,
5002 -1, &adj, &multipath, 0);
5003 if (ret < 0 || adj < 0) {
5004 if (!g_allow_regfunc)
5005 ferr(po, "non-__cdecl indirect call unhandled yet\n");
5006 pp->is_unresolved = 1;
5010 if (adj > ARRAY_SIZE(pp->arg))
5011 ferr(po, "esp adjust too large: %d\n", adj);
5012 pp->ret_type.name = strdup("int");
5013 pp->argc = pp->argc_stack = adj;
5014 for (arg = 0; arg < pp->argc; arg++)
5015 pp->arg[arg].type.name = strdup("int");
5020 // look for and make use of esp adjust
5023 if (!pp->is_stdcall && pp->argc_stack > 0) {
5024 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
5025 ret = scan_for_esp_adjust(i + 1, opcnt,
5026 adj_expect, &adj, &multipath, 0);
5029 if (pp->is_vararg) {
5030 if (adj / 4 < pp->argc_stack) {
5031 fnote(po, "(this call)\n");
5032 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
5033 adj, pp->argc_stack * 4);
5035 // modify pp to make it have varargs as normal args
5037 pp->argc += adj / 4 - pp->argc_stack;
5038 for (; arg < pp->argc; arg++) {
5039 pp->arg[arg].type.name = strdup("int");
5042 if (pp->argc > ARRAY_SIZE(pp->arg))
5043 ferr(po, "too many args for '%s'\n", tmpname);
5045 if (pp->argc_stack > adj / 4) {
5046 if (pp->is_noreturn)
5047 // assume no stack adjust was emited
5049 fnote(po, "(this call)\n");
5050 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
5051 tmpname, pp->argc_stack * 4, adj);
5054 scan_for_esp_adjust(i + 1, opcnt,
5055 pp->argc_stack * 4, &adj, &multipath, 1);
5057 else if (pp->is_vararg)
5058 ferr(po, "missing esp_adjust for vararg func '%s'\n",
5065 static void mark_float_arg(struct parsed_op *po,
5066 struct parsed_proto *pp, int arg, int *regmask_ffca)
5069 po->p_argnum = arg + 1;
5070 ferr_assert(po, pp->arg[arg].datap == NULL);
5071 pp->arg[arg].datap = po;
5072 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
5073 if (regmask_ffca != NULL)
5074 *regmask_ffca |= 1 << arg;
5077 static int check_for_stp(int i, int i_to)
5079 struct parsed_op *po;
5081 for (; i < i_to; i++) {
5083 if (po->op == OP_FST)
5085 if (g_labels[i] != NULL || (po->flags & OPF_JMP))
5087 if (po->op == OP_CALL || po->op == OP_PUSH || po->op == OP_POP)
5089 if (po->op == OP_ADD && po->operand[0].reg == xSP)
5096 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
5099 struct parsed_op *po;
5105 for (base_arg = 0; base_arg < pp->argc; base_arg++)
5106 if (pp->arg[base_arg].reg == NULL)
5109 for (j = i; j > 0; )
5111 ferr_assert(&ops[j], g_labels[j] == NULL);
5115 ferr_assert(po, po->op != OP_PUSH);
5116 if (po->op == OP_FST)
5118 if (po->operand[0].type != OPT_REGMEM)
5120 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
5123 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3)) {
5124 //ferr(po, "offset %d, %d args\n", offset, pp->argc_stack);
5128 arg = base_arg + offset / 4;
5129 mark_float_arg(po, pp, arg, regmask_ffca);
5131 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5132 && po->operand[1].type == OPT_CONST)
5134 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5139 for (arg = base_arg; arg < pp->argc; arg++) {
5140 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
5141 po = pp->arg[arg].datap;
5143 ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
5144 if (po->operand[0].lmod == OPLM_QWORD)
5151 static int collect_call_args_early(int i, struct parsed_proto *pp,
5152 int *regmask, int *regmask_ffca)
5154 struct parsed_op *po;
5159 for (arg = 0; arg < pp->argc; arg++)
5160 if (pp->arg[arg].reg == NULL)
5163 // first see if it can be easily done
5164 for (j = i; j > 0 && arg < pp->argc; )
5166 if (g_labels[j] != NULL)
5171 if (po->op == OP_CALL)
5173 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
5175 else if (po->op == OP_POP)
5177 else if (po->flags & OPF_CJMP)
5179 else if (po->op == OP_PUSH) {
5180 if (po->flags & (OPF_FARG|OPF_FARGNR))
5182 if (!g_header_mode) {
5183 ret = scan_for_mod(po, j + 1, i, 1);
5188 if (pp->arg[arg].type.is_va_list)
5192 for (arg++; arg < pp->argc; arg++)
5193 if (pp->arg[arg].reg == NULL)
5196 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5197 && po->operand[1].type == OPT_CONST)
5199 if (po->flags & (OPF_RMD|OPF_DONE))
5201 if (po->operand[1].val != pp->argc_stack * 4)
5202 ferr(po, "unexpected esp adjust: %d\n",
5203 po->operand[1].val * 4);
5204 ferr_assert(po, pp->argc - arg == pp->argc_stack);
5205 return collect_call_args_no_push(i, pp, regmask_ffca);
5213 for (arg = 0; arg < pp->argc; arg++)
5214 if (pp->arg[arg].reg == NULL)
5217 for (j = i; j > 0 && arg < pp->argc; )
5221 if (ops[j].op == OP_PUSH)
5223 ops[j].p_argnext = -1;
5224 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
5226 k = check_for_stp(j + 1, i);
5228 // push ecx; fstp dword ptr [esp]
5229 ret = parse_stack_esp_offset(&ops[k],
5230 ops[k].operand[0].name, &offset);
5231 if (ret == 0 && offset == 0) {
5232 if (!pp->arg[arg].type.is_float)
5233 ferr(&ops[i], "arg %d should be float\n", arg + 1);
5234 mark_float_arg(&ops[k], pp, arg, regmask_ffca);
5238 if (pp->arg[arg].datap == NULL) {
5239 pp->arg[arg].datap = &ops[j];
5240 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
5241 *regmask |= 1 << ops[j].operand[0].reg;
5244 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5245 ops[j].flags &= ~OPF_RSAVE;
5248 for (arg++; arg < pp->argc; arg++)
5249 if (pp->arg[arg].reg == NULL)
5257 static int sync_argnum(struct parsed_op *po, int argnum)
5259 struct parsed_op *po_tmp;
5261 // see if other branches don't have higher argnum
5262 for (po_tmp = po; po_tmp != NULL; ) {
5263 if (argnum < po_tmp->p_argnum)
5264 argnum = po_tmp->p_argnum;
5265 // note: p_argnext is active on current collect_call_args only
5266 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5269 // make all argnums consistent
5270 for (po_tmp = po; po_tmp != NULL; ) {
5271 if (po_tmp->p_argnum != 0)
5272 po_tmp->p_argnum = argnum;
5273 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5279 static int collect_call_args_r(struct parsed_op *po, int i,
5280 struct parsed_proto *pp, int *regmask, int *arg_grp,
5281 int arg, int argnum, int magic, int need_op_saving, int may_reuse)
5283 struct parsed_proto *pp_tmp;
5284 struct parsed_op *po_tmp;
5285 struct label_ref *lr;
5286 int need_to_save_current;
5287 int arg_grp_current = 0;
5288 int save_args_seen = 0;
5295 ferr(po, "dead label encountered\n");
5299 for (; arg < pp->argc; arg++, argnum++)
5300 if (pp->arg[arg].reg == NULL)
5302 magic = (magic & 0xffffff) | (arg << 24);
5304 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
5306 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
5307 if (ops[j].cc_scratch != magic) {
5308 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
5312 // ok: have already been here
5315 ops[j].cc_scratch = magic;
5317 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
5318 lr = &g_label_refs[j];
5319 if (lr->next != NULL)
5321 for (; lr->next; lr = lr->next) {
5322 check_i(&ops[j], lr->i);
5323 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5325 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5326 arg, argnum, magic, need_op_saving, may_reuse);
5331 check_i(&ops[j], lr->i);
5332 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5334 if (j > 0 && LAST_OP(j - 1)) {
5335 // follow last branch in reverse
5340 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5341 arg, argnum, magic, need_op_saving, may_reuse);
5347 if (ops[j].op == OP_CALL)
5349 if (pp->is_unresolved)
5354 ferr(po, "arg collect %d/%d hit unparsed call '%s'\n",
5355 arg, pp->argc, ops[j].operand[0].name);
5356 if (may_reuse && pp_tmp->argc_stack > 0)
5357 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
5358 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
5360 // esp adjust of 0 means we collected it before
5361 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
5362 && (ops[j].operand[1].type != OPT_CONST
5363 || ops[j].operand[1].val != 0))
5365 if (pp->is_unresolved)
5368 fnote(po, "(this call)\n");
5369 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
5370 arg, pp->argc, ops[j].operand[1].val);
5372 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
5374 if (pp->is_unresolved)
5377 fnote(po, "(this call)\n");
5378 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
5380 else if (ops[j].flags & OPF_CJMP)
5382 if (pp->is_unresolved)
5387 else if (ops[j].op == OP_PUSH
5388 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
5390 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
5393 ops[j].p_argnext = -1;
5394 po_tmp = pp->arg[arg].datap;
5396 ops[j].p_argnext = po_tmp - ops;
5397 pp->arg[arg].datap = &ops[j];
5399 argnum = sync_argnum(&ops[j], argnum);
5401 need_to_save_current = 0;
5403 if (ops[j].operand[0].type == OPT_REG)
5404 reg = ops[j].operand[0].reg;
5406 if (!need_op_saving) {
5407 ret = scan_for_mod(&ops[j], j + 1, i, 1);
5408 need_to_save_current = (ret >= 0);
5410 if (need_op_saving || need_to_save_current) {
5411 // mark this arg as one that needs operand saving
5412 pp->arg[arg].is_saved = 1;
5414 if (save_args_seen & (1 << (argnum - 1))) {
5417 if (arg_grp_current >= MAX_ARG_GRP)
5418 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
5422 else if (ops[j].p_argnum == 0)
5423 ops[j].flags |= OPF_RMD;
5425 // some PUSHes are reused by different calls on other branches,
5426 // but that can't happen if we didn't branch, so they
5427 // can be removed from future searches (handles nested calls)
5429 ops[j].flags |= OPF_FARGNR;
5431 ops[j].flags |= OPF_FARG;
5432 ops[j].flags &= ~OPF_RSAVE;
5434 // check for __VALIST
5435 if (!pp->is_unresolved && g_func_pp != NULL
5436 && pp->arg[arg].type.is_va_list)
5439 ret = resolve_origin(j, &ops[j].operand[0],
5440 magic + 1, &k, NULL);
5441 if (ret == 1 && k >= 0)
5443 if (ops[k].op == OP_LEA) {
5444 if (!g_func_pp->is_vararg)
5445 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
5448 snprintf(buf, sizeof(buf), "arg_%X",
5449 g_func_pp->argc_stack * 4);
5450 if (strstr(ops[k].operand[1].name, buf)
5451 || strstr(ops[k].operand[1].name, "arglist"))
5453 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
5454 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
5455 pp->arg[arg].is_saved = 0;
5459 ferr(&ops[k], "va_list arg detection failed\n");
5461 // check for va_list from g_func_pp arg too
5462 else if (ops[k].op == OP_MOV
5463 && is_stack_access(&ops[k], &ops[k].operand[1]))
5465 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5466 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5468 ops[k].flags |= OPF_RMD | OPF_DONE;
5469 ops[j].flags |= OPF_RMD;
5470 ops[j].p_argpass = ret + 1;
5471 pp->arg[arg].is_saved = 0;
5478 if (pp->arg[arg].is_saved) {
5479 ops[j].flags &= ~OPF_RMD;
5480 ops[j].p_argnum = argnum;
5483 // tracking reg usage
5485 *regmask |= 1 << reg;
5489 if (!pp->is_unresolved) {
5491 for (; arg < pp->argc; arg++, argnum++)
5492 if (pp->arg[arg].reg == NULL)
5495 magic = (magic & 0xffffff) | (arg << 24);
5498 if (ops[j].p_arggrp > arg_grp_current) {
5500 arg_grp_current = ops[j].p_arggrp;
5502 if (ops[j].p_argnum > 0)
5503 save_args_seen |= 1 << (ops[j].p_argnum - 1);
5506 if (arg < pp->argc) {
5507 ferr(po, "arg collect failed for '%s': %d/%d\n",
5508 pp->name, arg, pp->argc);
5512 if (arg_grp_current > *arg_grp)
5513 *arg_grp = arg_grp_current;
5518 static int collect_call_args(struct parsed_op *po, int i,
5519 struct parsed_proto *pp, int *regmask, int magic)
5521 // arg group is for cases when pushes for
5522 // multiple funcs are going on
5523 struct parsed_op *po_tmp;
5528 ret = collect_call_args_r(po, i, pp, regmask, &arg_grp,
5534 // propagate arg_grp
5535 for (a = 0; a < pp->argc; a++) {
5536 if (pp->arg[a].reg != NULL)
5539 po_tmp = pp->arg[a].datap;
5540 while (po_tmp != NULL) {
5541 po_tmp->p_arggrp = arg_grp;
5542 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5547 if (pp->is_unresolved) {
5549 pp->argc_stack += ret;
5550 for (a = 0; a < pp->argc; a++)
5551 if (pp->arg[a].type.name == NULL)
5552 pp->arg[a].type.name = strdup("int");
5558 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5559 int regmask_now, int *regmask,
5560 int regmask_save_now, int *regmask_save,
5561 int *regmask_init, int regmask_arg)
5563 struct parsed_op *po;
5571 for (; i < opcnt; i++)
5574 if (cbits[i >> 3] & (1 << (i & 7)))
5576 cbits[i >> 3] |= (1 << (i & 7));
5578 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5579 if (po->flags & (OPF_RMD|OPF_DONE))
5581 if (po->btj != NULL) {
5582 for (j = 0; j < po->btj->count; j++) {
5583 check_i(po, po->btj->d[j].bt_i);
5584 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5585 regmask_now, regmask, regmask_save_now, regmask_save,
5586 regmask_init, regmask_arg);
5591 check_i(po, po->bt_i);
5592 if (po->flags & OPF_CJMP)
5593 reg_use_pass(po->bt_i, opcnt, cbits,
5594 regmask_now, regmask, regmask_save_now, regmask_save,
5595 regmask_init, regmask_arg);
5601 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5602 && !g_func_pp->is_userstack
5603 && po->operand[0].type == OPT_REG)
5605 reg = po->operand[0].reg;
5606 ferr_assert(po, reg >= 0);
5609 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5610 if (regmask_now & (1 << reg)) {
5611 already_saved = regmask_save_now & (1 << reg);
5612 flags_set = OPF_RSAVE | OPF_DONE;
5615 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, 0);
5617 scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5618 reg, 0, 0, flags_set);
5621 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5623 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5628 ferr_assert(po, !already_saved);
5629 po->flags |= flags_set;
5631 if (regmask_now & (1 << reg)) {
5632 regmask_save_now |= (1 << reg);
5633 *regmask_save |= regmask_save_now;
5638 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5639 reg = po->operand[0].reg;
5640 ferr_assert(po, reg >= 0);
5642 if (regmask_save_now & (1 << reg))
5643 regmask_save_now &= ~(1 << reg);
5645 regmask_now &= ~(1 << reg);
5648 else if (po->op == OP_CALL) {
5649 if ((po->regmask_dst & (1 << xAX))
5650 && !(po->regmask_dst & (1 << xDX)))
5652 if (po->flags & OPF_TAIL)
5653 // don't need eax, will do "return f();" or "f(); return;"
5654 po->regmask_dst &= ~(1 << xAX);
5656 find_next_read_reg(i + 1, opcnt, xAX, OPLM_DWORD,
5657 i + opcnt * 17, &j);
5660 po->regmask_dst &= ~(1 << xAX);
5664 // not "full stack" mode and have something in stack
5665 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5666 ferr(po, "float stack is not empty on func call\n");
5669 if (po->flags & OPF_NOREGS)
5672 // if incomplete register is used, clear it on init to avoid
5673 // later use of uninitialized upper part in some situations
5674 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5675 && po->operand[0].lmod != OPLM_DWORD)
5677 reg = po->operand[0].reg;
5678 ferr_assert(po, reg >= 0);
5680 if (!(regmask_now & (1 << reg)))
5681 *regmask_init |= 1 << reg;
5684 regmask_op = po->regmask_src | po->regmask_dst;
5686 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5687 regmask_new &= ~(1 << xSP);
5688 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5689 regmask_new &= ~(1 << xBP);
5691 if (regmask_new != 0)
5692 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5694 if (regmask_op & (1 << xBP)) {
5695 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5696 if (po->regmask_dst & (1 << xBP))
5697 // compiler decided to drop bp frame and use ebp as scratch
5698 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5700 regmask_op &= ~(1 << xBP);
5704 if (po->flags & OPF_FPUSH) {
5705 if (regmask_now & mxST1)
5706 regmask_now |= mxSTa; // switch to "full stack" mode
5707 if (regmask_now & mxSTa)
5708 po->flags |= OPF_FSHIFT;
5709 if (!(regmask_now & mxST7_2)) {
5711 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5715 regmask_now |= regmask_op;
5716 *regmask |= regmask_now;
5719 if (po->flags & OPF_FPOPP) {
5720 if ((regmask_now & mxSTa) == 0)
5721 ferr(po, "float pop on empty stack?\n");
5722 if (regmask_now & mxST7_2)
5723 po->flags |= OPF_FSHIFT;
5724 if (!(regmask_now & mxST7_2))
5725 regmask_now &= ~mxST1_0;
5727 else if (po->flags & OPF_FPOP) {
5728 if ((regmask_now & mxSTa) == 0)
5729 ferr(po, "float pop on empty stack?\n");
5730 if (regmask_now & (mxST7_2 | mxST1))
5731 po->flags |= OPF_FSHIFT;
5732 if (!(regmask_now & mxST7_2)) {
5734 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5738 if (po->flags & OPF_TAIL) {
5739 if (!(regmask_now & mxST7_2)) {
5740 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5741 if (!(regmask_now & mxST0))
5742 ferr(po, "no st0 on float return, mask: %x\n",
5745 else if (regmask_now & mxST1_0)
5746 ferr(po, "float regs on tail: %x\n", regmask_now);
5749 // there is support for "conditional tailcall", sort of
5750 if (!(po->flags & OPF_CC))
5756 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5760 for (i = 0; i < pp->argc; i++)
5761 if (pp->arg[i].reg == NULL)
5765 memmove(&pp->arg[i + 1], &pp->arg[i],
5766 sizeof(pp->arg[0]) * pp->argc_stack);
5767 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5768 pp->arg[i].reg = strdup(reg);
5769 pp->arg[i].type.name = strdup("int");
5774 static void output_std_flag_z(FILE *fout, struct parsed_op *po,
5775 int *pfomask, const char *dst_opr_text)
5777 if (*pfomask & (1 << PFO_Z)) {
5778 fprintf(fout, "\n cond_z = (%s%s == 0);",
5779 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5780 *pfomask &= ~(1 << PFO_Z);
5784 static void output_std_flag_s(FILE *fout, struct parsed_op *po,
5785 int *pfomask, const char *dst_opr_text)
5787 if (*pfomask & (1 << PFO_S)) {
5788 fprintf(fout, "\n cond_s = (%s%s < 0);",
5789 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5790 *pfomask &= ~(1 << PFO_S);
5794 static void output_std_flags(FILE *fout, struct parsed_op *po,
5795 int *pfomask, const char *dst_opr_text)
5797 output_std_flag_z(fout, po, pfomask, dst_opr_text);
5798 output_std_flag_s(fout, po, pfomask, dst_opr_text);
5802 OPP_FORCE_NORETURN = (1 << 0),
5803 OPP_SIMPLE_ARGS = (1 << 1),
5804 OPP_ALIGN = (1 << 2),
5807 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
5810 const char *cconv = "";
5812 if (pp->is_fastcall)
5813 cconv = "__fastcall ";
5814 else if (pp->is_stdcall && pp->argc_reg == 0)
5815 cconv = "__stdcall ";
5817 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5819 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
5820 fprintf(fout, "noreturn ");
5823 static void output_pp(FILE *fout, const struct parsed_proto *pp,
5828 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5832 output_pp_attrs(fout, pp, flags);
5835 fprintf(fout, "%s", pp->name);
5840 for (i = 0; i < pp->argc; i++) {
5842 fprintf(fout, ", ");
5843 if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
5844 && !(flags & OPP_SIMPLE_ARGS))
5847 output_pp(fout, pp->arg[i].pp, 0);
5849 else if (pp->arg[i].type.is_retreg) {
5850 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
5853 fprintf(fout, "%s", pp->arg[i].type.name);
5855 fprintf(fout, " a%d", i + 1);
5858 if (pp->arg[i].type.is_64bit)
5861 if (pp->is_vararg) {
5863 fprintf(fout, ", ");
5864 fprintf(fout, "...");
5869 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
5875 snprintf(buf1, sizeof(buf1), "%d", grp);
5876 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
5881 static void gen_x_cleanup(int opcnt);
5883 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
5885 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
5886 struct parsed_opr *last_arith_dst = NULL;
5887 char buf1[256], buf2[256], buf3[256], cast[64];
5888 struct parsed_proto *pp, *pp_tmp;
5889 struct parsed_data *pd;
5890 int save_arg_vars[MAX_ARG_GRP] = { 0, };
5891 unsigned char cbits[MAX_OPS / 8];
5892 const char *float_type;
5893 const char *float_st0;
5894 const char *float_st1;
5895 int need_float_stack = 0;
5896 int need_float_sw = 0; // status word
5897 int need_tmp_var = 0;
5901 int label_pending = 0;
5902 int need_double = 0;
5903 int stack_align = 0;
5904 int stack_fsz_adj = 0;
5905 int regmask_save = 0; // used regs saved/restored in this func
5906 int regmask_arg; // regs from this function args (fastcall, etc)
5907 int regmask_ret; // regs needed on ret
5908 int regmask_now; // temp
5909 int regmask_init = 0; // regs that need zero initialization
5910 int regmask_pp = 0; // regs used in complex push-pop graph
5911 int regmask_ffca = 0; // float function call args
5912 int regmask = 0; // used regs
5922 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
5923 g_stack_frame_used = 0;
5925 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
5926 regmask_init = g_regmask_init;
5928 g_func_pp = proto_parse(fhdr, funcn, 0);
5929 if (g_func_pp == NULL)
5930 ferr(ops, "proto_parse failed for '%s'\n", funcn);
5932 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
5933 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
5936 // - resolve all branches
5937 // - parse calls with labels
5938 resolve_branches_parse_calls(opcnt);
5941 // - handle ebp/esp frame, remove ops related to it
5942 scan_prologue_epilogue(opcnt, &stack_align);
5944 // handle a case where sf size is unalignment, but is
5945 // placed in a way that elements are still aligned
5946 if (g_stack_fsz & 4) {
5947 for (i = 0; i < g_eqcnt; i++) {
5948 if (g_eqs[i].lmod != OPLM_QWORD)
5950 if (!(g_eqs[i].offset & 4)) {
5959 // - remove dead labels
5960 // - set regs needed at ret
5961 for (i = 0; i < opcnt; i++)
5963 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
5968 if (ops[i].op == OP_RET)
5969 ops[i].regmask_src |= regmask_ret;
5973 // - process trivial calls
5974 for (i = 0; i < opcnt; i++)
5977 if (po->flags & (OPF_RMD|OPF_DONE))
5980 if (po->op == OP_CALL)
5982 pp = process_call_early(i, opcnt, &j);
5984 if (!(po->flags & OPF_ATAIL)) {
5985 // since we know the args, try to collect them
5986 ret = collect_call_args_early(i, pp, ®mask, ®mask_ffca);
5994 // commit esp adjust
5995 if (ops[j].op != OP_POP)
5996 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5998 for (l = 0; l < pp->argc_stack; l++)
5999 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
6003 if (strstr(pp->ret_type.name, "int64"))
6006 po->flags |= OPF_DONE;
6012 // - process calls, stage 2
6013 // - handle some push/pop pairs
6014 // - scan for STD/CLD, propagate DF
6015 // - try to resolve needed x87 status word bits
6016 for (i = 0; i < opcnt; i++)
6021 if (po->flags & OPF_RMD)
6024 if (po->op == OP_CALL)
6026 if (!(po->flags & OPF_DONE)) {
6027 pp = process_call(i, opcnt);
6029 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
6030 // since we know the args, collect them
6031 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
6033 // for unresolved, collect after other passes
6037 ferr_assert(po, pp != NULL);
6039 po->regmask_src |= get_pp_arg_regmask_src(pp);
6040 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
6042 if (po->regmask_dst & mxST0)
6043 po->flags |= OPF_FPUSH;
6045 if (strstr(pp->ret_type.name, "int64"))
6051 if (po->flags & OPF_DONE)
6056 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
6057 && po->operand[0].type == OPT_CONST)
6059 scan_for_pop_const(i, opcnt, i + opcnt * 12);
6064 scan_pushes_for_pop(i, opcnt, ®mask_pp);
6068 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
6069 scan_propagate_df(i + 1, opcnt);
6074 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
6075 ferr(po, "TODO: fnstsw to mem\n");
6076 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
6078 ferr(po, "fnstsw resolve failed\n");
6079 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
6080 (void *)(long)(mask | (z_check << 16)));
6082 ferr(po, "failed to find fcom: %d\n", ret);
6091 // - find POPs for PUSHes, rm both
6092 // - scan for all used registers
6093 memset(cbits, 0, sizeof(cbits));
6094 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
6095 0, ®mask_save, ®mask_init, regmask_arg);
6097 need_float_stack = !!(regmask & mxST7_2);
6100 // - find flag set ops for their users
6101 // - do unresolved calls
6102 // - declare indirect functions
6103 // - other op specific processing
6104 for (i = 0; i < opcnt; i++)
6107 if (po->flags & (OPF_RMD|OPF_DONE))
6110 if (po->flags & OPF_CC)
6112 int setters[16], cnt = 0, branched = 0;
6114 ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
6115 &branched, setters, &cnt);
6116 if (ret < 0 || cnt <= 0)
6117 ferr(po, "unable to trace flag setter(s)\n");
6118 if (cnt > ARRAY_SIZE(setters))
6119 ferr(po, "too many flag setters\n");
6121 for (j = 0; j < cnt; j++)
6123 tmp_op = &ops[setters[j]]; // flag setter
6126 // to get nicer code, we try to delay test and cmp;
6127 // if we can't because of operand modification, or if we
6128 // have arith op, or branch, make it calculate flags explicitly
6129 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
6131 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
6132 pfomask = 1 << po->pfo;
6134 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
6135 pfomask = 1 << po->pfo;
6138 // see if we'll be able to handle based on op result
6139 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
6140 && po->pfo != PFO_Z && po->pfo != PFO_S
6141 && po->pfo != PFO_P)
6143 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
6145 pfomask = 1 << po->pfo;
6148 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
6149 propagate_lmod(tmp_op, &tmp_op->operand[0],
6150 &tmp_op->operand[1]);
6151 if (tmp_op->operand[0].lmod == OPLM_DWORD)
6156 tmp_op->pfomask |= pfomask;
6157 cond_vars |= pfomask;
6159 // note: may overwrite, currently not a problem
6163 if (po->op == OP_RCL || po->op == OP_RCR
6164 || po->op == OP_ADC || po->op == OP_SBB)
6165 cond_vars |= 1 << PFO_C;
6171 cond_vars |= 1 << PFO_Z;
6175 if (po->operand[0].lmod == OPLM_DWORD)
6180 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
6185 // note: resolved non-reg calls are OPF_DONE already
6187 ferr_assert(po, pp != NULL);
6189 if (pp->is_unresolved) {
6190 int regmask_stack = 0;
6191 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
6193 // this is pretty rough guess:
6194 // see ecx and edx were pushed (and not their saved versions)
6195 for (arg = 0; arg < pp->argc; arg++) {
6196 if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
6199 tmp_op = pp->arg[arg].datap;
6201 ferr(po, "parsed_op missing for arg%d\n", arg);
6202 if (tmp_op->operand[0].type == OPT_REG)
6203 regmask_stack |= 1 << tmp_op->operand[0].reg;
6206 if (!((regmask_stack & (1 << xCX))
6207 && (regmask_stack & (1 << xDX))))
6209 if (pp->argc_stack != 0
6210 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
6212 pp_insert_reg_arg(pp, "ecx");
6213 pp->is_fastcall = 1;
6214 regmask_init |= 1 << xCX;
6215 regmask |= 1 << xCX;
6217 if (pp->argc_stack != 0
6218 || ((regmask | regmask_arg) & (1 << xDX)))
6220 pp_insert_reg_arg(pp, "edx");
6221 regmask_init |= 1 << xDX;
6222 regmask |= 1 << xDX;
6226 // note: __cdecl doesn't fall into is_unresolved category
6227 if (pp->argc_stack > 0)
6230 if (!(po->flags & OPF_TAIL)
6231 && !(g_sct_func_attr & SCTFA_NOWARN))
6233 // treat al write as overwrite to avoid many false positives
6234 if (IS(pp->ret_type.name, "void") || pp->ret_type.is_float) {
6235 find_next_read_reg(i + 1, opcnt, xAX, OPLM_BYTE,
6236 i + opcnt * 25, &j);
6238 fnote(po, "eax used after void/float ret call\n");
6239 fnote(&ops[j], "(used here)\n");
6242 if (!strstr(pp->ret_type.name, "int64")) {
6243 find_next_read_reg(i + 1, opcnt, xDX, OPLM_BYTE,
6244 i + opcnt * 26, &j);
6245 // indirect calls are often guessed, don't warn
6246 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j])) {
6247 fnote(po, "edx used after 32bit ret call\n");
6248 fnote(&ops[j], "(used here)\n");
6252 // msvc often relies on callee not modifying 'this'
6253 for (arg = 0; arg < pp->argc; arg++) {
6254 if (pp->arg[arg].reg && IS(pp->arg[arg].reg, "ecx")) {
6260 find_next_read_reg(i + 1, opcnt, xCX, OPLM_BYTE,
6261 i + opcnt * 27, &j);
6262 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j])) {
6263 fnote(po, "ecx used after call\n");
6264 fnote(&ops[j], "(used here)\n");
6271 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
6273 // <var> = offset <something>
6274 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
6275 && !IS_START(po->operand[1].name, "off_"))
6277 if (!po->operand[0].pp->is_fptr)
6278 ferr(po, "%s not declared as fptr when it should be\n",
6279 po->operand[0].name);
6280 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
6281 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
6282 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
6283 fnote(po, "var: %s\n", buf1);
6284 fnote(po, "func: %s\n", buf2);
6285 ferr(po, "^ mismatch\n");
6293 if (po->operand[0].lmod == OPLM_DWORD) {
6294 // 32bit division is common, look for it
6295 if (po->op == OP_DIV)
6296 ret = scan_for_reg_clear(i, xDX);
6298 ret = scan_for_cdq_edx(i);
6300 po->flags |= OPF_32BIT;
6309 po->flags |= OPF_RMD | OPF_DONE;
6319 if (po->operand[0].lmod == OPLM_QWORD)
6329 find_next_read_reg(i + 1, opcnt, xDX, OPLM_DWORD,
6330 i + opcnt * 18, &j);
6332 po->flags |= OPF_32BIT;
6339 // this might need it's own pass...
6340 if (po->op != OP_FST && po->p_argnum > 0)
6341 save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
6343 // correct for "full stack" mode late enable
6344 if ((po->flags & (OPF_PPUSH|OPF_FPOP|OPF_FPOPP))
6345 && need_float_stack)
6346 po->flags |= OPF_FSHIFT;
6349 float_type = need_double ? "double" : "float";
6350 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
6351 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
6353 // output starts here
6356 fprintf(fout, "// had SEH\n");
6358 // define userstack size
6359 if (g_func_pp->is_userstack) {
6360 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
6361 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
6362 fprintf(fout, "#endif\n");
6365 // the function itself
6366 ferr_assert(ops, !g_func_pp->is_fptr);
6367 output_pp(fout, g_func_pp,
6368 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
6369 fprintf(fout, "\n{\n");
6371 // declare indirect functions
6372 for (i = 0; i < opcnt; i++) {
6374 if (po->flags & OPF_RMD)
6377 if (po->op == OP_CALL) {
6380 ferr(po, "NULL pp\n");
6382 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
6383 if (pp->name[0] != 0) {
6384 if (IS_START(pp->name, "guess"))
6387 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
6388 memcpy(pp->name, "i_", 2);
6390 // might be declared already
6392 for (j = 0; j < i; j++) {
6393 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
6394 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
6404 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
6407 output_pp(fout, pp, OPP_SIMPLE_ARGS);
6408 fprintf(fout, ";\n");
6413 // output LUTs/jumptables
6414 for (i = 0; i < g_func_pd_cnt; i++) {
6416 fprintf(fout, " static const ");
6417 if (pd->type == OPT_OFFSET) {
6418 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
6420 for (j = 0; j < pd->count; j++) {
6422 fprintf(fout, ", ");
6423 fprintf(fout, "&&%s", pd->d[j].u.label);
6427 fprintf(fout, "%s %s[] =\n { ",
6428 lmod_type_u(ops, pd->lmod), pd->label);
6430 for (j = 0; j < pd->count; j++) {
6432 fprintf(fout, ", ");
6433 fprintf(fout, "%u", pd->d[j].u.val);
6436 fprintf(fout, " };\n");
6440 // declare stack frame, va_arg
6443 fprintf(fout, " // stack_fsz_adj %d\n", stack_fsz_adj);
6445 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
6446 if (g_func_lmods & (1 << OPLM_WORD))
6447 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
6448 if (g_func_lmods & (1 << OPLM_BYTE))
6449 fprintf(fout, " u8 b[%d];", g_stack_fsz);
6450 if (g_func_lmods & (1 << OPLM_QWORD))
6451 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
6453 if (stack_align > 8)
6454 ferr(ops, "unhandled stack align of %d\n", stack_align);
6455 else if (stack_align == 8)
6456 fprintf(fout, " u64 align;");
6457 fprintf(fout, " } sf;\n");
6461 if (g_func_pp->is_userstack) {
6462 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
6463 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
6467 if (g_func_pp->is_vararg) {
6468 fprintf(fout, " va_list ap;\n");
6472 // declare arg-registers
6473 for (i = 0; i < g_func_pp->argc; i++) {
6474 if (g_func_pp->arg[i].reg != NULL) {
6475 reg = char_array_i(regs_r32,
6476 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
6477 if (regmask & (1 << reg)) {
6478 if (g_func_pp->arg[i].type.is_retreg)
6479 fprintf(fout, " u32 %s = *r_%s;\n",
6480 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
6482 fprintf(fout, " u32 %s = (u32)a%d;\n",
6483 g_func_pp->arg[i].reg, i + 1);
6486 if (g_func_pp->arg[i].type.is_retreg)
6487 ferr(ops, "retreg '%s' is unused?\n",
6488 g_func_pp->arg[i].reg);
6489 fprintf(fout, " // %s = a%d; // unused\n",
6490 g_func_pp->arg[i].reg, i + 1);
6496 // declare normal registers
6497 regmask_now = regmask & ~regmask_arg & ~g_regmask_rm;
6498 regmask_now &= ~(1 << xSP);
6499 if (regmask_now & 0x00ff) {
6500 for (reg = 0; reg < 8; reg++) {
6501 if (regmask_now & (1 << reg)) {
6502 fprintf(fout, " u32 %s", regs_r32[reg]);
6503 if (regmask_init & (1 << reg))
6504 fprintf(fout, " = 0");
6505 fprintf(fout, ";\n");
6511 if (regmask_now & 0xff00) {
6512 for (reg = 8; reg < 16; reg++) {
6513 if (regmask_now & (1 << reg)) {
6514 fprintf(fout, " mmxr %s", regs_r32[reg]);
6515 if (regmask_init & (1 << reg))
6516 fprintf(fout, " = { 0, }");
6517 fprintf(fout, ";\n");
6523 if (need_float_stack) {
6524 fprintf(fout, " %s f_st[8];\n", float_type);
6525 fprintf(fout, " int f_stp = 0;\n");
6529 if (regmask_now & 0xff0000) {
6530 for (reg = 16; reg < 24; reg++) {
6531 if (regmask_now & (1 << reg)) {
6532 fprintf(fout, " %s f_st%d", float_type, reg - 16);
6533 if (regmask_init & (1 << reg))
6534 fprintf(fout, " = 0");
6535 fprintf(fout, ";\n");
6542 if (need_float_sw) {
6543 fprintf(fout, " u16 f_sw;\n");
6548 for (reg = 0; reg < 8; reg++) {
6549 if (regmask_save & (1 << reg)) {
6550 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
6556 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6557 if (save_arg_vars[i] == 0)
6559 for (reg = 0; reg < 32; reg++) {
6560 if (save_arg_vars[i] & (1 << reg)) {
6561 fprintf(fout, " u32 %s;\n",
6562 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
6569 for (reg = 0; reg < 32; reg++) {
6570 if (regmask_ffca & (1 << reg)) {
6571 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
6577 // declare push-pop temporaries
6579 for (reg = 0; reg < 8; reg++) {
6580 if (regmask_pp & (1 << reg)) {
6581 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
6588 for (i = 0; i < 8; i++) {
6589 if (cond_vars & (1 << i)) {
6590 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
6597 fprintf(fout, " u32 tmp;\n");
6602 fprintf(fout, " u64 tmp64;\n");
6607 fprintf(fout, "\n");
6609 // do stack clear, if needed
6610 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6612 if (g_stack_clear_len != 0) {
6613 if (g_stack_clear_len <= 4) {
6614 for (i = 0; i < g_stack_clear_len; i++)
6615 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6616 fprintf(fout, "0;\n");
6619 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6620 g_stack_clear_start, g_stack_clear_len * 4);
6624 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6627 if (g_func_pp->is_vararg) {
6628 if (g_func_pp->argc_stack == 0)
6629 ferr(ops, "vararg func without stack args?\n");
6630 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
6634 for (i = 0; i < opcnt; i++)
6636 if (g_labels[i] != NULL) {
6637 fprintf(fout, "\n%s:\n", g_labels[i]);
6640 delayed_flag_op = NULL;
6641 last_arith_dst = NULL;
6645 if (po->flags & OPF_RMD)
6650 #define assert_operand_cnt(n_) \
6651 if (po->operand_cnt != n_) \
6652 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6654 // conditional/flag using op?
6655 if (po->flags & OPF_CC)
6661 // we go through all this trouble to avoid using parsed_flag_op,
6662 // which makes generated code much nicer
6663 if (delayed_flag_op != NULL)
6665 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6666 po->pfo, po->pfo_inv);
6669 else if (last_arith_dst != NULL
6670 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6671 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6674 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6675 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6676 last_arith_dst->lmod, buf3);
6679 else if (tmp_op != NULL) {
6680 // use preprocessed flag calc results
6681 if (!(tmp_op->pfomask & (1 << po->pfo)))
6682 ferr(po, "not prepared for pfo %d\n", po->pfo);
6684 // note: pfo_inv was not yet applied
6685 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6686 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6689 ferr(po, "all methods of finding comparison failed\n");
6692 if (po->flags & OPF_JMP) {
6693 fprintf(fout, " if %s", buf1);
6695 else if (po->op == OP_RCL || po->op == OP_RCR
6696 || po->op == OP_ADC || po->op == OP_SBB)
6699 fprintf(fout, " cond_%s = %s;\n",
6700 parsed_flag_op_names[po->pfo], buf1);
6702 else if (po->flags & OPF_DATA) { // SETcc
6703 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6704 fprintf(fout, " %s = %s;", buf2, buf1);
6707 ferr(po, "unhandled conditional op\n");
6711 pfomask = po->pfomask;
6716 assert_operand_cnt(2);
6717 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6718 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6719 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
6720 fprintf(fout, " %s = %s;", buf1,
6721 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6726 assert_operand_cnt(2);
6727 po->operand[1].lmod = OPLM_DWORD; // always
6728 fprintf(fout, " %s = %s;",
6729 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6730 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6735 assert_operand_cnt(2);
6736 fprintf(fout, " %s = %s;",
6737 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6738 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6742 assert_operand_cnt(2);
6743 switch (po->operand[1].lmod) {
6745 strcpy(buf3, "(s8)");
6748 strcpy(buf3, "(s16)");
6751 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6753 fprintf(fout, " %s = %s;",
6754 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6755 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6760 assert_operand_cnt(2);
6761 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6762 fprintf(fout, " tmp = %s;",
6763 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6764 fprintf(fout, " %s = %s;",
6765 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6766 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6767 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6768 fprintf(fout, " %s = %stmp;",
6769 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6770 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
6771 snprintf(g_comment, sizeof(g_comment), "xchg");
6775 assert_operand_cnt(1);
6776 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6777 fprintf(fout, " %s = ~%s;", buf1, buf1);
6781 assert_operand_cnt(2);
6782 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6783 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6784 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6785 strcpy(g_comment, "xlat");
6789 assert_operand_cnt(2);
6790 fprintf(fout, " %s = (s32)%s >> 31;",
6791 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6792 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6793 strcpy(g_comment, "cdq");
6797 assert_operand_cnt(1);
6798 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6799 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
6803 if (po->flags & OPF_REP) {
6804 assert_operand_cnt(3);
6809 assert_operand_cnt(2);
6810 fprintf(fout, " %s = %sesi; esi %c= %d;",
6811 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6812 lmod_cast_u_ptr(po, po->operand[1].lmod),
6813 (po->flags & OPF_DF) ? '-' : '+',
6814 lmod_bytes(po, po->operand[1].lmod));
6815 strcpy(g_comment, "lods");
6820 if (po->flags & OPF_REP) {
6821 assert_operand_cnt(3);
6822 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
6823 (po->flags & OPF_DF) ? '-' : '+',
6824 lmod_bytes(po, po->operand[1].lmod));
6825 fprintf(fout, " %sedi = eax;",
6826 lmod_cast_u_ptr(po, po->operand[1].lmod));
6827 strcpy(g_comment, "rep stos");
6830 assert_operand_cnt(2);
6831 fprintf(fout, " %sedi = eax; edi %c= %d;",
6832 lmod_cast_u_ptr(po, po->operand[1].lmod),
6833 (po->flags & OPF_DF) ? '-' : '+',
6834 lmod_bytes(po, po->operand[1].lmod));
6835 strcpy(g_comment, "stos");
6840 j = lmod_bytes(po, po->operand[0].lmod);
6841 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6842 l = (po->flags & OPF_DF) ? '-' : '+';
6843 if (po->flags & OPF_REP) {
6844 assert_operand_cnt(3);
6846 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
6849 " %sedi = %sesi;", buf1, buf1);
6850 strcpy(g_comment, "rep movs");
6853 assert_operand_cnt(2);
6854 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
6855 buf1, buf1, l, j, l, j);
6856 strcpy(g_comment, "movs");
6861 // repe ~ repeat while ZF=1
6862 j = lmod_bytes(po, po->operand[0].lmod);
6863 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6864 l = (po->flags & OPF_DF) ? '-' : '+';
6865 if (po->flags & OPF_REP) {
6866 assert_operand_cnt(3);
6868 " while (ecx != 0) {\n");
6869 if (pfomask & (1 << PFO_C)) {
6872 " cond_c = %sesi < %sedi;\n", buf1, buf1);
6873 pfomask &= ~(1 << PFO_C);
6876 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
6877 buf1, buf1, l, j, l, j);
6880 " if (cond_z %s 0) break;\n",
6881 (po->flags & OPF_REPZ) ? "==" : "!=");
6884 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
6885 (po->flags & OPF_REPZ) ? "e" : "ne");
6888 assert_operand_cnt(2);
6890 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
6891 buf1, buf1, l, j, l, j);
6892 strcpy(g_comment, "cmps");
6894 pfomask &= ~(1 << PFO_Z);
6895 last_arith_dst = NULL;
6896 delayed_flag_op = NULL;
6900 // only does ZF (for now)
6901 // repe ~ repeat while ZF=1
6902 j = lmod_bytes(po, po->operand[1].lmod);
6903 l = (po->flags & OPF_DF) ? '-' : '+';
6904 if (po->flags & OPF_REP) {
6905 assert_operand_cnt(3);
6907 " while (ecx != 0) {\n");
6909 " cond_z = (%seax == %sedi); edi %c= %d;\n",
6910 lmod_cast_u(po, po->operand[1].lmod),
6911 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6914 " if (cond_z %s 0) break;\n",
6915 (po->flags & OPF_REPZ) ? "==" : "!=");
6918 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
6919 (po->flags & OPF_REPZ) ? "e" : "ne");
6922 assert_operand_cnt(2);
6923 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
6924 lmod_cast_u(po, po->operand[1].lmod),
6925 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6926 strcpy(g_comment, "scas");
6928 pfomask &= ~(1 << PFO_Z);
6929 last_arith_dst = NULL;
6930 delayed_flag_op = NULL;
6933 // arithmetic w/flags
6935 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
6936 goto dualop_arith_const;
6937 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6941 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6942 if (po->operand[1].type == OPT_CONST) {
6943 j = lmod_bytes(po, po->operand[0].lmod);
6944 if (((1ull << j * 8) - 1) == po->operand[1].val)
6945 goto dualop_arith_const;
6950 assert_operand_cnt(2);
6951 fprintf(fout, " %s %s= %s;",
6952 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6954 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6955 output_std_flags(fout, po, &pfomask, buf1);
6956 last_arith_dst = &po->operand[0];
6957 delayed_flag_op = NULL;
6961 // and 0, or ~0 used instead mov
6962 assert_operand_cnt(2);
6963 fprintf(fout, " %s = %s;",
6964 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6965 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6966 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6967 output_std_flags(fout, po, &pfomask, buf1);
6968 last_arith_dst = &po->operand[0];
6969 delayed_flag_op = NULL;
6974 assert_operand_cnt(2);
6975 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6976 if (pfomask & (1 << PFO_C)) {
6977 if (po->operand[1].type == OPT_CONST) {
6978 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6979 j = po->operand[1].val;
6982 if (po->op == OP_SHL)
6986 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
6990 ferr(po, "zero shift?\n");
6994 pfomask &= ~(1 << PFO_C);
6996 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
6997 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6998 if (po->operand[1].type != OPT_CONST)
6999 fprintf(fout, " & 0x1f");
7001 output_std_flags(fout, po, &pfomask, buf1);
7002 last_arith_dst = &po->operand[0];
7003 delayed_flag_op = NULL;
7007 assert_operand_cnt(2);
7008 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7009 fprintf(fout, " %s = %s%s >> %s;", buf1,
7010 lmod_cast_s(po, po->operand[0].lmod), buf1,
7011 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7012 output_std_flags(fout, po, &pfomask, buf1);
7013 last_arith_dst = &po->operand[0];
7014 delayed_flag_op = NULL;
7019 assert_operand_cnt(3);
7020 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7021 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7022 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
7023 if (po->operand[2].type != OPT_CONST) {
7024 // no handling for "undefined" case, hopefully not needed
7025 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
7028 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7029 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7030 if (po->op == OP_SHLD) {
7031 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
7032 buf1, buf3, buf1, buf2, l, buf3);
7033 strcpy(g_comment, "shld");
7036 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
7037 buf1, buf3, buf1, buf2, l, buf3);
7038 strcpy(g_comment, "shrd");
7040 output_std_flags(fout, po, &pfomask, buf1);
7041 last_arith_dst = &po->operand[0];
7042 delayed_flag_op = NULL;
7047 assert_operand_cnt(2);
7048 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7049 if (po->operand[1].type == OPT_CONST) {
7050 j = po->operand[1].val;
7051 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
7052 fprintf(fout, po->op == OP_ROL ?
7053 " %s = (%s << %d) | (%s >> %d);" :
7054 " %s = (%s >> %d) | (%s << %d);",
7055 buf1, buf1, j, buf1,
7056 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
7060 output_std_flags(fout, po, &pfomask, buf1);
7061 last_arith_dst = &po->operand[0];
7062 delayed_flag_op = NULL;
7067 assert_operand_cnt(2);
7068 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7069 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7070 if (po->operand[1].type == OPT_CONST) {
7071 j = po->operand[1].val % l;
7073 ferr(po, "zero rotate\n");
7074 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
7075 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
7076 if (po->op == OP_RCL) {
7078 " %s = (%s << %d) | (cond_c << %d)",
7079 buf1, buf1, j, j - 1);
7081 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
7085 " %s = (%s >> %d) | (cond_c << %d)",
7086 buf1, buf1, j, l - j);
7088 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
7090 fprintf(fout, ";\n");
7091 fprintf(fout, " cond_c = tmp;");
7095 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
7096 output_std_flags(fout, po, &pfomask, buf1);
7097 last_arith_dst = &po->operand[0];
7098 delayed_flag_op = NULL;
7102 assert_operand_cnt(2);
7103 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7104 if (IS(opr_name(po, 0), opr_name(po, 1))) {
7105 // special case for XOR
7106 int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
7107 for (j = 0; j <= PFO_LE; j++) {
7108 if (pfomask & (1 << j)) {
7109 fprintf(fout, " cond_%s = %d;\n",
7110 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
7111 pfomask &= ~(1 << j);
7114 fprintf(fout, " %s = 0;",
7115 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7116 last_arith_dst = &po->operand[0];
7117 delayed_flag_op = NULL;
7123 assert_operand_cnt(2);
7124 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7125 if (pfomask & (1 << PFO_C)) {
7126 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7127 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7128 if (po->operand[0].lmod == OPLM_DWORD) {
7129 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
7130 fprintf(fout, " cond_c = tmp64 >> 32;\n");
7131 fprintf(fout, " %s = (u32)tmp64;",
7132 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7133 strcat(g_comment, " add64");
7136 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
7137 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
7138 fprintf(fout, " %s += %s;",
7139 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7142 pfomask &= ~(1 << PFO_C);
7143 output_std_flags(fout, po, &pfomask, buf1);
7144 last_arith_dst = &po->operand[0];
7145 delayed_flag_op = NULL;
7148 if (pfomask & (1 << PFO_LE)) {
7149 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
7150 fprintf(fout, " cond_%s = %s;\n",
7151 parsed_flag_op_names[PFO_LE], buf1);
7152 pfomask &= ~(1 << PFO_LE);
7157 assert_operand_cnt(2);
7158 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7159 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
7160 for (j = 0; j <= PFO_LE; j++) {
7161 if (!(pfomask & (1 << j)))
7163 if (j == PFO_Z || j == PFO_S)
7166 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7167 fprintf(fout, " cond_%s = %s;\n",
7168 parsed_flag_op_names[j], buf1);
7169 pfomask &= ~(1 << j);
7176 assert_operand_cnt(2);
7177 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7178 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7179 if (po->op == OP_SBB
7180 && IS(po->operand[0].name, po->operand[1].name))
7182 // avoid use of unitialized var
7183 fprintf(fout, " %s = -cond_c;", buf1);
7184 // carry remains what it was
7185 pfomask &= ~(1 << PFO_C);
7188 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
7189 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7191 output_std_flags(fout, po, &pfomask, buf1);
7192 last_arith_dst = &po->operand[0];
7193 delayed_flag_op = NULL;
7198 // on SKL, if src is 0, dst is left unchanged
7199 assert_operand_cnt(2);
7200 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7201 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7202 output_std_flag_z(fout, po, &pfomask, buf2);
7203 if (po->op == OP_BSF)
7204 snprintf(buf3, sizeof(buf3), "__builtin_ffs(%s) - 1", buf2);
7206 snprintf(buf3, sizeof(buf3), "31 - __builtin_clz(%s)", buf2);
7207 fprintf(fout, " if (%s) %s = %s;", buf2, buf1, buf3);
7208 last_arith_dst = &po->operand[0];
7209 delayed_flag_op = NULL;
7210 strcat(g_comment, po->op == OP_BSF ? " bsf" : " bsr");
7214 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
7215 for (j = 0; j <= PFO_LE; j++) {
7216 if (!(pfomask & (1 << j)))
7218 if (j == PFO_Z || j == PFO_S || j == PFO_C)
7221 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7222 fprintf(fout, " cond_%s = %s;\n",
7223 parsed_flag_op_names[j], buf1);
7224 pfomask &= ~(1 << j);
7230 if (pfomask & (1 << PFO_C))
7231 // carry is unaffected by inc/dec.. wtf?
7232 ferr(po, "carry propagation needed\n");
7234 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7235 if (po->operand[0].type == OPT_REG) {
7236 strcpy(buf2, po->op == OP_INC ? "++" : "--");
7237 fprintf(fout, " %s%s;", buf1, buf2);
7240 strcpy(buf2, po->op == OP_INC ? "+" : "-");
7241 fprintf(fout, " %s %s= 1;", buf1, buf2);
7243 output_std_flags(fout, po, &pfomask, buf1);
7244 last_arith_dst = &po->operand[0];
7245 delayed_flag_op = NULL;
7249 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7250 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
7251 fprintf(fout, " %s = -%s%s;", buf1,
7252 lmod_cast_s(po, po->operand[0].lmod), buf2);
7253 last_arith_dst = &po->operand[0];
7254 delayed_flag_op = NULL;
7255 if (pfomask & PFOB_C) {
7256 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
7259 output_std_flags(fout, po, &pfomask, buf1);
7263 if (po->operand_cnt == 2) {
7264 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7267 if (po->operand_cnt == 3)
7268 ferr(po, "TODO imul3\n");
7271 assert_operand_cnt(1);
7272 switch (po->operand[0].lmod) {
7274 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
7275 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
7276 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
7277 fprintf(fout, " edx = tmp64 >> 32;\n");
7278 fprintf(fout, " eax = tmp64;");
7281 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
7282 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
7283 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
7287 ferr(po, "TODO: unhandled mul type\n");
7290 last_arith_dst = NULL;
7291 delayed_flag_op = NULL;
7296 assert_operand_cnt(1);
7297 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7298 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
7299 po->op == OP_IDIV));
7300 switch (po->operand[0].lmod) {
7302 if (po->flags & OPF_32BIT)
7303 snprintf(buf2, sizeof(buf2), "%seax", cast);
7305 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7306 snprintf(buf2, sizeof(buf2), "%stmp64",
7307 (po->op == OP_IDIV) ? "(s64)" : "");
7309 if (po->operand[0].type == OPT_REG
7310 && po->operand[0].reg == xDX)
7312 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
7313 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
7316 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
7317 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
7321 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
7322 snprintf(buf2, sizeof(buf2), "%stmp",
7323 (po->op == OP_IDIV) ? "(s32)" : "");
7324 if (po->operand[0].type == OPT_REG
7325 && po->operand[0].reg == xDX)
7327 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
7329 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
7333 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
7335 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
7338 strcat(g_comment, " div16");
7341 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
7343 last_arith_dst = NULL;
7344 delayed_flag_op = NULL;
7349 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7351 for (j = 0; j < 8; j++) {
7352 if (pfomask & (1 << j)) {
7353 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
7354 fprintf(fout, " cond_%s = %s;",
7355 parsed_flag_op_names[j], buf1);
7362 last_arith_dst = NULL;
7363 delayed_flag_op = po;
7367 // SETcc - should already be handled
7370 // note: we reuse OP_Jcc for SETcc, only flags differ
7372 fprintf(fout, "\n goto %s;", po->operand[0].name);
7376 fprintf(fout, " if (ecx == 0)\n");
7377 fprintf(fout, " goto %s;", po->operand[0].name);
7378 strcat(g_comment, " jecxz");
7382 fprintf(fout, " if (--ecx != 0)\n");
7383 fprintf(fout, " goto %s;", po->operand[0].name);
7384 strcat(g_comment, " loop");
7388 assert_operand_cnt(1);
7389 last_arith_dst = NULL;
7390 delayed_flag_op = NULL;
7392 if (po->operand[0].type == OPT_REGMEM) {
7393 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
7396 ferr(po, "parse failure for jmp '%s'\n",
7397 po->operand[0].name);
7398 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
7401 else if (po->operand[0].type != OPT_LABEL)
7402 ferr(po, "unhandled jmp type\n");
7404 fprintf(fout, " goto %s;", po->operand[0].name);
7408 assert_operand_cnt(1);
7410 my_assert_not(pp, NULL);
7413 if (po->flags & OPF_CC) {
7414 // we treat conditional branch to another func
7415 // (yes such code exists..) as conditional tailcall
7417 fprintf(fout, " {\n");
7420 if (pp->is_fptr && !pp->is_arg) {
7421 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
7422 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7425 if (pp->is_fptr && (pp->is_unresolved || pp->is_guessed)) {
7426 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
7427 buf3, asmfn, po->asmln, pp->name);
7430 fprintf(fout, "%s", buf3);
7431 if (strstr(pp->ret_type.name, "int64")) {
7432 if (po->flags & OPF_TAIL)
7433 ferr(po, "int64 and tail?\n");
7434 fprintf(fout, "tmp64 = ");
7436 else if (!IS(pp->ret_type.name, "void")) {
7437 if (po->flags & OPF_TAIL) {
7438 if (regmask_ret & mxAX) {
7439 fprintf(fout, "return ");
7440 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
7441 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
7443 else if (regmask_ret & mxST0)
7444 ferr(po, "float tailcall\n");
7446 else if (po->regmask_dst & mxAX) {
7447 fprintf(fout, "eax = ");
7448 if (pp->ret_type.is_ptr)
7449 fprintf(fout, "(u32)");
7451 else if (po->regmask_dst & mxST0) {
7452 ferr_assert(po, po->flags & OPF_FPUSH);
7453 if (need_float_stack)
7454 fprintf(fout, "f_st[--f_stp & 7] = ");
7456 fprintf(fout, "f_st0 = ");
7460 if (pp->name[0] == 0)
7461 ferr(po, "missing pp->name\n");
7462 fprintf(fout, "%s%s(", pp->name,
7463 pp->has_structarg ? "_sa" : "");
7465 if (po->flags & OPF_ATAIL) {
7467 g_func_pp->is_stdcall && g_func_pp->argc_stack > 0;
7468 check_compat |= pp->argc_stack > 0;
7470 && (pp->argc_stack != g_func_pp->argc_stack
7471 || pp->is_stdcall != g_func_pp->is_stdcall))
7472 ferr(po, "incompatible arg-reuse tailcall\n");
7473 if (g_func_pp->has_retreg)
7474 ferr(po, "TODO: retreg+tailcall\n");
7476 for (arg = j = 0; arg < pp->argc; arg++) {
7478 fprintf(fout, ", ");
7481 if (pp->arg[arg].type.is_ptr)
7482 snprintf(cast, sizeof(cast), "(%s)",
7483 pp->arg[arg].type.name);
7485 if (pp->arg[arg].reg != NULL) {
7486 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7490 for (; j < g_func_pp->argc; j++)
7491 if (g_func_pp->arg[j].reg == NULL)
7493 fprintf(fout, "%sa%d", cast, j + 1);
7498 for (arg = 0; arg < pp->argc; arg++) {
7500 fprintf(fout, ", ");
7503 if (pp->arg[arg].type.is_ptr)
7504 snprintf(cast, sizeof(cast), "(%s)",
7505 pp->arg[arg].type.name);
7507 if (pp->arg[arg].reg != NULL) {
7508 if (pp->arg[arg].type.is_retreg)
7509 fprintf(fout, "&%s", pp->arg[arg].reg);
7510 else if (IS(pp->arg[arg].reg, "ebp")
7511 && g_bp_frame && !(po->flags & OPF_EBP_S))
7513 // rare special case
7514 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
7515 strcat(g_comment, " bp_ref");
7518 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7523 tmp_op = pp->arg[arg].datap;
7525 ferr(po, "parsed_op missing for arg%d\n", arg);
7527 if (tmp_op->flags & OPF_VAPUSH) {
7528 fprintf(fout, "ap");
7530 else if (tmp_op->op == OP_FST) {
7531 fprintf(fout, "fs_%d", tmp_op->p_argnum);
7532 if (tmp_op->operand[0].lmod == OPLM_QWORD)
7535 else if (pp->arg[arg].type.is_64bit) {
7536 ferr_assert(po, tmp_op->p_argpass == 0);
7537 ferr_assert(po, !pp->arg[arg].is_saved);
7538 ferr_assert(po, !pp->arg[arg].type.is_float);
7539 ferr_assert(po, cast[0] == 0);
7540 out_src_opr(buf1, sizeof(buf1),
7541 tmp_op, &tmp_op->operand[0], cast, 0);
7542 tmp_op = pp->arg[++arg].datap;
7543 ferr_assert(po, tmp_op != NULL);
7544 out_src_opr(buf2, sizeof(buf2),
7545 tmp_op, &tmp_op->operand[0], cast, 0);
7546 fprintf(fout, "((u64)(%s) << 32) | (%s)",
7549 else if (tmp_op->p_argpass != 0) {
7550 ferr_assert(po, !pp->arg[arg].type.is_float);
7551 fprintf(fout, "a%d", tmp_op->p_argpass);
7553 else if (pp->arg[arg].is_saved) {
7554 ferr_assert(po, tmp_op->p_argnum > 0);
7555 ferr_assert(po, !pp->arg[arg].type.is_float);
7556 fprintf(fout, "%s%s", cast,
7557 saved_arg_name(buf1, sizeof(buf1),
7558 tmp_op->p_arggrp, tmp_op->p_argnum));
7560 else if (pp->arg[arg].type.is_float) {
7561 ferr_assert(po, !pp->arg[arg].type.is_64bit);
7563 out_src_opr_float(buf1, sizeof(buf1),
7564 tmp_op, &tmp_op->operand[0], need_float_stack));
7568 out_src_opr(buf1, sizeof(buf1),
7569 tmp_op, &tmp_op->operand[0], cast, 0));
7573 fprintf(fout, ");");
7575 if (strstr(pp->ret_type.name, "int64")) {
7576 fprintf(fout, "\n");
7577 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7578 fprintf(fout, "%seax = tmp64;", buf3);
7581 if (pp->is_unresolved) {
7582 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
7584 strcat(g_comment, buf2);
7587 if (po->flags & OPF_TAIL) {
7589 if (i == opcnt - 1 || pp->is_noreturn)
7591 else if (IS(pp->ret_type.name, "void"))
7593 else if (!(regmask_ret & (1 << xAX)))
7595 // else already handled as 'return f()'
7598 fprintf(fout, "\n%sreturn;", buf3);
7599 strcat(g_comment, " ^ tailcall");
7602 strcat(g_comment, " tailcall");
7604 if ((regmask_ret & (1 << xAX))
7605 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7607 ferr(po, "int func -> void func tailcall?\n");
7610 if (pp->is_noreturn)
7611 strcat(g_comment, " noreturn");
7612 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7613 strcat(g_comment, " argframe");
7614 if (po->flags & OPF_CC)
7615 strcat(g_comment, " cond");
7617 if (po->flags & OPF_CC)
7618 fprintf(fout, "\n }");
7620 delayed_flag_op = NULL;
7621 last_arith_dst = NULL;
7625 if (g_func_pp->is_vararg)
7626 fprintf(fout, " va_end(ap);\n");
7627 if (g_func_pp->has_retreg) {
7628 for (arg = 0; arg < g_func_pp->argc; arg++)
7629 if (g_func_pp->arg[arg].type.is_retreg)
7630 fprintf(fout, " *r_%s = %s;\n",
7631 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7634 if (regmask_ret & mxST0) {
7635 fprintf(fout, " return %s;", float_st0);
7637 else if (!(regmask_ret & mxAX)) {
7638 if (i != opcnt - 1 || label_pending)
7639 fprintf(fout, " return;");
7641 else if (g_func_pp->ret_type.is_ptr) {
7642 fprintf(fout, " return (%s)eax;",
7643 g_func_pp->ret_type.name);
7645 else if (IS(g_func_pp->ret_type.name, "__int64"))
7646 fprintf(fout, " return ((u64)edx << 32) | eax;");
7648 fprintf(fout, " return eax;");
7650 last_arith_dst = NULL;
7651 delayed_flag_op = NULL;
7655 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7656 if (po->p_argnum != 0) {
7657 // special case - saved func arg
7658 fprintf(fout, " %s = %s;",
7659 saved_arg_name(buf2, sizeof(buf2),
7660 po->p_arggrp, po->p_argnum), buf1);
7663 else if (po->flags & OPF_RSAVE) {
7664 fprintf(fout, " s_%s = %s;", buf1, buf1);
7667 else if (po->flags & OPF_PPUSH) {
7669 ferr_assert(po, tmp_op != NULL);
7670 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7671 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7674 else if (g_func_pp->is_userstack) {
7675 fprintf(fout, " *(--esp) = %s;", buf1);
7678 if (!(g_ida_func_attr & IDAFA_NORETURN))
7679 ferr(po, "stray push encountered\n");
7684 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7685 if (po->flags & OPF_RSAVE) {
7686 fprintf(fout, " %s = s_%s;", buf1, buf1);
7689 else if (po->flags & OPF_PPUSH) {
7690 // push/pop graph / non-const
7691 ferr_assert(po, po->datap == NULL);
7692 fprintf(fout, " %s = pp_%s;", buf1, buf1);
7695 else if (po->datap != NULL) {
7698 fprintf(fout, " %s = %s;", buf1,
7699 out_src_opr(buf2, sizeof(buf2),
7700 tmp_op, &tmp_op->operand[0],
7701 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7704 else if (g_func_pp->is_userstack) {
7705 fprintf(fout, " %s = *esp++;", buf1);
7709 ferr(po, "stray pop encountered\n");
7719 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7720 fprintf(fout, " tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
7721 po->op == OPP_ALLSHL ? "<<" : ">>");
7722 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
7723 strcat(g_comment, po->op == OPP_ALLSHL
7724 ? " allshl" : " allshr");
7729 if (need_float_stack) {
7730 out_src_opr_float(buf1, sizeof(buf1),
7731 po, &po->operand[0], 1);
7732 if (po->regmask_src & mxSTa) {
7733 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7737 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
7740 if (po->flags & OPF_FSHIFT)
7741 fprintf(fout, " f_st1 = f_st0;");
7742 if (po->operand[0].type == OPT_REG
7743 && po->operand[0].reg == xST0)
7745 strcat(g_comment, " fld st");
7748 fprintf(fout, " f_st0 = %s;",
7749 out_src_opr_float(buf1, sizeof(buf1),
7750 po, &po->operand[0], 0));
7752 strcat(g_comment, " fld");
7756 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7757 lmod_cast(po, po->operand[0].lmod, 1), 0);
7758 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7759 if (need_float_stack) {
7760 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
7763 if (po->flags & OPF_FSHIFT)
7764 fprintf(fout, " f_st1 = f_st0;");
7765 fprintf(fout, " f_st0 = %s;", buf2);
7767 strcat(g_comment, " fild");
7771 if (need_float_stack)
7772 fprintf(fout, " f_st[--f_stp & 7] = ");
7774 if (po->flags & OPF_FSHIFT)
7775 fprintf(fout, " f_st1 = f_st0;");
7776 fprintf(fout, " f_st0 = ");
7778 switch (po->operand[0].val) {
7779 case X87_CONST_1: fprintf(fout, "1.0;"); break;
7780 case X87_CONST_L2T: fprintf(fout, "3.321928094887362;"); break;
7781 case X87_CONST_L2E: fprintf(fout, "M_LOG2E;"); break;
7782 case X87_CONST_PI: fprintf(fout, "M_PI;"); break;
7783 case X87_CONST_LG2: fprintf(fout, "0.301029995663981;"); break;
7784 case X87_CONST_LN2: fprintf(fout, "M_LN2;"); break;
7785 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
7786 default: ferr_assert(po, 0); break;
7791 if (po->flags & OPF_FARG) {
7792 // store to stack as func arg
7793 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7797 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7799 dead_dst = po->operand[0].type == OPT_REG
7800 && po->operand[0].reg == xST0;
7803 fprintf(fout, " %s = %s;", buf1, float_st0);
7804 if (po->flags & OPF_FSHIFT) {
7805 if (need_float_stack)
7806 fprintf(fout, " f_stp++;");
7808 fprintf(fout, " f_st0 = f_st1;");
7810 if (dead_dst && !(po->flags & OPF_FSHIFT))
7813 strcat(g_comment, " fst");
7817 fprintf(fout, " %s = %s%s;",
7818 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7819 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7820 if (po->flags & OPF_FSHIFT) {
7821 if (need_float_stack)
7822 fprintf(fout, " f_stp++;");
7824 fprintf(fout, " f_st0 = f_st1;");
7826 strcat(g_comment, " fist");
7833 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7835 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7837 dead_dst = (po->flags & OPF_FPOP)
7838 && po->operand[0].type == OPT_REG
7839 && po->operand[0].reg == xST0;
7841 case OP_FADD: j = '+'; break;
7842 case OP_FDIV: j = '/'; break;
7843 case OP_FMUL: j = '*'; break;
7844 case OP_FSUB: j = '-'; break;
7845 default: j = 'x'; break;
7847 if (need_float_stack) {
7849 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7850 if (po->flags & OPF_FSHIFT)
7851 fprintf(fout, " f_stp++;");
7854 if (po->flags & OPF_FSHIFT) {
7855 // note: assumes only 2 regs handled
7857 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
7859 fprintf(fout, " f_st0 = f_st1;");
7862 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7864 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7869 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7871 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7873 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
7875 dead_dst = (po->flags & OPF_FPOP)
7876 && po->operand[0].type == OPT_REG
7877 && po->operand[0].reg == xST0;
7878 j = po->op == OP_FDIVR ? '/' : '-';
7879 if (need_float_stack) {
7881 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7882 if (po->flags & OPF_FSHIFT)
7883 fprintf(fout, " f_stp++;");
7886 if (po->flags & OPF_FSHIFT) {
7888 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
7890 fprintf(fout, " f_st0 = f_st1;");
7893 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7895 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7903 case OP_FIADD: j = '+'; break;
7904 case OP_FIDIV: j = '/'; break;
7905 case OP_FIMUL: j = '*'; break;
7906 case OP_FISUB: j = '-'; break;
7907 default: j = 'x'; break;
7909 fprintf(fout, " %s %c= (%s)%s;", float_st0,
7911 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7912 lmod_cast(po, po->operand[0].lmod, 1), 0));
7917 fprintf(fout, " %s = %s %c %s;", float_st0,
7918 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7920 po->op == OP_FIDIVR ? '/' : '-', float_st0);
7925 ferr_assert(po, po->datap != NULL);
7926 mask = (long)po->datap & 0xffff;
7927 z_check = ((long)po->datap >> 16) & 1;
7928 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7930 if (mask == 0x0100 || mask == 0x0500) { // C0 -> <
7931 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
7934 else if (mask == 0x4000 || mask == 0x4400) { // C3 -> =
7935 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
7938 else if (mask == 0x4100) { // C3, C0
7940 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
7942 strcat(g_comment, " z_chk_det");
7945 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
7946 "(%s < %s ? 0x0100 : 0);",
7947 float_st0, buf1, float_st0, buf1);
7951 ferr(po, "unhandled sw mask: %x\n", mask);
7952 if (po->flags & OPF_FSHIFT) {
7953 if (need_float_stack) {
7954 if (po->flags & OPF_FPOPP)
7955 fprintf(fout, " f_stp += 2;");
7957 fprintf(fout, " f_stp++;");
7960 ferr_assert(po, !(po->flags & OPF_FPOPP));
7961 fprintf(fout, " f_st0 = f_st1;");
7968 fprintf(fout, " %s = f_sw;",
7969 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7973 fprintf(fout, " %s = -%s;", float_st0, float_st0);
7977 fprintf(fout, " %s = cos%s(%s);", float_st0,
7978 need_double ? "" : "f", float_st0);
7982 if (need_float_stack) {
7983 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
7984 need_double ? "" : "f", float_st1, float_st0);
7985 fprintf(fout, " f_stp++;");
7988 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
7989 need_double ? "" : "f");
7994 if (need_float_stack) {
7995 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
7996 float_st1, need_double ? "" : "f", float_st0);
7997 fprintf(fout, " f_stp++;");
8000 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
8001 need_double ? "" : "f");
8003 strcat(g_comment, " fyl2x");
8007 fprintf(fout, " %s = sin%s(%s);", float_st0,
8008 need_double ? "" : "f", float_st0);
8012 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
8013 need_double ? "" : "f", float_st0);
8017 dead_dst = po->operand[0].type == OPT_REG
8018 && po->operand[0].reg == xST0;
8020 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8022 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
8023 float_st0, float_st0, buf1, buf1);
8024 strcat(g_comment, " fxch");
8031 ferr_assert(po, po->flags & OPF_32BIT);
8032 fprintf(fout, " eax = (s32)%s;", float_st0);
8033 if (po->flags & OPF_FSHIFT) {
8034 if (need_float_stack)
8035 fprintf(fout, " f_stp++;");
8037 fprintf(fout, " f_st0 = f_st1;");
8039 strcat(g_comment, " ftol");
8043 if (need_float_stack) {
8044 fprintf(fout, " %s = pow%s(%s, %s);", float_st1,
8045 need_double ? "" : "f", float_st1, float_st0);
8046 fprintf(fout, " f_stp++;");
8049 fprintf(fout, " f_st0 = pow%s(f_st1, f_st0);",
8050 need_double ? "" : "f");
8052 strcat(g_comment, " CIpow");
8056 fprintf(fout, " do_skip_code_abort();");
8061 fprintf(fout, " do_emms();");
8066 ferr(po, "unhandled op type %d, flags %x\n",
8071 if (g_comment[0] != 0) {
8072 char *p = g_comment;
8073 while (my_isblank(*p))
8075 fprintf(fout, " // %s", p);
8080 fprintf(fout, "\n");
8082 // some sanity checking
8083 if (po->flags & OPF_REP) {
8084 if (po->op != OP_STOS && po->op != OP_MOVS
8085 && po->op != OP_CMPS && po->op != OP_SCAS)
8086 ferr(po, "unexpected rep\n");
8087 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
8088 && (po->op == OP_CMPS || po->op == OP_SCAS))
8089 ferr(po, "cmps/scas with plain rep\n");
8091 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
8092 && po->op != OP_CMPS && po->op != OP_SCAS)
8093 ferr(po, "unexpected repz/repnz\n");
8096 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
8098 // see is delayed flag stuff is still valid
8099 if (delayed_flag_op != NULL && delayed_flag_op != po) {
8100 if (is_any_opr_modified(delayed_flag_op, po, 0))
8101 delayed_flag_op = NULL;
8104 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
8105 if (is_opr_modified(last_arith_dst, po))
8106 last_arith_dst = NULL;
8113 if (g_stack_fsz && !g_stack_frame_used)
8114 fprintf(fout, " (void)sf;\n");
8116 fprintf(fout, "}\n\n");
8118 gen_x_cleanup(opcnt);
8121 static void gen_x_cleanup(int opcnt)
8125 for (i = 0; i < opcnt; i++) {
8126 struct label_ref *lr, *lr_del;
8128 lr = g_label_refs[i].next;
8129 while (lr != NULL) {
8134 g_label_refs[i].i = -1;
8135 g_label_refs[i].next = NULL;
8137 if (ops[i].op == OP_CALL) {
8139 proto_release(ops[i].pp);
8145 struct func_proto_dep;
8147 struct func_prototype {
8151 int regmask_dep; // likely register args
8152 int regmask_use; // used registers
8153 int has_ret:3; // -1, 0, 1: unresolved, no, yes
8154 unsigned int has_ret64:1;
8155 unsigned int dep_resolved:1;
8156 unsigned int is_stdcall:1;
8157 unsigned int eax_pass:1; // returns without touching eax
8158 struct func_proto_dep *dep_func;
8160 const struct parsed_proto *pp; // seed pp, if any
8163 struct func_proto_dep {
8165 struct func_prototype *proto;
8166 int regmask_live; // .. at the time of call
8167 unsigned int ret_dep:1; // return from this is caller's return
8168 unsigned int has_ret:1; // found from eax use after return
8169 unsigned int has_ret64:1;
8172 static struct func_prototype *hg_fp;
8173 static int hg_fp_cnt;
8175 static struct scanned_var {
8177 enum opr_lenmod lmod;
8178 unsigned int is_seeded:1;
8179 unsigned int is_c_str:1;
8180 const struct parsed_proto *pp; // seed pp, if any
8182 static int hg_var_cnt;
8184 static char **hg_refs;
8185 static int hg_ref_cnt;
8187 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8190 static struct func_prototype *hg_fp_add(const char *funcn)
8192 struct func_prototype *fp;
8194 if ((hg_fp_cnt & 0xff) == 0) {
8195 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
8196 my_assert_not(hg_fp, NULL);
8197 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
8200 fp = &hg_fp[hg_fp_cnt];
8201 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
8203 fp->argc_stack = -1;
8209 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
8214 for (i = 0; i < fp->dep_func_cnt; i++)
8215 if (IS(fp->dep_func[i].name, name))
8216 return &fp->dep_func[i];
8221 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
8224 if (hg_fp_find_dep(fp, name))
8227 if ((fp->dep_func_cnt & 0xff) == 0) {
8228 fp->dep_func = realloc(fp->dep_func,
8229 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
8230 my_assert_not(fp->dep_func, NULL);
8231 memset(&fp->dep_func[fp->dep_func_cnt], 0,
8232 sizeof(fp->dep_func[0]) * 0x100);
8234 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
8238 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
8240 const struct func_prototype *p1 = p1_, *p2 = p2_;
8241 return strcmp(p1->name, p2->name);
8245 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
8247 const struct func_prototype *p1 = p1_, *p2 = p2_;
8248 return p1->id - p2->id;
8252 static void hg_ref_add(const char *name)
8254 if ((hg_ref_cnt & 0xff) == 0) {
8255 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
8256 my_assert_not(hg_refs, NULL);
8257 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
8260 hg_refs[hg_ref_cnt] = strdup(name);
8261 my_assert_not(hg_refs[hg_ref_cnt], NULL);
8265 // recursive register dep pass
8266 // - track saved regs (part 2)
8267 // - try to figure out arg-regs
8268 // - calculate reg deps
8269 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
8270 struct func_prototype *fp, int regmask_save, int regmask_dst,
8271 int *regmask_dep, int *regmask_use, int *has_ret)
8273 struct func_proto_dep *dep;
8274 struct parsed_op *po;
8275 int from_caller = 0;
8280 for (; i < opcnt; i++)
8282 if (cbits[i >> 3] & (1 << (i & 7)))
8284 cbits[i >> 3] |= (1 << (i & 7));
8288 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
8289 if (po->flags & OPF_RMD)
8292 if (po->btj != NULL) {
8294 for (j = 0; j < po->btj->count; j++) {
8295 check_i(po, po->btj->d[j].bt_i);
8296 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
8297 regmask_save, regmask_dst, regmask_dep, regmask_use,
8303 check_i(po, po->bt_i);
8304 if (po->flags & OPF_CJMP) {
8305 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
8306 regmask_save, regmask_dst, regmask_dep, regmask_use,
8315 if (po->flags & OPF_FARG)
8316 /* (just calculate register deps) */;
8317 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
8319 reg = po->operand[0].reg;
8320 ferr_assert(po, reg >= 0);
8322 if (po->flags & OPF_RSAVE) {
8323 regmask_save |= 1 << reg;
8326 if (po->flags & OPF_DONE)
8329 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0, 0);
8331 regmask_save |= 1 << reg;
8332 po->flags |= OPF_RMD;
8333 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, OPF_RMD);
8337 else if (po->flags & OPF_RMD)
8339 else if (po->op == OP_CALL) {
8340 po->regmask_dst |= 1 << xAX;
8342 dep = hg_fp_find_dep(fp, po->operand[0].name);
8344 dep->regmask_live = regmask_save | regmask_dst;
8345 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8346 dep->regmask_live |= 1 << xBP;
8349 else if (po->op == OP_RET) {
8350 if (po->operand_cnt > 0) {
8352 if (fp->argc_stack >= 0
8353 && fp->argc_stack != po->operand[0].val / 4)
8354 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
8355 fp->argc_stack = po->operand[0].val / 4;
8359 if (!fp->eax_pass && (po->flags & OPF_TAIL)) {
8360 if (po->op == OP_CALL) {
8365 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
8368 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
8371 if (ret != 1 && from_caller) {
8372 // unresolved eax - probably void func
8377 if (j >= 0 && ops[j].op == OP_CALL) {
8378 if (ops[j].pp != NULL && !ops[j].pp->is_unresolved) {
8379 int call_has_ret = !IS(ops[j].pp->ret_type.name, "void");
8380 if (ops[j].pp->is_noreturn) {
8381 // could be some fail path
8383 *has_ret = call_has_ret;
8386 *has_ret = call_has_ret;
8389 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
8401 l = regmask_save | regmask_dst;
8402 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8405 l = po->regmask_src & ~l;
8408 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
8409 l, regmask_dst, regmask_save, po->flags);
8412 *regmask_use |= (po->regmask_src | po->regmask_dst)
8414 regmask_dst |= po->regmask_dst;
8416 if (po->flags & OPF_TAIL) {
8417 if (!(po->flags & OPF_CC)) // not cond. tailcall
8423 static void gen_hdr(const char *funcn, int opcnt)
8425 unsigned char cbits[MAX_OPS / 8];
8426 const struct parsed_proto *pp_c;
8427 struct parsed_proto *pp;
8428 struct func_prototype *fp;
8429 struct func_proto_dep *dep;
8430 struct parsed_op *po;
8431 int regmask_dummy = 0;
8434 int max_bp_offset = 0;
8439 pp_c = proto_parse(g_fhdr, funcn, 1);
8441 // already in seed, will add to hg_fp later
8444 fp = hg_fp_add(funcn);
8446 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
8447 g_stack_frame_used = 0;
8451 // - resolve all branches
8452 // - parse calls with labels
8453 resolve_branches_parse_calls(opcnt);
8456 // - handle ebp/esp frame, remove ops related to it
8457 scan_prologue_epilogue(opcnt, NULL);
8460 // - remove dead labels
8462 for (i = 0; i < opcnt; i++)
8464 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8470 if (po->flags & (OPF_RMD|OPF_DONE))
8473 if (po->op == OP_CALL) {
8474 if (po->operand[0].type == OPT_LABEL)
8475 hg_fp_add_dep(fp, opr_name(po, 0));
8476 else if (po->pp != NULL)
8477 hg_fp_add_dep(fp, po->pp->name);
8482 // - handle push <const>/pop pairs
8483 for (i = 0; i < opcnt; i++)
8486 if (po->flags & (OPF_RMD|OPF_DONE))
8489 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
8490 scan_for_pop_const(i, opcnt, i + opcnt * 13);
8494 // - process trivial calls
8495 for (i = 0; i < opcnt; i++)
8498 if (po->flags & (OPF_RMD|OPF_DONE))
8501 if (po->op == OP_CALL)
8503 pp = process_call_early(i, opcnt, &j);
8505 if (!(po->flags & OPF_ATAIL))
8506 // since we know the args, try to collect them
8507 if (collect_call_args_early(i, pp, NULL, NULL) != 0)
8513 // commit esp adjust
8514 if (ops[j].op != OP_POP)
8515 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
8517 for (l = 0; l < pp->argc_stack; l++)
8518 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
8522 po->flags |= OPF_DONE;
8528 // - track saved regs (simple)
8530 for (i = 0; i < opcnt; i++)
8533 if (po->flags & (OPF_RMD|OPF_DONE))
8536 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
8537 && po->operand[0].reg != xCX)
8539 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
8541 // regmask_save |= 1 << po->operand[0].reg; // do it later
8542 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
8543 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
8546 else if (po->op == OP_CALL)
8548 pp = process_call(i, opcnt);
8550 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
8551 // since we know the args, collect them
8552 ret = collect_call_args(po, i, pp, ®mask_dummy,
8555 if (!(po->flags & OPF_TAIL)
8556 && po->operand[0].type == OPT_LABEL)
8558 dep = hg_fp_find_dep(fp, opr_name(po, 0));
8559 ferr_assert(po, dep != NULL);
8560 // treat al write as overwrite to avoid many false positives
8561 find_next_read_reg(i + 1, opcnt, xAX, OPLM_BYTE,
8562 i + opcnt * 25, &j);
8565 find_next_read_reg(i + 1, opcnt, xDX, OPLM_BYTE,
8566 i + opcnt * 26, &j);
8567 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j]))
8574 memset(cbits, 0, (opcnt + 7) / 8);
8575 regmask_dep = regmask_use = 0;
8578 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0,
8579 ®mask_dep, ®mask_use, &has_ret);
8581 // find unreachable code - must be fixed in IDA
8582 for (i = 0; i < opcnt; i++)
8584 if (cbits[i >> 3] & (1 << (i & 7)))
8587 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
8588 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
8590 // the compiler sometimes still generates code after
8591 // noreturn OS functions
8594 if (!(ops[i].flags & OPF_RMD)
8595 && ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
8597 ferr(&ops[i], "unreachable code\n");
8601 for (i = 0; i < g_eqcnt; i++) {
8602 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
8603 max_bp_offset = g_eqs[i].offset;
8606 if (fp->argc_stack < 0) {
8607 max_bp_offset = (max_bp_offset + 3) & ~3;
8608 fp->argc_stack = max_bp_offset / 4;
8609 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
8613 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
8614 fp->regmask_use = regmask_use;
8615 fp->has_ret = has_ret;
8617 printf("// has_ret %d, regmask_dep %x\n",
8618 fp->has_ret, fp->regmask_dep);
8619 output_hdr_fp(stdout, fp, 1);
8620 if (IS(funcn, "sub_10007F72")) exit(1);
8623 gen_x_cleanup(opcnt);
8626 static void hg_fp_resolve_deps(struct func_prototype *fp)
8628 struct func_prototype fp_s;
8629 struct func_proto_dep *dep;
8633 // this thing is recursive, so mark first..
8634 fp->dep_resolved = 1;
8636 for (i = 0; i < fp->dep_func_cnt; i++) {
8637 dep = &fp->dep_func[i];
8639 strcpy(fp_s.name, dep->name);
8640 dep->proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8641 sizeof(hg_fp[0]), hg_fp_cmp_name);
8642 if (dep->proto != NULL) {
8643 if (!dep->proto->dep_resolved)
8644 hg_fp_resolve_deps(dep->proto);
8646 regmask_dep = ~dep->regmask_live
8647 & dep->proto->regmask_dep;
8648 fp->regmask_dep |= regmask_dep;
8649 // printf("dep %s %s |= %x\n", fp->name,
8650 // fp->dep_func[i].name, regmask_dep);
8652 if (dep->has_ret && (dep->proto->regmask_use & mxAX))
8653 dep->proto->has_ret = 1;
8654 if (dep->has_ret64 && (dep->proto->regmask_use & mxDX))
8655 dep->proto->has_ret64 = 1;
8656 if (fp->has_ret == -1 && dep->ret_dep)
8657 fp->has_ret = dep->proto->has_ret;
8662 // make all thiscall/edx arg functions referenced from .data fastcall
8663 static void do_func_refs_from_data(void)
8665 struct func_prototype *fp, fp_s;
8668 for (i = 0; i < hg_ref_cnt; i++) {
8669 strcpy(fp_s.name, hg_refs[i]);
8670 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8671 sizeof(hg_fp[0]), hg_fp_cmp_name);
8675 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
8676 fp->regmask_dep |= mxCX | mxDX;
8680 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8683 const struct parsed_proto *pp;
8684 char *p, namebuf[NAMELEN];
8690 for (; count > 0; count--, fp++) {
8691 if (fp->has_ret == -1)
8692 fprintf(fout, "// ret unresolved\n");
8694 fprintf(fout, "// dep:");
8695 for (j = 0; j < fp->dep_func_cnt; j++) {
8696 fprintf(fout, " %s/", fp->dep_func[j].name);
8697 if (fp->dep_func[j].proto != NULL)
8698 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8699 fp->dep_func[j].proto->has_ret);
8701 fprintf(fout, "\n");
8704 p = strchr(fp->name, '@');
8706 memcpy(namebuf, fp->name, p - fp->name);
8707 namebuf[p - fp->name] = 0;
8715 pp = proto_parse(g_fhdr, name, 1);
8716 if (pp != NULL && pp->is_include)
8719 if (fp->pp != NULL) {
8720 // part of seed, output later
8724 regmask_dep = fp->regmask_dep;
8725 argc_normal = fp->argc_stack;
8727 fprintf(fout, "%-5s",
8728 fp->pp ? fp->pp->ret_type.name :
8729 fp->has_ret64 ? "__int64" :
8730 fp->has_ret ? "int" : "void");
8731 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
8732 && (regmask_dep & ~mxCX) == 0)
8734 fprintf(fout, "/*__thiscall*/ ");
8738 else if ((regmask_dep == (mxCX | mxDX)
8739 && (fp->is_stdcall || fp->argc_stack == 0))
8740 || (regmask_dep == mxCX && fp->argc_stack == 0))
8742 fprintf(fout, " __fastcall ");
8743 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8749 else if (regmask_dep && !fp->is_stdcall) {
8750 fprintf(fout, "/*__usercall*/ ");
8752 else if (regmask_dep) {
8753 fprintf(fout, "/*__userpurge*/ ");
8755 else if (fp->is_stdcall)
8756 fprintf(fout, " __stdcall ");
8758 fprintf(fout, " __cdecl ");
8760 fprintf(fout, "%s(", name);
8763 for (j = 0; j < xSP; j++) {
8764 if (regmask_dep & (1 << j)) {
8767 fprintf(fout, ", ");
8769 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8771 fprintf(fout, "int");
8772 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
8776 for (j = 0; j < argc_normal; j++) {
8779 fprintf(fout, ", ");
8780 if (fp->pp != NULL) {
8781 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8782 if (!fp->pp->arg[arg - 1].type.is_ptr)
8786 fprintf(fout, "int ");
8787 fprintf(fout, "a%d", arg);
8790 fprintf(fout, ");\n");
8794 static void output_hdr(FILE *fout)
8796 static const char *lmod_c_names[] = {
8797 [OPLM_UNSPEC] = "???",
8798 [OPLM_BYTE] = "uint8_t",
8799 [OPLM_WORD] = "uint16_t",
8800 [OPLM_DWORD] = "uint32_t",
8801 [OPLM_QWORD] = "uint64_t",
8803 const struct scanned_var *var;
8804 struct func_prototype *fp;
8805 char line[256] = { 0, };
8809 // add stuff from headers
8810 for (i = 0; i < pp_cache_size; i++) {
8811 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
8812 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
8814 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
8815 fp = hg_fp_add(name);
8816 fp->pp = &pp_cache[i];
8817 fp->argc_stack = fp->pp->argc_stack;
8818 fp->is_stdcall = fp->pp->is_stdcall;
8819 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
8820 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
8824 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
8825 for (i = 0; i < hg_fp_cnt; i++)
8826 hg_fp_resolve_deps(&hg_fp[i]);
8828 // adjust functions referenced from data segment
8829 do_func_refs_from_data();
8831 // final adjustments
8832 for (i = 0; i < hg_fp_cnt; i++) {
8833 if (hg_fp[i].eax_pass && (hg_fp[i].regmask_dep & mxAX))
8834 hg_fp[i].has_ret = 1;
8837 // note: messes up .proto ptr, don't use
8838 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
8841 for (i = 0; i < hg_var_cnt; i++) {
8844 if (var->pp != NULL)
8847 else if (var->is_c_str)
8848 fprintf(fout, "extern %-8s %s[];", "char", var->name);
8850 fprintf(fout, "extern %-8s %s;",
8851 lmod_c_names[var->lmod], var->name);
8854 fprintf(fout, " // seeded");
8855 fprintf(fout, "\n");
8858 fprintf(fout, "\n");
8860 // output function prototypes
8861 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
8864 fprintf(fout, "\n// - seed -\n");
8867 while (fgets(line, sizeof(line), g_fhdr))
8868 fwrite(line, 1, strlen(line), fout);
8871 // '=' needs special treatment
8873 static char *next_word_s(char *w, size_t wsize, char *s)
8880 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
8882 for (i = 1; i < wsize - 1; i++) {
8884 printf("warning: missing closing quote: \"%s\"\n", s);
8893 for (; i < wsize - 1; i++) {
8894 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
8900 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
8901 printf("warning: '%s' truncated\n", w);
8906 static int cmpstringp(const void *p1, const void *p2)
8908 return strcmp(*(char * const *)p1, *(char * const *)p2);
8911 static int is_xref_needed(char *p, char **rlist, int rlist_len)
8916 if (strstr(p, "..."))
8917 // unable to determine, assume needed
8920 if (*p == '.') // .text, .data, ...
8921 // ref from other data or non-function -> no
8924 p2 = strpbrk(p, "+:\r\n\x18");
8927 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8928 // referenced from removed code
8934 static int ida_xrefs_show_need(FILE *fasm, char *p,
8935 char **rlist, int rlist_len)
8941 p = strrchr(p, ';');
8942 if (p != NULL && *p == ';') {
8943 if (IS_START(p + 2, "sctref"))
8945 if (IS_START(p + 2, "DATA XREF: ")) {
8947 if (is_xref_needed(p, rlist, rlist_len))
8955 if (!my_fgets(line, sizeof(line), fasm))
8957 // non-first line is always indented
8958 if (!my_isblank(line[0]))
8961 // should be no content, just comment
8966 p = strrchr(p, ';');
8969 if (IS_START(p, "sctref")) {
8974 // it's printed once, but no harm to check again
8975 if (IS_START(p, "DATA XREF: "))
8978 if (is_xref_needed(p, rlist, rlist_len)) {
8983 fseek(fasm, pos, SEEK_SET);
8987 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
8989 struct scanned_var *var;
8990 char line[256] = { 0, };
8999 // skip to next data section
9000 while (my_fgets(line, sizeof(line), fasm))
9005 if (*p == 0 || *p == ';')
9008 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
9009 if (*p == 0 || *p == ';')
9012 if (*p != 's' || !IS_START(p, "segment para public"))
9018 if (p == NULL || !IS_START(p, "segment para public"))
9022 if (!IS_START(p, "'DATA'"))
9026 while (my_fgets(line, sizeof(line), fasm))
9031 no_identifier = my_isblank(*p);
9034 if (*p == 0 || *p == ';')
9037 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9038 words[wordc][0] = 0;
9039 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9040 if (*p == 0 || *p == ';') {
9046 if (wordc == 2 && IS(words[1], "ends"))
9051 if (no_identifier) {
9052 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
9053 hg_ref_add(words[2]);
9057 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
9058 // when this starts, we don't need anything from this section
9062 // check refs comment(s)
9063 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
9066 if ((hg_var_cnt & 0xff) == 0) {
9067 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
9068 * (hg_var_cnt + 0x100));
9069 my_assert_not(hg_vars, NULL);
9070 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
9073 var = &hg_vars[hg_var_cnt++];
9074 snprintf(var->name, sizeof(var->name), "%s", words[0]);
9076 // maybe already in seed header?
9077 var->pp = proto_parse(g_fhdr, var->name, 1);
9078 if (var->pp != NULL) {
9079 if (var->pp->is_fptr) {
9080 var->lmod = OPLM_DWORD;
9083 else if (var->pp->is_func)
9085 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
9086 aerr("unhandled C type '%s' for '%s'\n",
9087 var->pp->type.name, var->name);
9093 if (IS(words[1], "dd")) {
9094 var->lmod = OPLM_DWORD;
9095 if (wordc >= 4 && IS(words[2], "offset"))
9096 hg_ref_add(words[3]);
9098 else if (IS(words[1], "dw"))
9099 var->lmod = OPLM_WORD;
9100 else if (IS(words[1], "db")) {
9101 var->lmod = OPLM_BYTE;
9102 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
9103 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
9107 else if (IS(words[1], "dq"))
9108 var->lmod = OPLM_QWORD;
9109 //else if (IS(words[1], "dt"))
9111 aerr("type '%s' not known\n", words[1]);
9119 static void set_label(int i, const char *name)
9125 p = strchr(name, ':');
9129 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
9130 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
9131 g_labels[i] = realloc(g_labels[i], len + 1);
9132 my_assert_not(g_labels[i], NULL);
9133 memcpy(g_labels[i], name, len);
9134 g_labels[i][len] = 0;
9143 static struct chunk_item *func_chunks;
9144 static int func_chunk_cnt;
9145 static int func_chunk_alloc;
9147 static void add_func_chunk(FILE *fasm, const char *name, int line)
9149 if (func_chunk_cnt >= func_chunk_alloc) {
9150 func_chunk_alloc *= 2;
9151 func_chunks = realloc(func_chunks,
9152 func_chunk_alloc * sizeof(func_chunks[0]));
9153 my_assert_not(func_chunks, NULL);
9155 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
9156 func_chunks[func_chunk_cnt].name = strdup(name);
9157 func_chunks[func_chunk_cnt].asmln = line;
9161 static int cmp_chunks(const void *p1, const void *p2)
9163 const struct chunk_item *c1 = p1, *c2 = p2;
9164 return strcmp(c1->name, c2->name);
9167 static void scan_ahead_for_chunks(FILE *fasm)
9177 oldpos = ftell(fasm);
9180 while (my_fgets(line, sizeof(line), fasm))
9191 // get rid of random tabs
9192 for (i = 0; line[i] != 0; i++)
9193 if (line[i] == '\t')
9196 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9199 next_word(words[0], sizeof(words[0]), p);
9200 if (words[0][0] == 0)
9201 aerr("missing name for func chunk?\n");
9203 add_func_chunk(fasm, words[0], asmln);
9205 else if (IS_START(p, "; sctend"))
9211 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9212 words[wordc][0] = 0;
9213 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9214 if (*p == 0 || *p == ';') {
9220 if (wordc == 2 && IS(words[1], "ends"))
9224 fseek(fasm, oldpos, SEEK_SET);
9228 int main(int argc, char *argv[])
9230 FILE *fout, *fasm, *frlist;
9231 struct parsed_data *pd = NULL;
9233 char **rlist = NULL;
9235 int rlist_alloc = 0;
9236 int func_chunks_used = 0;
9237 int func_chunks_sorted = 0;
9238 int func_chunk_i = -1;
9239 long func_chunk_ret = 0;
9240 int func_chunk_ret_ln = 0;
9241 int scanned_ahead = 0;
9243 char words[20][256];
9244 enum opr_lenmod lmod;
9245 char *sctproto = NULL;
9247 int pending_endp = 0;
9249 int skip_code_end = 0;
9250 int skip_warned = 0;
9263 for (arg = 1; arg < argc; arg++) {
9264 if (IS(argv[arg], "-v"))
9266 else if (IS(argv[arg], "-rf"))
9267 g_allow_regfunc = 1;
9268 else if (IS(argv[arg], "-uc"))
9269 g_allow_user_icall = 1;
9270 else if (IS(argv[arg], "-m"))
9272 else if (IS(argv[arg], "-hdr"))
9273 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
9278 if (argc < arg + 3) {
9279 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
9280 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
9282 " -hdr - header generation mode\n"
9283 " -rf - allow unannotated indirect calls\n"
9284 " -uc - allow ind. calls/refs to __usercall\n"
9285 " -m - allow multiple .text sections\n"
9286 "[rlist] is a file with function names to skip,"
9294 asmfn = argv[arg++];
9295 fasm = fopen(asmfn, "r");
9296 my_assert_not(fasm, NULL);
9298 hdrfn = argv[arg++];
9299 g_fhdr = fopen(hdrfn, "r");
9300 my_assert_not(g_fhdr, NULL);
9303 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
9304 my_assert_not(rlist, NULL);
9305 // needs special handling..
9306 rlist[rlist_len++] = "__alloca_probe";
9308 func_chunk_alloc = 32;
9309 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
9310 my_assert_not(func_chunks, NULL);
9312 memset(words, 0, sizeof(words));
9314 for (; arg < argc; arg++) {
9317 frlist = fopen(argv[arg], "r");
9318 my_assert_not(frlist, NULL);
9320 while (my_fgets(line, sizeof(line), frlist)) {
9322 if (*p == 0 || *p == ';')
9325 if (IS_START(p, "#if 0")
9326 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
9330 else if (IS_START(p, "#endif"))
9337 p = next_word(words[0], sizeof(words[0]), p);
9338 if (words[0][0] == 0)
9341 if (rlist_len >= rlist_alloc) {
9342 rlist_alloc = rlist_alloc * 2 + 64;
9343 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
9344 my_assert_not(rlist, NULL);
9346 rlist[rlist_len++] = strdup(words[0]);
9354 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
9356 fout = fopen(argv[arg_out], "w");
9357 my_assert_not(fout, NULL);
9360 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
9361 my_assert_not(g_eqs, NULL);
9363 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
9364 g_label_refs[i].i = -1;
9365 g_label_refs[i].next = NULL;
9369 scan_variables(fasm, rlist, rlist_len);
9371 while (my_fgets(line, sizeof(line), fasm))
9380 // get rid of random tabs
9381 for (i = 0; line[i] != 0; i++)
9382 if (line[i] == '\t')
9387 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
9388 goto do_pending_endp; // eww..
9390 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
9392 static const char *attrs[] = {
9401 // parse IDA's attribute-list comment
9402 g_ida_func_attr = 0;
9405 for (; *p != 0; p = sskip(p)) {
9406 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9407 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9408 g_ida_func_attr |= 1 << i;
9409 p += strlen(attrs[i]);
9413 if (i == ARRAY_SIZE(attrs)) {
9414 anote("unparsed IDA attr: %s\n", p);
9417 if (IS(attrs[i], "fpd=")) {
9418 p = next_word(words[0], sizeof(words[0]), p);
9423 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
9425 static const char *attrs[] = {
9432 // parse manual attribute-list comment
9433 g_sct_func_attr = 0;
9436 for (; *p != 0; p = sskip(p)) {
9437 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9438 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9439 g_sct_func_attr |= 1 << i;
9440 p += strlen(attrs[i]);
9447 // clear_sf=start,len (in dwords)
9448 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
9449 &g_stack_clear_len, &j);
9451 // clear_regmask=<mask>
9452 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
9454 // rm_regmask=<mask>
9455 ret = sscanf(p, "=%x%n", &g_regmask_rm, &j) + 1;
9457 anote("unparsed attr value: %s\n", p);
9462 else if (i == ARRAY_SIZE(attrs)) {
9463 anote("unparsed sct attr: %s\n", p);
9468 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9471 next_word(words[0], sizeof(words[0]), p);
9472 if (words[0][0] == 0)
9473 aerr("missing name for func chunk?\n");
9475 if (!scanned_ahead) {
9476 add_func_chunk(fasm, words[0], asmln);
9477 func_chunks_sorted = 0;
9480 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
9482 if (func_chunk_i >= 0) {
9483 if (func_chunk_i < func_chunk_cnt
9484 && IS(func_chunks[func_chunk_i].name, g_func))
9486 // move on to next chunk
9487 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9489 aerr("seek failed for '%s' chunk #%d\n",
9490 g_func, func_chunk_i);
9491 asmln = func_chunks[func_chunk_i].asmln;
9495 if (func_chunk_ret == 0)
9496 aerr("no return from chunk?\n");
9497 fseek(fasm, func_chunk_ret, SEEK_SET);
9498 asmln = func_chunk_ret_ln;
9504 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
9505 func_chunks_used = 1;
9507 if (IS_START(g_func, "sub_")) {
9508 unsigned long addr = strtoul(p, NULL, 16);
9509 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
9510 if (addr > f_addr && !scanned_ahead) {
9511 //anote("scan_ahead caused by '%s', addr %lx\n",
9513 scan_ahead_for_chunks(fasm);
9515 func_chunks_sorted = 0;
9523 for (i = wordc; i < ARRAY_SIZE(words); i++)
9525 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9526 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9527 if (*p == 0 || *p == ';') {
9532 if (*p != 0 && *p != ';')
9533 aerr("too many words\n");
9535 if (skip_code_end) {
9540 // allow asm patches in comments
9542 // skip IDA's forced non-removable comment
9543 if (!IS_START(p, "; sct") && (p2 = strchr(p + 1, ';')))
9546 if (*p == ';' && IS_START(p, "; sct")) {
9547 if (IS_START(p, "; sctpatch:")) {
9549 if (*p == 0 || *p == ';')
9551 goto parse_words; // lame
9553 if (IS_START(p, "; sctproto:")) {
9554 sctproto = strdup(p + 11);
9556 else if (IS_START(p, "; sctend")) {
9561 else if (IS_START(p, "; sctskip_start")) {
9562 if (in_func && !g_skip_func) {
9564 ops[pi].op = OPP_ABORT;
9565 ops[pi].asmln = asmln;
9571 else if (IS_START(p, "; sctskip_end")) {
9579 awarn("wordc == 0?\n");
9583 // don't care about this:
9584 if (words[0][0] == '.'
9585 || IS(words[0], "include")
9586 || IS(words[0], "assume") || IS(words[1], "segment")
9587 || IS(words[0], "align"))
9593 // do delayed endp processing to collect switch jumptables
9595 if (in_func && !g_skip_func && !end && wordc >= 2
9596 && ((words[0][0] == 'd' && words[0][2] == 0)
9597 || (words[1][0] == 'd' && words[1][2] == 0)))
9600 if (words[1][0] == 'd' && words[1][2] == 0) {
9602 if (g_func_pd_cnt >= pd_alloc) {
9603 pd_alloc = pd_alloc * 2 + 16;
9604 g_func_pd = realloc(g_func_pd,
9605 sizeof(g_func_pd[0]) * pd_alloc);
9606 my_assert_not(g_func_pd, NULL);
9608 pd = &g_func_pd[g_func_pd_cnt];
9610 memset(pd, 0, sizeof(*pd));
9611 strcpy(pd->label, words[0]);
9612 pd->type = OPT_CONST;
9613 pd->lmod = lmod_from_directive(words[1]);
9619 anote("skipping alignment byte?\n");
9622 lmod = lmod_from_directive(words[0]);
9623 if (lmod != pd->lmod)
9624 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
9627 if (pd->count_alloc < pd->count + wordc) {
9628 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
9629 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
9630 my_assert_not(pd->d, NULL);
9632 for (; i < wordc; i++) {
9633 if (IS(words[i], "offset")) {
9634 pd->type = OPT_OFFSET;
9637 p = strchr(words[i], ',');
9640 if (pd->type == OPT_OFFSET)
9641 pd->d[pd->count].u.label = strdup(words[i]);
9643 pd->d[pd->count].u.val = parse_number(words[i], 0);
9644 pd->d[pd->count].bt_i = -1;
9650 if (in_func && !g_skip_func) {
9652 gen_hdr(g_func, pi);
9654 gen_func(fout, g_fhdr, g_func, pi);
9659 g_ida_func_attr = 0;
9660 g_sct_func_attr = 0;
9661 g_stack_clear_start = 0;
9662 g_stack_clear_len = 0;
9669 func_chunks_used = 0;
9672 memset(&ops, 0, pi * sizeof(ops[0]));
9677 for (i = 0; i < g_func_pd_cnt; i++) {
9679 if (pd->type == OPT_OFFSET) {
9680 for (j = 0; j < pd->count; j++)
9681 free(pd->d[j].u.label);
9696 if (IS(words[1], "proc")) {
9698 aerr("proc '%s' while in_func '%s'?\n",
9701 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9703 strcpy(g_func, words[0]);
9704 set_label(0, words[0]);
9709 if (IS(words[1], "endp"))
9712 aerr("endp '%s' while not in_func?\n", words[0]);
9713 if (!IS(g_func, words[0]))
9714 aerr("endp '%s' while in_func '%s'?\n",
9717 aerr("endp '%s' while skipping code\n", words[0]);
9719 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
9720 && ops[0].op == OP_JMP && ops[0].operand[0].segment)
9726 if (!g_skip_func && func_chunks_used) {
9727 // start processing chunks
9728 struct chunk_item *ci, key = { g_func, 0 };
9730 func_chunk_ret = ftell(fasm);
9731 func_chunk_ret_ln = asmln;
9732 if (!func_chunks_sorted) {
9733 qsort(func_chunks, func_chunk_cnt,
9734 sizeof(func_chunks[0]), cmp_chunks);
9735 func_chunks_sorted = 1;
9737 ci = bsearch(&key, func_chunks, func_chunk_cnt,
9738 sizeof(func_chunks[0]), cmp_chunks);
9740 aerr("'%s' needs chunks, but none found\n", g_func);
9741 func_chunk_i = ci - func_chunks;
9742 for (; func_chunk_i > 0; func_chunk_i--)
9743 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
9746 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9748 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
9749 asmln = func_chunks[func_chunk_i].asmln;
9757 if (wordc == 2 && IS(words[1], "ends")) {
9761 goto do_pending_endp;
9765 // scan for next text segment
9766 while (my_fgets(line, sizeof(line), fasm)) {
9769 if (*p == 0 || *p == ';')
9772 if (strstr(p, "segment para public 'CODE' use32"))
9779 p = strchr(words[0], ':');
9781 set_label(pi, words[0]);
9785 if (!in_func || g_skip_func || skip_code) {
9786 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
9788 anote("skipping from '%s'\n", g_labels[pi]);
9792 g_labels[pi] = NULL;
9796 if (wordc > 1 && IS(words[1], "="))
9799 aerr("unhandled equ, wc=%d\n", wordc);
9800 if (g_eqcnt >= eq_alloc) {
9802 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
9803 my_assert_not(g_eqs, NULL);
9806 len = strlen(words[0]);
9807 if (len > sizeof(g_eqs[0].name) - 1)
9808 aerr("equ name too long: %d\n", len);
9809 strcpy(g_eqs[g_eqcnt].name, words[0]);
9811 if (!IS(words[3], "ptr"))
9812 aerr("unhandled equ\n");
9813 if (IS(words[2], "dword"))
9814 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
9815 else if (IS(words[2], "word"))
9816 g_eqs[g_eqcnt].lmod = OPLM_WORD;
9817 else if (IS(words[2], "byte"))
9818 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
9819 else if (IS(words[2], "qword"))
9820 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
9822 aerr("bad lmod: '%s'\n", words[2]);
9824 g_eqs[g_eqcnt].offset = parse_number(words[4], 0);
9829 if (pi >= ARRAY_SIZE(ops))
9830 aerr("too many ops\n");
9832 parse_op(&ops[pi], words, wordc);
9834 ops[pi].datap = sctproto;
9849 // vim:ts=2:shiftwidth=2:expandtab