5 * This work is licensed under the terms of 3-clause BSD license.
6 * See COPYING file in the top-level directory.
14 #include "my_assert.h"
18 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
19 #define IS(w, y) !strcmp(w, y)
20 #define IS_START(w, y) !strncmp(w, y, strlen(y))
22 #include "protoparse.h"
24 static const char *asmfn;
28 #define anote(fmt, ...) \
29 printf("%s:%d: note: " fmt, asmfn, asmln, ##__VA_ARGS__)
30 #define awarn(fmt, ...) \
31 printf("%s:%d: warning: " fmt, asmfn, asmln, ##__VA_ARGS__)
32 #define aerr(fmt, ...) do { \
33 printf("%s:%d: error: " fmt, asmfn, asmln, ##__VA_ARGS__); \
38 #include "masm_tools.h"
41 OPF_RMD = (1 << 0), /* removed from code generation */
42 OPF_DATA = (1 << 1), /* data processing - writes to dst opr */
43 OPF_FLAGS = (1 << 2), /* sets flags */
44 OPF_JMP = (1 << 3), /* branch, call */
45 OPF_CJMP = (1 << 4), /* cond. branch (cc or jecxz/loop) */
46 OPF_CC = (1 << 5), /* uses flags */
47 OPF_TAIL = (1 << 6), /* ret or tail call */
48 OPF_RSAVE = (1 << 7), /* push/pop is local reg save/load */
49 OPF_REP = (1 << 8), /* prefixed by rep */
50 OPF_REPZ = (1 << 9), /* rep is repe/repz */
51 OPF_REPNZ = (1 << 10), /* rep is repne/repnz */
52 OPF_FARG = (1 << 11), /* push collected as func arg */
53 OPF_FARGNR = (1 << 12), /* push collected as func arg (no reuse) */
54 OPF_EBP_S = (1 << 13), /* ebp used as scratch here, not BP */
55 OPF_DF = (1 << 14), /* DF flag set */
56 OPF_ATAIL = (1 << 15), /* tail call with reused arg frame */
57 OPF_32BIT = (1 << 16), /* 32bit division */
58 OPF_LOCK = (1 << 17), /* op has lock prefix */
59 OPF_VAPUSH = (1 << 18), /* vararg ptr push (as call arg) */
60 OPF_DONE = (1 << 19), /* already fully handled by analysis */
61 OPF_PPUSH = (1 << 20), /* part of complex push-pop graph */
62 OPF_NOREGS = (1 << 21), /* don't track regs of this op */
63 OPF_FPUSH = (1 << 22), /* pushes x87 stack */
64 OPF_FPOP = (1 << 23), /* pops x87 stack */
65 OPF_FSHIFT = (1 << 24), /* x87 stack shift is actually needed */
141 // pseudo-ops for lib calls
156 // must be sorted (larger len must be further in enum)
165 #define MAX_EXITS 128
167 #define MAX_OPERANDS 3
170 #define OPR_INIT(type_, lmod_, reg_) \
171 { type_, lmod_, reg_, }
175 enum opr_lenmod lmod;
177 unsigned int is_ptr:1; // pointer in C
178 unsigned int is_array:1; // array in C
179 unsigned int type_from_var:1; // .. in header, sometimes wrong
180 unsigned int size_mismatch:1; // type override differs from C
181 unsigned int size_lt:1; // type override is larger than C
182 unsigned int had_ds:1; // had ds: prefix
183 const struct parsed_proto *pp; // for OPT_LABEL
190 struct parsed_opr operand[MAX_OPERANDS];
193 unsigned char pfo_inv;
194 unsigned char operand_cnt;
195 unsigned char p_argnum; // arg push: altered before call arg #
196 unsigned char p_arggrp; // arg push: arg group # for above
197 unsigned char p_argpass;// arg push: arg of host func
198 short p_argnext;// arg push: same arg pushed elsewhere or -1
199 int regmask_src; // all referensed regs
201 int pfomask; // flagop: parsed_flag_op that can't be delayed
202 int cc_scratch; // scratch storage during analysis
203 int bt_i; // branch target for branches
204 struct parsed_data *btj;// branch targets for jumptables
205 struct parsed_proto *pp;// parsed_proto for OP_CALL
211 // OP_CALL - parser proto hint (str)
212 // (OPF_CC) - points to one of (OPF_FLAGS) that affects cc op
213 // OP_PUSH - points to OP_POP in complex push/pop graph
214 // OP_POP - points to OP_PUSH in simple push/pop pair
218 enum opr_lenmod lmod;
225 enum opr_lenmod lmod;
239 struct label_ref *next;
243 IDAFA_BP_FRAME = (1 << 0),
244 IDAFA_LIB_FUNC = (1 << 1),
245 IDAFA_STATIC = (1 << 2),
246 IDAFA_NORETURN = (1 << 3),
247 IDAFA_THUNK = (1 << 4),
248 IDAFA_FPD = (1 << 5),
261 // note: limited to 32k due to p_argnext
263 #define MAX_ARG_GRP 2
265 static struct parsed_op ops[MAX_OPS];
266 static struct parsed_equ *g_eqs;
268 static char *g_labels[MAX_OPS];
269 static struct label_ref g_label_refs[MAX_OPS];
270 static const struct parsed_proto *g_func_pp;
271 static struct parsed_data *g_func_pd;
272 static int g_func_pd_cnt;
273 static int g_func_lmods;
274 static char g_func[256];
275 static char g_comment[256];
276 static int g_bp_frame;
277 static int g_sp_frame;
278 static int g_stack_frame_used;
279 static int g_stack_fsz;
280 static int g_ida_func_attr;
281 static int g_skip_func;
282 static int g_allow_regfunc;
283 static int g_quiet_pp;
284 static int g_header_mode;
286 #define ferr(op_, fmt, ...) do { \
287 printf("%s:%d: error %u: [%s] '%s': " fmt, asmfn, (op_)->asmln, \
288 __LINE__, g_func, dump_op(op_), ##__VA_ARGS__); \
292 #define fnote(op_, fmt, ...) \
293 printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
294 dump_op(op_), ##__VA_ARGS__)
296 #define ferr_assert(op_, cond) do { \
297 if (!(cond)) ferr(op_, "assertion '%s' failed\n", #cond); \
300 const char *regs_r32[] = {
301 "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
302 // not r32, but list here for easy parsing and printing
303 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
304 "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"
306 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
307 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
308 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
314 xMM0, xMM1, xMM2, xMM3, // mmx
315 xMM4, xMM5, xMM6, xMM7,
316 xST0, xST1, xST2, xST3, // x87
317 xST4, xST5, xST6, xST7,
320 #define mxAX (1 << xAX)
321 #define mxDX (1 << xDX)
322 #define mxST0 (1 << xST0)
323 #define mxST1 (1 << xST1)
325 // possible basic comparison types (without inversion)
326 enum parsed_flag_op {
330 PFO_BE, // 6 CF=1||ZF=1
334 PFO_LE, // e ZF=1||SF!=OF
337 #define PFOB_O (1 << PFO_O)
338 #define PFOB_C (1 << PFO_C)
339 #define PFOB_Z (1 << PFO_Z)
340 #define PFOB_S (1 << PFO_S)
342 static const char *parsed_flag_op_names[] = {
343 "o", "c", "z", "be", "s", "p", "l", "le"
346 static int char_array_i(const char *array[], size_t len, const char *s)
350 for (i = 0; i < len; i++)
357 static void printf_number(char *buf, size_t buf_size,
358 unsigned long number)
360 // output in C-friendly form
361 snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
364 static int check_segment_prefix(const char *s)
366 if (s[0] == 0 || s[1] != 's' || s[2] != ':')
380 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
384 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
386 *reg_lmod = OPLM_QWORD;
390 *reg_lmod = OPLM_DWORD;
393 reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
395 *reg_lmod = OPLM_WORD;
398 reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
400 *reg_lmod = OPLM_BYTE;
403 reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
405 *reg_lmod = OPLM_BYTE;
412 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
414 enum opr_lenmod lmod;
427 while (my_isblank(*s))
429 for (; my_issep(*s); d++, s++)
431 while (my_isblank(*s))
435 // skip '?s:' prefixes
436 if (check_segment_prefix(s))
439 s = next_idt(w, sizeof(w), s);
444 reg = parse_reg(&lmod, w);
446 *regmask |= 1 << reg;
450 if ('0' <= w[0] && w[0] <= '9') {
451 number = parse_number(w);
452 printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
456 // probably some label/identifier - pass
459 snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
463 strcpy(name, cvtbuf);
468 static int is_reg_in_str(const char *s)
472 if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
475 for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
476 if (!strncmp(s, regs_r32[i], 3))
482 static const char *parse_stack_el(const char *name, char *extra_reg,
485 const char *p, *p2, *s;
491 if (g_bp_frame || early_try)
494 if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
496 if (extra_reg != NULL) {
497 strncpy(extra_reg, name, 3);
502 if (IS_START(p, "ebp+")) {
506 if (p2 != NULL && is_reg_in_str(p)) {
507 if (extra_reg != NULL) {
508 strncpy(extra_reg, p, p2 - p);
509 extra_reg[p2 - p] = 0;
514 if (!('0' <= *p && *p <= '9'))
521 if (!IS_START(name, "esp+"))
527 if (is_reg_in_str(s)) {
528 if (extra_reg != NULL) {
529 strncpy(extra_reg, s, p - s);
530 extra_reg[p - s] = 0;
535 aerr("%s IDA stackvar not set?\n", __func__);
537 if (!('0' <= *s && *s <= '9')) {
538 aerr("%s IDA stackvar offset not set?\n", __func__);
541 if (s[0] == '0' && s[1] == 'x')
544 if (len < sizeof(buf) - 1) {
545 strncpy(buf, s, len);
547 val = strtol(buf, &endp, 16);
548 if (val == 0 || *endp != 0) {
549 aerr("%s num parse fail for '%s'\n", __func__, buf);
558 if ('0' <= *p && *p <= '9')
564 static int guess_lmod_from_name(struct parsed_opr *opr)
566 if (IS_START(opr->name, "dword_") || IS_START(opr->name, "off_")) {
567 opr->lmod = OPLM_DWORD;
570 if (IS_START(opr->name, "word_")) {
571 opr->lmod = OPLM_WORD;
574 if (IS_START(opr->name, "byte_")) {
575 opr->lmod = OPLM_BYTE;
578 if (IS_START(opr->name, "qword_")) {
579 opr->lmod = OPLM_QWORD;
585 static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
586 const struct parsed_type *c_type)
588 static const char *dword_types[] = {
589 "uint32_t", "int", "_DWORD", "UINT_PTR", "DWORD",
590 "WPARAM", "LPARAM", "UINT", "__int32",
591 "LONG", "HIMC", "BOOL", "size_t",
594 static const char *word_types[] = {
595 "uint16_t", "int16_t", "_WORD", "WORD",
596 "unsigned __int16", "__int16",
598 static const char *byte_types[] = {
599 "uint8_t", "int8_t", "char",
600 "unsigned __int8", "__int8", "BYTE", "_BYTE",
602 // structures.. deal the same as with _UNKNOWN for now
608 if (c_type->is_ptr) {
613 n = skip_type_mod(c_type->name);
615 for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
616 if (IS(n, dword_types[i])) {
622 for (i = 0; i < ARRAY_SIZE(word_types); i++) {
623 if (IS(n, word_types[i])) {
629 for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
630 if (IS(n, byte_types[i])) {
639 static char *default_cast_to(char *buf, size_t buf_size,
640 struct parsed_opr *opr)
646 if (opr->pp == NULL || opr->pp->type.name == NULL
649 snprintf(buf, buf_size, "%s", "(void *)");
653 snprintf(buf, buf_size, "(%s)", opr->pp->type.name);
657 static enum opr_type lmod_from_directive(const char *d)
661 else if (IS(d, "dw"))
663 else if (IS(d, "db"))
666 aerr("unhandled directive: '%s'\n", d);
670 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
676 *regmask |= 1 << reg;
679 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
682 static int parse_operand(struct parsed_opr *opr,
683 int *regmask, int *regmask_indirect,
684 char words[16][256], int wordc, int w, unsigned int op_flags)
686 const struct parsed_proto *pp = NULL;
687 enum opr_lenmod tmplmod;
688 unsigned long number;
696 aerr("parse_operand w %d, wordc %d\n", w, wordc);
700 for (i = w; i < wordc; i++) {
701 len = strlen(words[i]);
702 if (words[i][len - 1] == ',') {
703 words[i][len - 1] = 0;
709 wordc_in = wordc - w;
711 if ((op_flags & OPF_JMP) && wordc_in > 0
712 && !('0' <= words[w][0] && words[w][0] <= '9'))
714 const char *label = NULL;
716 if (wordc_in == 3 && !strncmp(words[w], "near", 4)
717 && IS(words[w + 1], "ptr"))
718 label = words[w + 2];
719 else if (wordc_in == 2 && IS(words[w], "short"))
720 label = words[w + 1];
721 else if (wordc_in == 1
722 && strchr(words[w], '[') == NULL
723 && parse_reg(&tmplmod, words[w]) < 0)
727 opr->type = OPT_LABEL;
728 ret = check_segment_prefix(label);
731 aerr("fs/gs used\n");
735 strcpy(opr->name, label);
741 if (IS(words[w + 1], "ptr")) {
742 if (IS(words[w], "dword"))
743 opr->lmod = OPLM_DWORD;
744 else if (IS(words[w], "word"))
745 opr->lmod = OPLM_WORD;
746 else if (IS(words[w], "byte"))
747 opr->lmod = OPLM_BYTE;
748 else if (IS(words[w], "qword"))
749 opr->lmod = OPLM_QWORD;
751 aerr("type parsing failed\n");
753 wordc_in = wordc - w;
758 if (IS(words[w], "offset")) {
759 opr->type = OPT_OFFSET;
760 opr->lmod = OPLM_DWORD;
761 strcpy(opr->name, words[w + 1]);
762 pp = proto_parse(g_fhdr, opr->name, 1);
765 if (IS(words[w], "(offset")) {
766 p = strchr(words[w + 1], ')');
768 aerr("parse of bracketed offset failed\n");
770 opr->type = OPT_OFFSET;
771 strcpy(opr->name, words[w + 1]);
777 aerr("parse_operand 1 word expected\n");
779 ret = check_segment_prefix(words[w]);
782 aerr("fs/gs used\n");
784 memmove(words[w], words[w] + 3, strlen(words[w]) - 2);
786 strcpy(opr->name, words[w]);
788 if (words[w][0] == '[') {
789 opr->type = OPT_REGMEM;
790 ret = sscanf(words[w], "[%[^]]]", opr->name);
792 aerr("[] parse failure\n");
794 parse_indmode(opr->name, regmask_indirect, 1);
795 if (opr->lmod == OPLM_UNSPEC && parse_stack_el(opr->name, NULL, 1))
798 struct parsed_equ *eq =
799 equ_find(NULL, parse_stack_el(opr->name, NULL, 1), &i);
801 opr->lmod = eq->lmod;
803 // might be unaligned access
804 g_func_lmods |= 1 << OPLM_BYTE;
808 else if (strchr(words[w], '[')) {
810 p = strchr(words[w], '[');
811 opr->type = OPT_REGMEM;
812 parse_indmode(p, regmask_indirect, 0);
813 strncpy(buf, words[w], p - words[w]);
814 buf[p - words[w]] = 0;
815 pp = proto_parse(g_fhdr, buf, 1);
818 else if (('0' <= words[w][0] && words[w][0] <= '9')
819 || words[w][0] == '-')
821 number = parse_number(words[w]);
822 opr->type = OPT_CONST;
824 printf_number(opr->name, sizeof(opr->name), number);
828 ret = parse_reg(&tmplmod, opr->name);
830 setup_reg_opr(opr, ret, tmplmod, regmask);
834 // most likely var in data segment
835 opr->type = OPT_LABEL;
836 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
840 if (pp->is_fptr || pp->is_func) {
841 opr->lmod = OPLM_DWORD;
845 tmplmod = OPLM_UNSPEC;
846 if (!guess_lmod_from_c_type(&tmplmod, &pp->type))
847 anote("unhandled C type '%s' for '%s'\n",
848 pp->type.name, opr->name);
850 if (opr->lmod == OPLM_UNSPEC) {
852 opr->type_from_var = 1;
854 else if (opr->lmod != tmplmod) {
855 opr->size_mismatch = 1;
856 if (tmplmod < opr->lmod)
859 opr->is_ptr = pp->type.is_ptr;
861 opr->is_array = pp->type.is_array;
865 if (opr->lmod == OPLM_UNSPEC)
866 guess_lmod_from_name(opr);
870 static const struct {
875 { "repe", OPF_REP|OPF_REPZ },
876 { "repz", OPF_REP|OPF_REPZ },
877 { "repne", OPF_REP|OPF_REPNZ },
878 { "repnz", OPF_REP|OPF_REPNZ },
879 { "lock", OPF_LOCK }, // ignored for now..
882 #define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
884 static const struct {
887 unsigned short minopr;
888 unsigned short maxopr;
891 unsigned char pfo_inv;
893 { "nop", OP_NOP, 0, 0, 0 },
894 { "push", OP_PUSH, 1, 1, 0 },
895 { "pop", OP_POP, 1, 1, OPF_DATA },
896 { "leave",OP_LEAVE, 0, 0, OPF_DATA },
897 { "mov" , OP_MOV, 2, 2, OPF_DATA },
898 { "lea", OP_LEA, 2, 2, OPF_DATA },
899 { "movzx",OP_MOVZX, 2, 2, OPF_DATA },
900 { "movsx",OP_MOVSX, 2, 2, OPF_DATA },
901 { "xchg", OP_XCHG, 2, 2, OPF_DATA },
902 { "not", OP_NOT, 1, 1, OPF_DATA },
903 { "xlat", OP_XLAT, 0, 0, OPF_DATA },
904 { "cdq", OP_CDQ, 0, 0, OPF_DATA },
905 { "lodsb",OP_LODS, 0, 0, OPF_DATA },
906 { "lodsw",OP_LODS, 0, 0, OPF_DATA },
907 { "lodsd",OP_LODS, 0, 0, OPF_DATA },
908 { "stosb",OP_STOS, 0, 0, OPF_DATA },
909 { "stosw",OP_STOS, 0, 0, OPF_DATA },
910 { "stosd",OP_STOS, 0, 0, OPF_DATA },
911 { "movsb",OP_MOVS, 0, 0, OPF_DATA },
912 { "movsw",OP_MOVS, 0, 0, OPF_DATA },
913 { "movsd",OP_MOVS, 0, 0, OPF_DATA },
914 { "cmpsb",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
915 { "cmpsw",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
916 { "cmpsd",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
917 { "scasb",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
918 { "scasw",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
919 { "scasd",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
920 { "std", OP_STD, 0, 0, OPF_DATA }, // special flag
921 { "cld", OP_CLD, 0, 0, OPF_DATA },
922 { "add", OP_ADD, 2, 2, OPF_DATA|OPF_FLAGS },
923 { "sub", OP_SUB, 2, 2, OPF_DATA|OPF_FLAGS },
924 { "and", OP_AND, 2, 2, OPF_DATA|OPF_FLAGS },
925 { "or", OP_OR, 2, 2, OPF_DATA|OPF_FLAGS },
926 { "xor", OP_XOR, 2, 2, OPF_DATA|OPF_FLAGS },
927 { "shl", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
928 { "shr", OP_SHR, 2, 2, OPF_DATA|OPF_FLAGS },
929 { "sal", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
930 { "sar", OP_SAR, 2, 2, OPF_DATA|OPF_FLAGS },
931 { "shld", OP_SHLD, 3, 3, OPF_DATA|OPF_FLAGS },
932 { "shrd", OP_SHRD, 3, 3, OPF_DATA|OPF_FLAGS },
933 { "rol", OP_ROL, 2, 2, OPF_DATA|OPF_FLAGS },
934 { "ror", OP_ROR, 2, 2, OPF_DATA|OPF_FLAGS },
935 { "rcl", OP_RCL, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
936 { "rcr", OP_RCR, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
937 { "adc", OP_ADC, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
938 { "sbb", OP_SBB, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
939 { "bsf", OP_BSF, 2, 2, OPF_DATA|OPF_FLAGS },
940 { "inc", OP_INC, 1, 1, OPF_DATA|OPF_FLAGS },
941 { "dec", OP_DEC, 1, 1, OPF_DATA|OPF_FLAGS },
942 { "neg", OP_NEG, 1, 1, OPF_DATA|OPF_FLAGS },
943 { "mul", OP_MUL, 1, 1, OPF_DATA|OPF_FLAGS },
944 { "imul", OP_IMUL, 1, 3, OPF_DATA|OPF_FLAGS },
945 { "div", OP_DIV, 1, 1, OPF_DATA|OPF_FLAGS },
946 { "idiv", OP_IDIV, 1, 1, OPF_DATA|OPF_FLAGS },
947 { "test", OP_TEST, 2, 2, OPF_FLAGS },
948 { "cmp", OP_CMP, 2, 2, OPF_FLAGS },
949 { "retn", OP_RET, 0, 1, OPF_TAIL },
950 { "call", OP_CALL, 1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
951 { "jmp", OP_JMP, 1, 1, OPF_JMP },
952 { "jecxz",OP_JECXZ, 1, 1, OPF_JMP|OPF_CJMP },
953 { "loop", OP_LOOP, 1, 1, OPF_JMP|OPF_CJMP|OPF_DATA },
954 { "jo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 0 }, // 70 OF=1
955 { "jno", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 1 }, // 71 OF=0
956 { "jc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72 CF=1
957 { "jb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72
958 { "jnc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73 CF=0
959 { "jnb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
960 { "jae", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
961 { "jz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74 ZF=1
962 { "je", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74
963 { "jnz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75 ZF=0
964 { "jne", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75
965 { "jbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76 CF=1||ZF=1
966 { "jna", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76
967 { "ja", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77 CF=0&&ZF=0
968 { "jnbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77
969 { "js", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 0 }, // 78 SF=1
970 { "jns", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 1 }, // 79 SF=0
971 { "jp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a PF=1
972 { "jpe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a
973 { "jnp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b PF=0
974 { "jpo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b
975 { "jl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c SF!=OF
976 { "jnge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c
977 { "jge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d SF=OF
978 { "jnl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d
979 { "jle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e ZF=1||SF!=OF
980 { "jng", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e
981 { "jg", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f ZF=0&&SF=OF
982 { "jnle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f
983 { "seto", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 0 },
984 { "setno", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 1 },
985 { "setc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
986 { "setb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
987 { "setnc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
988 { "setae", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
989 { "setnb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
990 { "setz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
991 { "sete", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
992 { "setnz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
993 { "setne", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
994 { "setbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
995 { "setna", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
996 { "seta", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
997 { "setnbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
998 { "sets", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 0 },
999 { "setns", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 1 },
1000 { "setp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1001 { "setpe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1002 { "setnp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1003 { "setpo", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1004 { "setl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1005 { "setnge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1006 { "setge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1007 { "setnl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1008 { "setle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1009 { "setng", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1010 { "setg", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1011 { "setnle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1013 { "fld", OP_FLD, 1, 1, OPF_FPUSH },
1014 { "fild", OP_FILD, 1, 1, OPF_FPUSH },
1015 { "fld1", OP_FLDc, 0, 0, OPF_FPUSH },
1016 { "fldz", OP_FLDc, 0, 0, OPF_FPUSH },
1017 { "fstp", OP_FST, 1, 1, OPF_FPOP },
1018 { "fst", OP_FST, 1, 1, 0 },
1019 { "fadd", OP_FADD, 0, 2, 0 },
1020 { "faddp", OP_FADD, 0, 2, OPF_FPOP },
1021 { "fdiv", OP_FDIV, 0, 2, 0 },
1022 { "fdivp", OP_FDIV, 0, 2, OPF_FPOP },
1023 { "fmul", OP_FMUL, 0, 2, 0 },
1024 { "fmulp", OP_FMUL, 0, 2, OPF_FPOP },
1025 { "fsub", OP_FSUB, 0, 2, 0 },
1026 { "fsubp", OP_FSUB, 0, 2, OPF_FPOP },
1027 { "fdivr", OP_FDIVR, 0, 2, 0 },
1028 { "fdivrp", OP_FDIVR, 0, 2, OPF_FPOP },
1029 { "fsubr", OP_FSUBR, 0, 2, 0 },
1030 { "fsubrp", OP_FSUBR, 0, 2, OPF_FPOP },
1031 { "fiadd", OP_FIADD, 1, 1, 0 },
1032 { "fidiv", OP_FIDIV, 1, 1, 0 },
1033 { "fimul", OP_FIMUL, 1, 1, 0 },
1034 { "fisub", OP_FISUB, 1, 1, 0 },
1035 { "fidivr", OP_FIDIVR, 1, 1, 0 },
1036 { "fisubr", OP_FISUBR, 1, 1, 0 },
1038 { "emms", OP_EMMS, 0, 0, OPF_DATA },
1039 { "movq", OP_MOV, 2, 2, OPF_DATA },
1040 // pseudo-ops for lib calls
1041 { "_ftol", OPP_FTOL },
1046 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
1048 enum opr_lenmod lmod = OPLM_UNSPEC;
1049 int prefix_flags = 0;
1057 for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
1058 if (IS(words[w], pref_table[i].name)) {
1059 prefix_flags = pref_table[i].flags;
1066 aerr("lone prefix: '%s'\n", words[0]);
1071 for (i = 0; i < ARRAY_SIZE(op_table); i++) {
1072 if (IS(words[w], op_table[i].name))
1076 if (i == ARRAY_SIZE(op_table)) {
1078 aerr("unhandled op: '%s'\n", words[0]);
1083 op->op = op_table[i].op;
1084 op->flags = op_table[i].flags | prefix_flags;
1085 op->pfo = op_table[i].pfo;
1086 op->pfo_inv = op_table[i].pfo_inv;
1087 op->regmask_src = op->regmask_dst = 0;
1090 if (op->op == OP_UD2)
1093 for (opr = 0; opr < op_table[i].maxopr; opr++) {
1094 if (opr >= op_table[i].minopr && w >= wordc)
1097 regmask = regmask_ind = 0;
1098 w = parse_operand(&op->operand[opr], ®mask, ®mask_ind,
1099 words, wordc, w, op->flags);
1101 if (opr == 0 && (op->flags & OPF_DATA))
1102 op->regmask_dst = regmask;
1104 op->regmask_src |= regmask;
1105 op->regmask_src |= regmask_ind;
1107 if (op->operand[opr].lmod != OPLM_UNSPEC)
1108 g_func_lmods |= 1 << op->operand[opr].lmod;
1112 aerr("parse_op %s incomplete: %d/%d\n",
1113 words[0], w, wordc);
1116 op->operand_cnt = opr;
1117 if (!strncmp(op_table[i].name, "set", 3))
1118 op->operand[0].lmod = OPLM_BYTE;
1121 // first operand is not dst
1124 op->regmask_src |= op->regmask_dst;
1125 op->regmask_dst = 0;
1128 // first operand is src too
1140 op->regmask_src |= op->regmask_dst;
1145 op->regmask_src |= op->regmask_dst;
1146 op->regmask_dst |= op->regmask_src;
1152 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1153 && op->operand[0].lmod == op->operand[1].lmod
1154 && op->operand[0].reg == op->operand[1].reg
1155 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1157 op->regmask_src = 0;
1160 op->regmask_src |= op->regmask_dst;
1163 // ops with implicit argumets
1165 op->operand_cnt = 2;
1166 setup_reg_opr(&op->operand[0], xAX, OPLM_BYTE, &op->regmask_src);
1167 op->regmask_dst = op->regmask_src;
1168 setup_reg_opr(&op->operand[1], xBX, OPLM_DWORD, &op->regmask_src);
1172 op->operand_cnt = 2;
1173 setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
1174 setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
1180 if (words[op_w][4] == 'b')
1182 else if (words[op_w][4] == 'w')
1184 else if (words[op_w][4] == 'd')
1187 op->regmask_src = 0;
1188 setup_reg_opr(&op->operand[j++], op->op == OP_LODS ? xSI : xDI,
1189 OPLM_DWORD, &op->regmask_src);
1190 op->regmask_dst = op->regmask_src;
1191 setup_reg_opr(&op->operand[j++], xAX, lmod,
1192 op->op == OP_LODS ? &op->regmask_dst : &op->regmask_src);
1193 if (op->flags & OPF_REP) {
1194 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1195 op->regmask_dst |= 1 << xCX;
1197 op->operand_cnt = j;
1202 if (words[op_w][4] == 'b')
1204 else if (words[op_w][4] == 'w')
1206 else if (words[op_w][4] == 'd')
1209 op->regmask_src = 0;
1210 // note: lmod is not correct, don't have where to place it
1211 setup_reg_opr(&op->operand[j++], xDI, lmod, &op->regmask_src);
1212 setup_reg_opr(&op->operand[j++], xSI, OPLM_DWORD, &op->regmask_src);
1213 if (op->flags & OPF_REP)
1214 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1215 op->operand_cnt = j;
1216 op->regmask_dst = op->regmask_src;
1220 op->regmask_dst = 1 << xCX;
1223 op->operand_cnt = 2;
1224 op->regmask_src = 1 << xCX;
1225 op->operand[1].type = OPT_REG;
1226 op->operand[1].reg = xCX;
1227 op->operand[1].lmod = OPLM_DWORD;
1231 if (op->operand_cnt == 2) {
1232 if (op->operand[0].type != OPT_REG)
1233 aerr("reg expected\n");
1234 op->regmask_src |= 1 << op->operand[0].reg;
1236 if (op->operand_cnt != 1)
1241 op->regmask_src |= op->regmask_dst;
1242 op->regmask_dst = (1 << xDX) | (1 << xAX);
1243 if (op->operand[0].lmod == OPLM_UNSPEC)
1244 op->operand[0].lmod = OPLM_DWORD;
1249 // we could set up operands for edx:eax, but there is no real need to
1250 // (see is_opr_modified())
1251 op->regmask_src |= op->regmask_dst;
1252 op->regmask_dst = (1 << xDX) | (1 << xAX);
1253 if (op->operand[0].lmod == OPLM_UNSPEC)
1254 op->operand[0].lmod = OPLM_DWORD;
1262 op->regmask_src |= op->regmask_dst;
1263 if (op->operand[1].lmod == OPLM_UNSPEC)
1264 op->operand[1].lmod = OPLM_BYTE;
1269 op->regmask_src |= op->regmask_dst;
1270 if (op->operand[2].lmod == OPLM_UNSPEC)
1271 op->operand[2].lmod = OPLM_BYTE;
1275 op->regmask_src |= op->regmask_dst;
1276 op->regmask_dst = 0;
1277 if (op->operand[0].lmod == OPLM_UNSPEC
1278 && (op->operand[0].type == OPT_CONST
1279 || op->operand[0].type == OPT_OFFSET
1280 || op->operand[0].type == OPT_LABEL))
1281 op->operand[0].lmod = OPLM_DWORD;
1287 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1288 && op->operand[0].lmod == op->operand[1].lmod
1289 && op->operand[0].reg == op->operand[1].reg
1290 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1292 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1293 op->regmask_src = op->regmask_dst = 0;
1298 if (op->operand[0].type == OPT_REG
1299 && op->operand[1].type == OPT_REGMEM)
1302 snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1303 if (IS(buf, op->operand[1].name))
1304 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1309 // trashed regs must be explicitly detected later
1310 op->regmask_dst = 0;
1314 op->regmask_dst = (1 << xBP) | (1 << xSP);
1315 op->regmask_src = 1 << xBP;
1320 op->regmask_dst |= mxST0;
1324 op->regmask_dst |= mxST0;
1325 if (IS(words[op_w] + 3, "1"))
1326 op->operand[0].val = X87_CONST_1;
1327 else if (IS(words[op_w] + 3, "z"))
1328 op->operand[0].val = X87_CONST_Z;
1334 op->regmask_src |= mxST0;
1343 op->regmask_src |= mxST0;
1344 if (op->operand_cnt == 2)
1345 op->regmask_src |= op->regmask_dst;
1346 else if (op->operand_cnt == 1) {
1347 memcpy(&op->operand[1], &op->operand[0], sizeof(op->operand[1]));
1348 op->operand[0].type = OPT_REG;
1349 op->operand[0].lmod = OPLM_QWORD;
1350 op->operand[0].reg = xST0;
1351 op->regmask_dst |= mxST0;
1354 // IDA doesn't use this
1355 aerr("no operands?\n");
1364 op->regmask_src |= mxST0;
1365 op->regmask_dst |= mxST0;
1372 if (op->operand[0].type == OPT_REG
1373 && op->operand[1].type == OPT_CONST)
1375 struct parsed_opr *op1 = &op->operand[1];
1376 if ((op->op == OP_AND && op1->val == 0)
1379 || (op->operand[0].lmod == OPLM_WORD && op1->val == 0xffff)
1380 || (op->operand[0].lmod == OPLM_BYTE && op1->val == 0xff))))
1382 op->regmask_src = 0;
1387 static const char *op_name(struct parsed_op *po)
1389 static char buf[16];
1393 if (po->op == OP_JCC || po->op == OP_SCC) {
1395 *p++ = (po->op == OP_JCC) ? 'j' : 's';
1398 strcpy(p, parsed_flag_op_names[po->pfo]);
1402 for (i = 0; i < ARRAY_SIZE(op_table); i++)
1403 if (op_table[i].op == po->op)
1404 return op_table[i].name;
1410 static const char *dump_op(struct parsed_op *po)
1412 static char out[128];
1419 snprintf(out, sizeof(out), "%s", op_name(po));
1420 for (i = 0; i < po->operand_cnt; i++) {
1424 snprintf(p, sizeof(out) - (p - out),
1425 po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1426 po->operand[i].name);
1432 static const char *lmod_type_u(struct parsed_op *po,
1433 enum opr_lenmod lmod)
1445 ferr(po, "invalid lmod: %d\n", lmod);
1446 return "(_invalid_)";
1450 static const char *lmod_cast_u(struct parsed_op *po,
1451 enum opr_lenmod lmod)
1463 ferr(po, "invalid lmod: %d\n", lmod);
1464 return "(_invalid_)";
1468 static const char *lmod_cast_u_ptr(struct parsed_op *po,
1469 enum opr_lenmod lmod)
1481 ferr(po, "invalid lmod: %d\n", lmod);
1482 return "(_invalid_)";
1486 static const char *lmod_cast_s(struct parsed_op *po,
1487 enum opr_lenmod lmod)
1499 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1500 return "(_invalid_)";
1504 static const char *lmod_cast(struct parsed_op *po,
1505 enum opr_lenmod lmod, int is_signed)
1508 lmod_cast_s(po, lmod) :
1509 lmod_cast_u(po, lmod);
1512 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1524 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1529 static const char *opr_name(struct parsed_op *po, int opr_num)
1531 if (opr_num >= po->operand_cnt)
1532 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1533 return po->operand[opr_num].name;
1536 static unsigned int opr_const(struct parsed_op *po, int opr_num)
1538 if (opr_num >= po->operand_cnt)
1539 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1540 if (po->operand[opr_num].type != OPT_CONST)
1541 ferr(po, "opr %d: const expected\n", opr_num);
1542 return po->operand[opr_num].val;
1545 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1547 if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
1548 ferr(po, "invalid reg: %d\n", popr->reg);
1549 return regs_r32[popr->reg];
1552 static int check_simple_cast(const char *cast, int *bits, int *is_signed)
1554 if (IS_START(cast, "(s8)") || IS_START(cast, "(u8)"))
1556 else if (IS_START(cast, "(s16)") || IS_START(cast, "(u16)"))
1558 else if (IS_START(cast, "(s32)") || IS_START(cast, "(u32)"))
1560 else if (IS_START(cast, "(s64)") || IS_START(cast, "(u64)"))
1565 *is_signed = cast[1] == 's' ? 1 : 0;
1569 static int check_deref_cast(const char *cast, int *bits)
1571 if (IS_START(cast, "*(u8 *)"))
1573 else if (IS_START(cast, "*(u16 *)"))
1575 else if (IS_START(cast, "*(u32 *)"))
1577 else if (IS_START(cast, "*(u64 *)"))
1585 // cast1 is the "final" cast
1586 static const char *simplify_cast(const char *cast1, const char *cast2)
1588 static char buf[256];
1596 if (IS(cast1, cast2))
1599 if (check_simple_cast(cast1, &bits1, &s1) == 0
1600 && check_simple_cast(cast2, &bits2, &s2) == 0)
1605 if (check_simple_cast(cast1, &bits1, &s1) == 0
1606 && check_deref_cast(cast2, &bits2) == 0)
1608 if (bits1 == bits2) {
1609 snprintf(buf, sizeof(buf), "*(%c%d *)", s1 ? 's' : 'u', bits1);
1614 if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1617 snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1621 static const char *simplify_cast_num(const char *cast, unsigned int val)
1623 if (IS(cast, "(u8)") && val < 0x100)
1625 if (IS(cast, "(s8)") && val < 0x80)
1627 if (IS(cast, "(u16)") && val < 0x10000)
1629 if (IS(cast, "(s16)") && val < 0x8000)
1631 if (IS(cast, "(s32)") && val < 0x80000000)
1637 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1646 namelen = strlen(name);
1648 p = strchr(name, '+');
1652 ferr(po, "equ parse failed for '%s'\n", name);
1654 if (IS_START(p, "0x"))
1656 *extra_offs = strtol(p, &endp, 16);
1658 ferr(po, "equ parse failed for '%s'\n", name);
1661 for (i = 0; i < g_eqcnt; i++)
1662 if (strncmp(g_eqs[i].name, name, namelen) == 0
1663 && g_eqs[i].name[namelen] == 0)
1667 ferr(po, "unresolved equ name: '%s'\n", name);
1674 static int is_stack_access(struct parsed_op *po,
1675 const struct parsed_opr *popr)
1677 return (parse_stack_el(popr->name, NULL, 0)
1678 || (g_bp_frame && !(po->flags & OPF_EBP_S)
1679 && IS_START(popr->name, "ebp")));
1682 static void parse_stack_access(struct parsed_op *po,
1683 const char *name, char *ofs_reg, int *offset_out,
1684 int *stack_ra_out, const char **bp_arg_out, int is_lea)
1686 const char *bp_arg = "";
1687 const char *p = NULL;
1688 struct parsed_equ *eq;
1695 if (IS_START(name, "ebp-")
1696 || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1699 if (IS_START(p, "0x"))
1701 offset = strtoul(p, &endp, 16);
1705 ferr(po, "ebp- parse of '%s' failed\n", name);
1708 bp_arg = parse_stack_el(name, ofs_reg, 0);
1709 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1710 eq = equ_find(po, bp_arg, &offset);
1712 ferr(po, "detected but missing eq\n");
1713 offset += eq->offset;
1716 if (!strncmp(name, "ebp", 3))
1719 // yes it sometimes LEAs ra for compares..
1720 if (!is_lea && ofs_reg[0] == 0
1721 && stack_ra <= offset && offset < stack_ra + 4)
1723 ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1726 *offset_out = offset;
1727 *stack_ra_out = stack_ra;
1729 *bp_arg_out = bp_arg;
1732 static int stack_frame_access(struct parsed_op *po,
1733 struct parsed_opr *popr, char *buf, size_t buf_size,
1734 const char *name, const char *cast, int is_src, int is_lea)
1736 enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1737 const char *prefix = "";
1738 const char *bp_arg = NULL;
1739 char ofs_reg[16] = { 0, };
1740 int i, arg_i, arg_s;
1748 if (po->flags & OPF_EBP_S)
1749 ferr(po, "stack_frame_access while ebp is scratch\n");
1751 parse_stack_access(po, name, ofs_reg, &offset,
1752 &stack_ra, &bp_arg, is_lea);
1754 if (offset > stack_ra)
1756 arg_i = (offset - stack_ra - 4) / 4;
1757 if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1759 if (g_func_pp->is_vararg
1760 && arg_i == g_func_pp->argc_stack && is_lea)
1762 // should be va_list
1765 snprintf(buf, buf_size, "%sap", cast);
1768 ferr(po, "offset %d (%s,%d) doesn't map to any arg\n",
1769 offset, bp_arg, arg_i);
1771 if (ofs_reg[0] != 0)
1772 ferr(po, "offset reg on arg access?\n");
1774 for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1775 if (g_func_pp->arg[i].reg != NULL)
1781 if (i == g_func_pp->argc)
1782 ferr(po, "arg %d not in prototype?\n", arg_i);
1784 popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
1791 ferr(po, "lea/byte to arg?\n");
1792 if (is_src && (offset & 3) == 0)
1793 snprintf(buf, buf_size, "%sa%d",
1794 simplify_cast(cast, "(u8)"), i + 1);
1796 snprintf(buf, buf_size, "%sBYTE%d(a%d)",
1797 cast, offset & 3, i + 1);
1802 ferr(po, "lea/word to arg?\n");
1807 ferr(po, "problematic arg store\n");
1808 snprintf(buf, buf_size, "%s((char *)&a%d + 1)",
1809 simplify_cast(cast, "*(u16 *)"), i + 1);
1812 ferr(po, "unaligned arg word load\n");
1814 else if (is_src && (offset & 2) == 0)
1815 snprintf(buf, buf_size, "%sa%d",
1816 simplify_cast(cast, "(u16)"), i + 1);
1818 snprintf(buf, buf_size, "%s%sWORD(a%d)",
1819 cast, (offset & 2) ? "HI" : "LO", i + 1);
1831 snprintf(buf, buf_size, "(u32)&a%d + %d",
1834 ferr(po, "unaligned arg store\n");
1836 // mov edx, [ebp+arg_4+2]; movsx ecx, dx
1837 snprintf(buf, buf_size, "%s(a%d >> %d)",
1838 prefix, i + 1, (offset & 3) * 8);
1842 snprintf(buf, buf_size, "%s%sa%d",
1843 prefix, is_lea ? "&" : "", i + 1);
1848 ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
1852 snprintf(g_comment, sizeof(g_comment), "%s unaligned", bp_arg);
1855 guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
1856 if (tmp_lmod != OPLM_DWORD
1857 && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
1858 < lmod_bytes(po, popr->lmod) + (offset & 3))))
1860 ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
1861 i + 1, offset, g_func_pp->arg[i].type.name);
1863 // can't check this because msvc likes to reuse
1864 // arg space for scratch..
1865 //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
1866 // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
1870 if (g_stack_fsz == 0)
1871 ferr(po, "stack var access without stackframe\n");
1872 g_stack_frame_used = 1;
1874 sf_ofs = g_stack_fsz + offset;
1875 lim = (ofs_reg[0] != 0) ? -4 : 0;
1876 if (offset > 0 || sf_ofs < lim)
1877 ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
1887 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1888 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1892 if ((sf_ofs & 1) || ofs_reg[0] != 0) {
1893 // known unaligned or possibly unaligned
1894 strcat(g_comment, " unaligned");
1896 prefix = "*(u16 *)&";
1897 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1898 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1901 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
1905 if ((sf_ofs & 3) || ofs_reg[0] != 0) {
1906 // known unaligned or possibly unaligned
1907 strcat(g_comment, " unaligned");
1909 prefix = "*(u32 *)&";
1910 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1911 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1914 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
1918 ferr_assert(po, !(sf_ofs & 7));
1919 ferr_assert(po, ofs_reg[0] == 0);
1920 // float callers set is_lea
1921 ferr_assert(po, is_lea);
1922 snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
1926 ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
1933 static void check_func_pp(struct parsed_op *po,
1934 const struct parsed_proto *pp, const char *pfx)
1936 enum opr_lenmod tmp_lmod;
1940 if (pp->argc_reg != 0) {
1941 if (/*!g_allow_regfunc &&*/ !pp->is_fastcall) {
1942 pp_print(buf, sizeof(buf), pp);
1943 ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
1945 if (pp->argc_stack > 0 && pp->argc_reg != 2)
1946 ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
1947 pfx, pp->argc_reg, pp->argc_stack);
1950 // fptrs must use 32bit args, callsite might have no information and
1951 // lack a cast to smaller types, which results in incorrectly masked
1952 // args passed (callee may assume masked args, it does on ARM)
1953 if (!pp->is_osinc) {
1954 for (i = 0; i < pp->argc; i++) {
1955 ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
1956 if (ret && tmp_lmod != OPLM_DWORD)
1957 ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
1958 i + 1, pp->arg[i].type.name);
1963 static const char *check_label_read_ref(struct parsed_op *po,
1966 const struct parsed_proto *pp;
1968 pp = proto_parse(g_fhdr, name, 0);
1970 ferr(po, "proto_parse failed for ref '%s'\n", name);
1973 check_func_pp(po, pp, "ref");
1978 static char *out_src_opr(char *buf, size_t buf_size,
1979 struct parsed_op *po, struct parsed_opr *popr, const char *cast,
1982 char tmp1[256], tmp2[256];
1991 switch (popr->type) {
1994 ferr(po, "lea from reg?\n");
1996 switch (popr->lmod) {
1998 snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2001 snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2004 snprintf(buf, buf_size, "%s%s",
2005 simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2008 if (popr->name[1] == 'h') // XXX..
2009 snprintf(buf, buf_size, "%s(%s >> 8)",
2010 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2012 snprintf(buf, buf_size, "%s%s",
2013 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2016 ferr(po, "invalid src lmod: %d\n", popr->lmod);
2021 if (is_stack_access(po, popr)) {
2022 stack_frame_access(po, popr, buf, buf_size,
2023 popr->name, cast, 1, is_lea);
2027 strcpy(expr, popr->name);
2028 if (strchr(expr, '[')) {
2029 // special case: '[' can only be left for label[reg] form
2030 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2032 ferr(po, "parse failure for '%s'\n", expr);
2033 if (tmp1[0] == '(') {
2034 // (off_4FFF50+3)[eax]
2035 p = strchr(tmp1 + 1, ')');
2036 if (p == NULL || p[1] != 0)
2037 ferr(po, "parse failure (2) for '%s'\n", expr);
2039 memmove(tmp1, tmp1 + 1, strlen(tmp1));
2041 snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2044 // XXX: do we need more parsing?
2046 snprintf(buf, buf_size, "%s", expr);
2050 snprintf(buf, buf_size, "%s(%s)",
2051 simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2055 name = check_label_read_ref(po, popr->name);
2056 if (cast[0] == 0 && popr->is_ptr)
2060 snprintf(buf, buf_size, "(u32)&%s", name);
2061 else if (popr->size_lt)
2062 snprintf(buf, buf_size, "%s%s%s%s", cast,
2063 lmod_cast_u_ptr(po, popr->lmod),
2064 popr->is_array ? "" : "&", name);
2066 snprintf(buf, buf_size, "%s%s%s", cast, name,
2067 popr->is_array ? "[0]" : "");
2071 name = check_label_read_ref(po, popr->name);
2075 ferr(po, "lea an offset?\n");
2076 snprintf(buf, buf_size, "%s&%s", cast, name);
2081 ferr(po, "lea from const?\n");
2083 printf_number(tmp1, sizeof(tmp1), popr->val);
2084 if (popr->val == 0 && strchr(cast, '*'))
2085 snprintf(buf, buf_size, "NULL");
2087 snprintf(buf, buf_size, "%s%s",
2088 simplify_cast_num(cast, popr->val), tmp1);
2092 ferr(po, "invalid src type: %d\n", popr->type);
2098 // note: may set is_ptr (we find that out late for ebp frame..)
2099 static char *out_dst_opr(char *buf, size_t buf_size,
2100 struct parsed_op *po, struct parsed_opr *popr)
2102 switch (popr->type) {
2104 switch (popr->lmod) {
2106 snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2109 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2113 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2117 if (popr->name[1] == 'h') // XXX..
2118 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2120 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2123 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2128 if (is_stack_access(po, popr)) {
2129 stack_frame_access(po, popr, buf, buf_size,
2130 popr->name, "", 0, 0);
2134 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2137 if (popr->size_mismatch)
2138 snprintf(buf, buf_size, "%s%s%s",
2139 lmod_cast_u_ptr(po, popr->lmod),
2140 popr->is_array ? "" : "&", popr->name);
2142 snprintf(buf, buf_size, "%s%s", popr->name,
2143 popr->is_array ? "[0]" : "");
2147 ferr(po, "invalid dst type: %d\n", popr->type);
2153 static char *out_src_opr_u32(char *buf, size_t buf_size,
2154 struct parsed_op *po, struct parsed_opr *popr)
2156 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2159 static char *out_src_opr_float(char *buf, size_t buf_size,
2160 struct parsed_op *po, struct parsed_opr *popr)
2162 const char *cast = NULL;
2165 switch (popr->type) {
2167 if (popr->reg < xST0 || popr->reg > xST7)
2168 ferr(po, "bad reg: %d\n", popr->reg);
2170 snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2176 switch (popr->lmod) {
2184 ferr(po, "unhandled lmod: %d\n", popr->lmod);
2187 out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2188 snprintf(buf, buf_size, "*((%s *)%s)", cast, tmp);
2192 ferr(po, "invalid float type: %d\n", popr->type);
2198 static char *out_dst_opr_float(char *buf, size_t buf_size,
2199 struct parsed_op *po, struct parsed_opr *popr)
2202 return out_src_opr_float(buf, buf_size, po, popr);
2205 static void out_test_for_cc(char *buf, size_t buf_size,
2206 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2207 enum opr_lenmod lmod, const char *expr)
2209 const char *cast, *scast;
2211 cast = lmod_cast_u(po, lmod);
2212 scast = lmod_cast_s(po, lmod);
2216 case PFO_BE: // CF=1||ZF=1; CF=0
2217 snprintf(buf, buf_size, "(%s%s %s 0)",
2218 cast, expr, is_inv ? "!=" : "==");
2222 case PFO_L: // SF!=OF; OF=0
2223 snprintf(buf, buf_size, "(%s%s %s 0)",
2224 scast, expr, is_inv ? ">=" : "<");
2227 case PFO_LE: // ZF=1||SF!=OF; OF=0
2228 snprintf(buf, buf_size, "(%s%s %s 0)",
2229 scast, expr, is_inv ? ">" : "<=");
2233 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2237 static void out_cmp_for_cc(char *buf, size_t buf_size,
2238 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2240 const char *cast, *scast, *cast_use;
2241 char buf1[256], buf2[256];
2242 enum opr_lenmod lmod;
2244 if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2245 ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2246 po->operand[0].lmod, po->operand[1].lmod);
2247 lmod = po->operand[0].lmod;
2249 cast = lmod_cast_u(po, lmod);
2250 scast = lmod_cast_s(po, lmod);
2266 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2269 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2270 if (po->op == OP_DEC)
2271 snprintf(buf2, sizeof(buf2), "1");
2273 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_use, 0);
2277 // note: must be unsigned compare
2278 snprintf(buf, buf_size, "(%s %s %s)",
2279 buf1, is_inv ? ">=" : "<", buf2);
2283 snprintf(buf, buf_size, "(%s %s %s)",
2284 buf1, is_inv ? "!=" : "==", buf2);
2288 // note: must be unsigned compare
2289 snprintf(buf, buf_size, "(%s %s %s)",
2290 buf1, is_inv ? ">" : "<=", buf2);
2293 if (is_inv && lmod == OPLM_BYTE
2294 && po->operand[1].type == OPT_CONST
2295 && po->operand[1].val == 0xff)
2297 snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2298 snprintf(buf, buf_size, "(0)");
2302 // note: must be signed compare
2304 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2305 scast, buf1, buf2, is_inv ? ">=" : "<");
2309 snprintf(buf, buf_size, "(%s %s %s)",
2310 buf1, is_inv ? ">=" : "<", buf2);
2314 snprintf(buf, buf_size, "(%s %s %s)",
2315 buf1, is_inv ? ">" : "<=", buf2);
2323 static void out_cmp_test(char *buf, size_t buf_size,
2324 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2326 char buf1[256], buf2[256], buf3[256];
2328 if (po->op == OP_TEST) {
2329 if (IS(opr_name(po, 0), opr_name(po, 1))) {
2330 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2333 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2334 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2335 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2337 out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2338 po->operand[0].lmod, buf3);
2340 else if (po->op == OP_CMP) {
2341 out_cmp_for_cc(buf, buf_size, po, pfo, is_inv);
2344 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2347 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2348 struct parsed_opr *popr2)
2350 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2351 ferr(po, "missing lmod for both operands\n");
2353 if (popr1->lmod == OPLM_UNSPEC)
2354 popr1->lmod = popr2->lmod;
2355 else if (popr2->lmod == OPLM_UNSPEC)
2356 popr2->lmod = popr1->lmod;
2357 else if (popr1->lmod != popr2->lmod) {
2358 if (popr1->type_from_var) {
2359 popr1->size_mismatch = 1;
2360 if (popr1->lmod < popr2->lmod)
2362 popr1->lmod = popr2->lmod;
2364 else if (popr2->type_from_var) {
2365 popr2->size_mismatch = 1;
2366 if (popr2->lmod < popr1->lmod)
2368 popr2->lmod = popr1->lmod;
2371 ferr(po, "conflicting lmods: %d vs %d\n",
2372 popr1->lmod, popr2->lmod);
2376 static const char *op_to_c(struct parsed_op *po)
2400 ferr(po, "op_to_c was supplied with %d\n", po->op);
2404 // last op in stream - unconditional branch or ret
2405 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2406 || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2407 && ops[_i].op != OP_CALL))
2409 #define check_i(po, i) \
2411 ferr(po, "bad " #i ": %d\n", i)
2413 // note: this skips over calls and rm'd stuff assuming they're handled
2414 // so it's intended to use at one of final passes
2415 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2416 int depth, int flags_set)
2418 struct parsed_op *po;
2423 for (; i < opcnt; i++) {
2425 if (po->cc_scratch == magic)
2426 return ret; // already checked
2427 po->cc_scratch = magic;
2429 if (po->flags & OPF_TAIL) {
2430 if (po->op == OP_CALL) {
2431 if (po->pp != NULL && po->pp->is_noreturn)
2432 // assume no stack cleanup for noreturn
2435 return -1; // deadend
2438 if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
2441 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2442 if (po->btj != NULL) {
2444 for (j = 0; j < po->btj->count; j++) {
2445 check_i(po, po->btj->d[j].bt_i);
2446 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2449 return ret; // dead end
2454 check_i(po, po->bt_i);
2455 if (po->flags & OPF_CJMP) {
2456 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2459 return ret; // dead end
2468 if ((po->op == OP_POP || po->op == OP_PUSH)
2469 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2474 if (po->op == OP_PUSH) {
2477 else if (po->op == OP_POP) {
2478 if (relevant && depth == 0) {
2479 po->flags |= flags_set;
2489 // scan for 'reg' pop backwards starting from i
2490 // intended to use for register restore search, so other reg
2491 // references are considered an error
2492 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2494 struct parsed_op *po;
2495 struct label_ref *lr;
2498 ops[i].cc_scratch = magic;
2502 if (g_labels[i] != NULL) {
2503 lr = &g_label_refs[i];
2504 for (; lr != NULL; lr = lr->next) {
2505 check_i(&ops[i], lr->i);
2506 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2510 if (i > 0 && LAST_OP(i - 1))
2518 if (ops[i].cc_scratch == magic)
2520 ops[i].cc_scratch = magic;
2523 if (po->op == OP_POP && po->operand[0].reg == reg) {
2524 if (po->flags & (OPF_RMD|OPF_DONE))
2527 po->flags |= set_flags;
2531 // this also covers the case where we reach corresponding push
2532 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2536 // nothing interesting on this path
2540 static void find_reachable_exits(int i, int opcnt, int magic,
2541 int *exits, int *exit_count)
2543 struct parsed_op *po;
2546 for (; i < opcnt; i++)
2549 if (po->cc_scratch == magic)
2551 po->cc_scratch = magic;
2553 if (po->flags & OPF_TAIL) {
2554 ferr_assert(po, *exit_count < MAX_EXITS);
2555 exits[*exit_count] = i;
2560 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2561 if (po->flags & OPF_RMD)
2564 if (po->btj != NULL) {
2565 for (j = 0; j < po->btj->count; j++) {
2566 check_i(po, po->btj->d[j].bt_i);
2567 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2573 check_i(po, po->bt_i);
2574 if (po->flags & OPF_CJMP)
2575 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2583 // scan for 'reg' pop backwards starting from exits (all paths)
2584 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2586 static int exits[MAX_EXITS];
2587 static int exit_count;
2592 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2594 ferr_assert(&ops[i], exit_count > 0);
2597 for (j = 0; j < exit_count; j++) {
2598 ret = scan_for_rsave_pop_reg(exits[j], i + opcnt * 16 + set_flags,
2607 // scan for one or more pop of push <const>
2608 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2609 int push_i, int is_probe)
2611 struct parsed_op *po;
2612 struct label_ref *lr;
2616 for (; i < opcnt; i++)
2619 if (po->cc_scratch == magic)
2620 return ret; // already checked
2621 po->cc_scratch = magic;
2623 if (po->flags & OPF_JMP) {
2624 if (po->flags & OPF_RMD)
2626 if (po->op == OP_CALL)
2629 if (po->btj != NULL) {
2630 for (j = 0; j < po->btj->count; j++) {
2631 check_i(po, po->btj->d[j].bt_i);
2632 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2640 check_i(po, po->bt_i);
2641 if (po->flags & OPF_CJMP) {
2642 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2653 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2656 if (g_labels[i] != NULL) {
2657 // all refs must be visited
2658 lr = &g_label_refs[i];
2659 for (; lr != NULL; lr = lr->next) {
2661 if (ops[lr->i].cc_scratch != magic)
2664 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2668 if (po->op == OP_POP)
2670 if (po->flags & (OPF_RMD|OPF_DONE))
2674 po->flags |= OPF_DONE;
2675 po->datap = &ops[push_i];
2684 static void scan_for_pop_const(int i, int opcnt, int magic)
2688 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
2690 ops[i].flags |= OPF_RMD | OPF_DONE;
2691 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
2695 // check if all branch targets within a marked path are also marked
2696 // note: the path checked must not be empty or end with a branch
2697 static int check_path_branches(int opcnt, int magic)
2699 struct parsed_op *po;
2702 for (i = 0; i < opcnt; i++) {
2704 if (po->cc_scratch != magic)
2707 if (po->flags & OPF_JMP) {
2708 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
2711 if (po->btj != NULL) {
2712 for (j = 0; j < po->btj->count; j++) {
2713 check_i(po, po->btj->d[j].bt_i);
2714 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
2719 check_i(po, po->bt_i);
2720 if (ops[po->bt_i].cc_scratch != magic)
2722 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
2730 // scan for multiple pushes for given pop
2731 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
2734 int reg = ops[pop_i].operand[0].reg;
2735 struct parsed_op *po;
2736 struct label_ref *lr;
2739 ops[i].cc_scratch = magic;
2743 if (g_labels[i] != NULL) {
2744 lr = &g_label_refs[i];
2745 for (; lr != NULL; lr = lr->next) {
2746 check_i(&ops[i], lr->i);
2747 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
2751 if (i > 0 && LAST_OP(i - 1))
2759 if (ops[i].cc_scratch == magic)
2761 ops[i].cc_scratch = magic;
2764 if (po->op == OP_CALL)
2766 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
2769 if (po->op == OP_PUSH)
2771 if (po->datap != NULL)
2773 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2774 // leave this case for reg save/restore handlers
2778 po->flags |= OPF_PPUSH | OPF_DONE;
2779 po->datap = &ops[pop_i];
2788 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
2790 int magic = i + opcnt * 14;
2793 ret = scan_pushes_for_pop_r(i, magic, i, 1);
2795 ret = check_path_branches(opcnt, magic);
2797 ops[i].flags |= OPF_PPUSH | OPF_DONE;
2798 *regmask_pp |= 1 << ops[i].operand[0].reg;
2799 scan_pushes_for_pop_r(i, magic + 1, i, 0);
2804 static void scan_propagate_df(int i, int opcnt)
2806 struct parsed_op *po = &ops[i];
2809 for (; i < opcnt; i++) {
2811 if (po->flags & OPF_DF)
2812 return; // already resolved
2813 po->flags |= OPF_DF;
2815 if (po->op == OP_CALL)
2816 ferr(po, "call with DF set?\n");
2818 if (po->flags & OPF_JMP) {
2819 if (po->btj != NULL) {
2821 for (j = 0; j < po->btj->count; j++) {
2822 check_i(po, po->btj->d[j].bt_i);
2823 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
2828 if (po->flags & OPF_RMD)
2830 check_i(po, po->bt_i);
2831 if (po->flags & OPF_CJMP)
2832 scan_propagate_df(po->bt_i, opcnt);
2838 if (po->flags & OPF_TAIL)
2841 if (po->op == OP_CLD) {
2842 po->flags |= OPF_RMD | OPF_DONE;
2847 ferr(po, "missing DF clear?\n");
2850 // is operand 'opr' referenced by parsed_op 'po'?
2851 static int is_opr_referenced(const struct parsed_opr *opr,
2852 const struct parsed_op *po)
2856 if (opr->type == OPT_REG) {
2857 mask = po->regmask_dst | po->regmask_src;
2858 if (po->op == OP_CALL)
2859 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
2860 if ((1 << opr->reg) & mask)
2866 for (i = 0; i < po->operand_cnt; i++)
2867 if (IS(po->operand[0].name, opr->name))
2873 // is operand 'opr' read by parsed_op 'po'?
2874 static int is_opr_read(const struct parsed_opr *opr,
2875 const struct parsed_op *po)
2877 if (opr->type == OPT_REG) {
2878 if (po->regmask_src & (1 << opr->reg))
2888 // is operand 'opr' modified by parsed_op 'po'?
2889 static int is_opr_modified(const struct parsed_opr *opr,
2890 const struct parsed_op *po)
2894 if (opr->type == OPT_REG) {
2895 if (po->op == OP_CALL) {
2896 mask = po->regmask_dst;
2897 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
2898 if (mask & (1 << opr->reg))
2904 if (po->regmask_dst & (1 << opr->reg))
2910 return IS(po->operand[0].name, opr->name);
2913 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
2914 static int is_any_opr_modified(const struct parsed_op *po_test,
2915 const struct parsed_op *po, int c_mode)
2920 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
2923 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
2926 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
2929 // in reality, it can wreck any register, but in decompiled C
2930 // version it can only overwrite eax or edx:eax
2931 mask = (1 << xAX) | (1 << xDX);
2935 if (po->op == OP_CALL
2936 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
2939 for (i = 0; i < po_test->operand_cnt; i++)
2940 if (IS(po_test->operand[i].name, po->operand[0].name))
2946 // scan for any po_test operand modification in range given
2947 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
2950 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
2953 for (; i < opcnt; i++) {
2954 if (is_any_opr_modified(po_test, &ops[i], c_mode))
2961 // scan for po_test operand[0] modification in range given
2962 static int scan_for_mod_opr0(struct parsed_op *po_test,
2965 for (; i < opcnt; i++) {
2966 if (is_opr_modified(&po_test->operand[0], &ops[i]))
2973 static int scan_for_flag_set(int i, int magic, int *branched,
2974 int *setters, int *setter_cnt)
2976 struct label_ref *lr;
2980 if (ops[i].cc_scratch == magic) {
2981 // is this a problem?
2982 //ferr(&ops[i], "%s looped\n", __func__);
2985 ops[i].cc_scratch = magic;
2987 if (g_labels[i] != NULL) {
2990 lr = &g_label_refs[i];
2991 for (; lr->next; lr = lr->next) {
2992 check_i(&ops[i], lr->i);
2993 ret = scan_for_flag_set(lr->i, magic,
2994 branched, setters, setter_cnt);
2999 check_i(&ops[i], lr->i);
3000 if (i > 0 && LAST_OP(i - 1)) {
3004 ret = scan_for_flag_set(lr->i, magic,
3005 branched, setters, setter_cnt);
3011 if (ops[i].flags & OPF_FLAGS) {
3012 setters[*setter_cnt] = i;
3017 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3024 // scan back for cdq, if anything modifies edx, fail
3025 static int scan_for_cdq_edx(int i)
3028 if (g_labels[i] != NULL) {
3029 if (g_label_refs[i].next != NULL)
3031 if (i > 0 && LAST_OP(i - 1)) {
3032 i = g_label_refs[i].i;
3039 if (ops[i].op == OP_CDQ)
3042 if (ops[i].regmask_dst & (1 << xDX))
3049 static int scan_for_reg_clear(int i, int reg)
3052 if (g_labels[i] != NULL) {
3053 if (g_label_refs[i].next != NULL)
3055 if (i > 0 && LAST_OP(i - 1)) {
3056 i = g_label_refs[i].i;
3063 if (ops[i].op == OP_XOR
3064 && ops[i].operand[0].lmod == OPLM_DWORD
3065 && ops[i].operand[0].reg == ops[i].operand[1].reg
3066 && ops[i].operand[0].reg == reg)
3069 if (ops[i].regmask_dst & (1 << reg))
3076 static void patch_esp_adjust(struct parsed_op *po, int adj)
3078 ferr_assert(po, po->op == OP_ADD);
3079 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3080 ferr_assert(po, po->operand[1].type == OPT_CONST);
3082 // this is a bit of a hack, but deals with use of
3083 // single adj for multiple calls
3084 po->operand[1].val -= adj;
3085 po->flags |= OPF_RMD;
3086 if (po->operand[1].val == 0)
3087 po->flags |= OPF_DONE;
3088 ferr_assert(po, (int)po->operand[1].val >= 0);
3091 // scan for positive, constant esp adjust
3092 // multipath case is preliminary
3093 static int scan_for_esp_adjust(int i, int opcnt,
3094 int adj_expect, int *adj, int *is_multipath, int do_update)
3096 int adj_expect_unknown = 0;
3097 struct parsed_op *po;
3101 *adj = *is_multipath = 0;
3102 if (adj_expect < 0) {
3103 adj_expect_unknown = 1;
3104 adj_expect = 32 * 4; // enough?
3107 for (; i < opcnt && *adj < adj_expect; i++) {
3108 if (g_labels[i] != NULL)
3112 if (po->flags & OPF_DONE)
3115 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3116 if (po->operand[1].type != OPT_CONST)
3117 ferr(&ops[i], "non-const esp adjust?\n");
3118 *adj += po->operand[1].val;
3120 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3123 patch_esp_adjust(po, adj_expect);
3125 po->flags |= OPF_RMD;
3129 else if (po->op == OP_PUSH) {
3130 //if (first_pop == -1)
3131 // first_pop = -2; // none
3132 *adj -= lmod_bytes(po, po->operand[0].lmod);
3134 else if (po->op == OP_POP) {
3135 if (!(po->flags & OPF_DONE)) {
3136 // seems like msvc only uses 'pop ecx' for stack realignment..
3137 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3139 if (first_pop == -1 && *adj >= 0)
3142 if (do_update && *adj >= 0) {
3143 po->flags |= OPF_RMD;
3145 po->flags |= OPF_DONE | OPF_NOREGS;
3148 *adj += lmod_bytes(po, po->operand[0].lmod);
3149 if (*adj > adj_best)
3152 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3153 if (po->op == OP_JMP && po->btj == NULL) {
3159 if (po->op != OP_CALL)
3161 if (po->operand[0].type != OPT_LABEL)
3163 if (po->pp != NULL && po->pp->is_stdcall)
3165 if (adj_expect_unknown && first_pop >= 0)
3167 // assume it's another cdecl call
3171 if (first_pop >= 0) {
3172 // probably only 'pop ecx' was used
3180 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3182 struct parsed_op *po;
3186 ferr(ops, "%s: followed bad branch?\n", __func__);
3188 for (; i < opcnt; i++) {
3190 if (po->cc_scratch == magic)
3192 po->cc_scratch = magic;
3195 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3196 if (po->btj != NULL) {
3198 for (j = 0; j < po->btj->count; j++)
3199 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3203 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3204 if (!(po->flags & OPF_CJMP))
3207 if (po->flags & OPF_TAIL)
3212 static const struct parsed_proto *try_recover_pp(
3213 struct parsed_op *po, const struct parsed_opr *opr, int *search_instead)
3215 const struct parsed_proto *pp = NULL;
3219 // maybe an arg of g_func?
3220 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3222 char ofs_reg[16] = { 0, };
3223 int arg, arg_s, arg_i;
3230 parse_stack_access(po, opr->name, ofs_reg,
3231 &offset, &stack_ra, NULL, 0);
3232 if (ofs_reg[0] != 0)
3233 ferr(po, "offset reg on arg access?\n");
3234 if (offset <= stack_ra) {
3235 // search who set the stack var instead
3236 if (search_instead != NULL)
3237 *search_instead = 1;
3241 arg_i = (offset - stack_ra - 4) / 4;
3242 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3243 if (g_func_pp->arg[arg].reg != NULL)
3249 if (arg == g_func_pp->argc)
3250 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3252 pp = g_func_pp->arg[arg].fptr;
3254 ferr(po, "icall sa: arg%d is not a fptr?\n", arg + 1);
3255 check_func_pp(po, pp, "icall arg");
3257 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3259 p = strchr(opr->name + 1, '[');
3260 memcpy(buf, opr->name, p - opr->name);
3261 buf[p - opr->name] = 0;
3262 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3264 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3265 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3268 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3271 check_func_pp(po, pp, "reg-fptr ref");
3277 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3278 int magic, const struct parsed_proto **pp_found, int *pp_i,
3281 const struct parsed_proto *pp = NULL;
3282 struct parsed_op *po;
3283 struct label_ref *lr;
3285 ops[i].cc_scratch = magic;
3288 if (g_labels[i] != NULL) {
3289 lr = &g_label_refs[i];
3290 for (; lr != NULL; lr = lr->next) {
3291 check_i(&ops[i], lr->i);
3292 scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3294 if (i > 0 && LAST_OP(i - 1))
3302 if (ops[i].cc_scratch == magic)
3304 ops[i].cc_scratch = magic;
3306 if (!(ops[i].flags & OPF_DATA))
3308 if (!is_opr_modified(opr, &ops[i]))
3310 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3311 // most probably trashed by some processing
3316 opr = &ops[i].operand[1];
3317 if (opr->type != OPT_REG)
3321 po = (i >= 0) ? &ops[i] : ops;
3324 // reached the top - can only be an arg-reg
3325 if (opr->type != OPT_REG || g_func_pp == NULL)
3328 for (i = 0; i < g_func_pp->argc; i++) {
3329 if (g_func_pp->arg[i].reg == NULL)
3331 if (IS(opr->name, g_func_pp->arg[i].reg))
3334 if (i == g_func_pp->argc)
3336 pp = g_func_pp->arg[i].fptr;
3338 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3339 i + 1, g_func_pp->arg[i].reg);
3340 check_func_pp(po, pp, "icall reg-arg");
3343 pp = try_recover_pp(po, opr, NULL);
3345 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3346 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3347 || (*pp_found)->is_stdcall != pp->is_stdcall
3348 || (*pp_found)->is_fptr != pp->is_fptr
3349 || (*pp_found)->argc != pp->argc
3350 || (*pp_found)->argc_reg != pp->argc_reg
3351 || (*pp_found)->argc_stack != pp->argc_stack)
3353 ferr(po, "icall: parsed_proto mismatch\n");
3363 static void add_label_ref(struct label_ref *lr, int op_i)
3365 struct label_ref *lr_new;
3372 lr_new = calloc(1, sizeof(*lr_new));
3374 lr_new->next = lr->next;
3378 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3380 struct parsed_op *po = &ops[i];
3381 struct parsed_data *pd;
3382 char label[NAMELEN], *p;
3385 p = strchr(po->operand[0].name, '[');
3389 len = p - po->operand[0].name;
3390 strncpy(label, po->operand[0].name, len);
3393 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3394 if (IS(g_func_pd[j].label, label)) {
3400 //ferr(po, "label '%s' not parsed?\n", label);
3403 if (pd->type != OPT_OFFSET)
3404 ferr(po, "label '%s' with non-offset data?\n", label);
3406 // find all labels, link
3407 for (j = 0; j < pd->count; j++) {
3408 for (l = 0; l < opcnt; l++) {
3409 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3410 add_label_ref(&g_label_refs[l], i);
3420 static void clear_labels(int count)
3424 for (i = 0; i < count; i++) {
3425 if (g_labels[i] != NULL) {
3432 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3437 for (i = 0; i < pp->argc; i++) {
3438 if (pp->arg[i].reg != NULL) {
3439 reg = char_array_i(regs_r32,
3440 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3442 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3443 pp->arg[i].reg, pp->name);
3444 regmask |= 1 << reg;
3451 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3453 if (strstr(pp->ret_type.name, "int64"))
3454 return (1 << xAX) | (1 << xDX);
3455 if (IS(pp->ret_type.name, "float")
3456 || IS(pp->ret_type.name, "double"))
3460 if (strcasecmp(pp->ret_type.name, "void") == 0)
3466 static void resolve_branches_parse_calls(int opcnt)
3468 static const struct {
3472 unsigned int regmask_src;
3473 unsigned int regmask_dst;
3475 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3477 const struct parsed_proto *pp_c;
3478 struct parsed_proto *pp;
3479 struct parsed_data *pd;
3480 struct parsed_op *po;
3481 const char *tmpname;
3485 for (i = 0; i < opcnt; i++)
3491 if (po->op == OP_CALL) {
3494 if (po->operand[0].type == OPT_LABEL) {
3495 tmpname = opr_name(po, 0);
3496 if (IS_START(tmpname, "loc_"))
3497 ferr(po, "call to loc_*\n");
3499 // convert some calls to pseudo-ops
3500 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3501 if (!IS(tmpname, pseudo_ops[l].name))
3504 po->op = pseudo_ops[l].op;
3505 po->operand_cnt = 0;
3506 po->regmask_src = pseudo_ops[l].regmask_src;
3507 po->regmask_dst = pseudo_ops[l].regmask_dst;
3508 po->flags = pseudo_ops[l].flags;
3509 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3512 if (l < ARRAY_SIZE(pseudo_ops))
3515 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3516 if (!g_header_mode && pp_c == NULL)
3517 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3520 pp = proto_clone(pp_c);
3521 my_assert_not(pp, NULL);
3524 else if (po->datap != NULL) {
3525 pp = calloc(1, sizeof(*pp));
3526 my_assert_not(pp, NULL);
3528 ret = parse_protostr(po->datap, pp);
3530 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3537 check_func_pp(po, pp, "fptr var call");
3538 if (pp->is_noreturn)
3539 po->flags |= OPF_TAIL;
3545 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3548 if (po->operand[0].type == OPT_REGMEM) {
3549 pd = try_resolve_jumptab(i, opcnt);
3557 for (l = 0; l < opcnt; l++) {
3558 if (g_labels[l] != NULL
3559 && IS(po->operand[0].name, g_labels[l]))
3561 if (l == i + 1 && po->op == OP_JMP) {
3562 // yet another alignment type..
3563 po->flags |= OPF_RMD|OPF_DONE;
3566 add_label_ref(&g_label_refs[l], i);
3572 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3575 if (po->operand[0].type == OPT_LABEL)
3579 ferr(po, "unhandled branch\n");
3583 po->flags |= OPF_TAIL;
3584 if (i > 0 && ops[i - 1].op == OP_POP)
3585 po->flags |= OPF_ATAIL;
3590 static void scan_prologue_epilogue(int opcnt)
3592 int ecx_push = 0, esp_sub = 0;
3596 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
3597 && ops[1].op == OP_MOV
3598 && IS(opr_name(&ops[1], 0), "ebp")
3599 && IS(opr_name(&ops[1], 1), "esp"))
3602 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3603 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3606 if (ops[2].op == OP_SUB && IS(opr_name(&ops[2], 0), "esp")) {
3607 g_stack_fsz = opr_const(&ops[2], 1);
3608 ops[2].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3612 // another way msvc builds stack frame..
3614 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3616 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3620 // and another way..
3621 if (i == 2 && ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3622 && ops[i].operand[1].type == OPT_CONST
3623 && ops[i + 1].op == OP_CALL
3624 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3626 g_stack_fsz += ops[i].operand[1].val;
3627 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3629 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3636 for (; i < opcnt; i++)
3637 if (ops[i].flags & OPF_TAIL)
3640 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3641 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3647 if ((ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
3648 || ops[j].op == OP_LEAVE)
3650 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3652 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
3653 && ops[i].pp->is_noreturn)
3655 // on noreturn, msvc sometimes cleans stack, sometimes not
3660 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3661 ferr(&ops[j], "'pop ebp' expected\n");
3663 if (g_stack_fsz != 0) {
3664 if (ops[j].op == OP_LEAVE)
3666 else if (ops[j].op == OP_POP
3667 && ops[j - 1].op == OP_MOV
3668 && IS(opr_name(&ops[j - 1], 0), "esp")
3669 && IS(opr_name(&ops[j - 1], 1), "ebp"))
3671 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3674 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3676 ferr(&ops[j], "esp restore expected\n");
3679 if (ecx_push && j >= 0 && ops[j].op == OP_POP
3680 && IS(opr_name(&ops[j], 0), "ecx"))
3682 ferr(&ops[j], "unexpected ecx pop\n");
3688 } while (i < opcnt);
3691 ferr(ops, "missing ebp epilogue\n");
3697 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3698 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3704 for (; i < opcnt; i++) {
3705 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
3707 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
3708 && ops[i].operand[1].type == OPT_CONST)
3710 g_stack_fsz = ops[i].operand[1].val;
3711 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3717 if (ecx_push && !esp_sub) {
3718 // could actually be args for a call..
3719 for (; i < opcnt; i++)
3720 if (ops[i].op != OP_PUSH)
3723 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
3724 const struct parsed_proto *pp;
3725 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
3726 j = pp ? pp->argc_stack : 0;
3727 while (i > 0 && j > 0) {
3729 if (ops[i].op == OP_PUSH) {
3730 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
3735 ferr(&ops[i], "unhandled prologue\n");
3738 i = g_stack_fsz = ecx_push = 0;
3739 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3740 if (!(ops[i].flags & OPF_RMD))
3750 if (ecx_push || esp_sub)
3756 for (; i < opcnt; i++)
3757 if (ops[i].flags & OPF_TAIL)
3760 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3761 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3768 for (l = 0; l < ecx_push; l++) {
3769 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
3771 else if (ops[j].op == OP_ADD
3772 && IS(opr_name(&ops[j], 0), "esp")
3773 && ops[j].operand[1].type == OPT_CONST)
3776 l += ops[j].operand[1].val / 4 - 1;
3779 ferr(&ops[j], "'pop ecx' expected\n");
3781 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3785 ferr(&ops[j], "epilogue scan failed\n");
3791 if (ops[j].op != OP_ADD
3792 || !IS(opr_name(&ops[j], 0), "esp")
3793 || ops[j].operand[1].type != OPT_CONST
3794 || ops[j].operand[1].val != g_stack_fsz)
3795 ferr(&ops[j], "'add esp' expected\n");
3797 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3798 ops[j].operand[1].val = 0; // hack for stack arg scanner
3803 } while (i < opcnt);
3806 ferr(ops, "missing esp epilogue\n");
3810 static const struct parsed_proto *resolve_icall(int i, int opcnt,
3811 int *pp_i, int *multi_src)
3813 const struct parsed_proto *pp = NULL;
3814 int search_advice = 0;
3819 switch (ops[i].operand[0].type) {
3823 pp = try_recover_pp(&ops[i], &ops[i].operand[0], &search_advice);
3828 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
3836 // find an instruction that changed opr before i op
3837 // *op_i must be set to -1 by the caller
3838 // *entry is set to 1 if one source is determined to be the caller
3839 // returns 1 if found, *op_i is then set to origin
3840 static int resolve_origin(int i, const struct parsed_opr *opr,
3841 int magic, int *op_i, int *is_caller)
3843 struct label_ref *lr;
3846 if (ops[i].cc_scratch == magic)
3848 ops[i].cc_scratch = magic;
3851 if (g_labels[i] != NULL) {
3852 lr = &g_label_refs[i];
3853 for (; lr != NULL; lr = lr->next) {
3854 check_i(&ops[i], lr->i);
3855 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
3857 if (i > 0 && LAST_OP(i - 1))
3863 if (is_caller != NULL)
3868 if (ops[i].cc_scratch == magic)
3870 ops[i].cc_scratch = magic;
3872 if (!(ops[i].flags & OPF_DATA))
3874 if (!is_opr_modified(opr, &ops[i]))
3881 // XXX: could check if the other op does the same
3890 // find an instruction that previously referenced opr
3891 // if multiple results are found - fail
3892 // *op_i must be set to -1 by the caller
3893 // returns 1 if found, *op_i is then set to referencer insn
3894 static int resolve_last_ref(int i, const struct parsed_opr *opr,
3895 int magic, int *op_i)
3897 struct label_ref *lr;
3900 if (ops[i].cc_scratch == magic)
3902 ops[i].cc_scratch = magic;
3905 if (g_labels[i] != NULL) {
3906 lr = &g_label_refs[i];
3907 for (; lr != NULL; lr = lr->next) {
3908 check_i(&ops[i], lr->i);
3909 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
3911 if (i > 0 && LAST_OP(i - 1))
3919 if (ops[i].cc_scratch == magic)
3921 ops[i].cc_scratch = magic;
3923 if (!is_opr_referenced(opr, &ops[i]))
3934 // find next instruction that reads opr
3935 // *op_i must be set to -1 by the caller
3936 // on return, *op_i is set to first referencer insn
3937 // returns 1 if exactly 1 referencer is found
3938 static int find_next_read(int i, int opcnt,
3939 const struct parsed_opr *opr, int magic, int *op_i)
3941 struct parsed_op *po;
3944 for (; i < opcnt; i++)
3946 if (ops[i].cc_scratch == magic)
3948 ops[i].cc_scratch = magic;
3951 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3952 if (po->btj != NULL) {
3954 for (j = 0; j < po->btj->count; j++) {
3955 check_i(po, po->btj->d[j].bt_i);
3956 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
3962 if (po->flags & OPF_RMD)
3964 check_i(po, po->bt_i);
3965 if (po->flags & OPF_CJMP) {
3966 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
3975 if (!is_opr_read(opr, po)) {
3976 if (is_opr_modified(opr, po)
3977 && (po->op == OP_CALL
3978 || ((po->flags & OPF_DATA)
3979 && po->operand[0].lmod == OPLM_DWORD)))
3984 if (po->flags & OPF_TAIL)
3999 static int try_resolve_const(int i, const struct parsed_opr *opr,
4000 int magic, unsigned int *val)
4005 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4008 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4011 *val = ops[i].operand[1].val;
4018 static struct parsed_proto *process_call_early(int i, int opcnt,
4021 struct parsed_op *po = &ops[i];
4022 struct parsed_proto *pp;
4028 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4032 // look for and make use of esp adjust
4034 if (!pp->is_stdcall && pp->argc_stack > 0)
4035 ret = scan_for_esp_adjust(i + 1, opcnt,
4036 pp->argc_stack * 4, &adj, &multipath, 0);
4038 if (pp->argc_stack > adj / 4)
4042 if (ops[ret].op == OP_POP) {
4043 for (j = 1; j < adj / 4; j++) {
4044 if (ops[ret + j].op != OP_POP
4045 || ops[ret + j].operand[0].reg != xCX)
4057 static struct parsed_proto *process_call(int i, int opcnt)
4059 struct parsed_op *po = &ops[i];
4060 const struct parsed_proto *pp_c;
4061 struct parsed_proto *pp;
4062 const char *tmpname;
4063 int call_i = -1, ref_i = -1;
4064 int adj = 0, multipath = 0;
4067 tmpname = opr_name(po, 0);
4072 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4074 if (!pp_c->is_func && !pp_c->is_fptr)
4075 ferr(po, "call to non-func: %s\n", pp_c->name);
4076 pp = proto_clone(pp_c);
4077 my_assert_not(pp, NULL);
4079 // not resolved just to single func
4082 switch (po->operand[0].type) {
4084 // we resolved this call and no longer need the register
4085 po->regmask_src &= ~(1 << po->operand[0].reg);
4087 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4088 && ops[call_i].operand[1].type == OPT_LABEL)
4090 // no other source users?
4091 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4093 if (ret == 1 && call_i == ref_i) {
4094 // and nothing uses it after us?
4096 find_next_read(i + 1, opcnt, &po->operand[0],
4097 i + opcnt * 11, &ref_i);
4099 // then also don't need the source mov
4100 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4112 pp = calloc(1, sizeof(*pp));
4113 my_assert_not(pp, NULL);
4116 ret = scan_for_esp_adjust(i + 1, opcnt,
4117 -1, &adj, &multipath, 0);
4118 if (ret < 0 || adj < 0) {
4119 if (!g_allow_regfunc)
4120 ferr(po, "non-__cdecl indirect call unhandled yet\n");
4121 pp->is_unresolved = 1;
4125 if (adj > ARRAY_SIZE(pp->arg))
4126 ferr(po, "esp adjust too large: %d\n", adj);
4127 pp->ret_type.name = strdup("int");
4128 pp->argc = pp->argc_stack = adj;
4129 for (arg = 0; arg < pp->argc; arg++)
4130 pp->arg[arg].type.name = strdup("int");
4135 // look for and make use of esp adjust
4138 if (!pp->is_stdcall && pp->argc_stack > 0) {
4139 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
4140 ret = scan_for_esp_adjust(i + 1, opcnt,
4141 adj_expect, &adj, &multipath, 0);
4144 if (pp->is_vararg) {
4145 if (adj / 4 < pp->argc_stack) {
4146 fnote(po, "(this call)\n");
4147 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
4148 adj, pp->argc_stack * 4);
4150 // modify pp to make it have varargs as normal args
4152 pp->argc += adj / 4 - pp->argc_stack;
4153 for (; arg < pp->argc; arg++) {
4154 pp->arg[arg].type.name = strdup("int");
4157 if (pp->argc > ARRAY_SIZE(pp->arg))
4158 ferr(po, "too many args for '%s'\n", tmpname);
4160 if (pp->argc_stack > adj / 4) {
4161 fnote(po, "(this call)\n");
4162 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
4163 tmpname, pp->argc_stack * 4, adj);
4166 scan_for_esp_adjust(i + 1, opcnt,
4167 pp->argc_stack * 4, &adj, &multipath, 1);
4169 else if (pp->is_vararg)
4170 ferr(po, "missing esp_adjust for vararg func '%s'\n",
4176 static int collect_call_args_early(struct parsed_op *po, int i,
4177 struct parsed_proto *pp, int *regmask)
4182 for (arg = 0; arg < pp->argc; arg++)
4183 if (pp->arg[arg].reg == NULL)
4186 // first see if it can be easily done
4187 for (j = i; j > 0 && arg < pp->argc; )
4189 if (g_labels[j] != NULL)
4193 if (ops[j].op == OP_CALL)
4195 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP)
4197 else if (ops[j].op == OP_POP)
4199 else if (ops[j].flags & OPF_CJMP)
4201 else if (ops[j].op == OP_PUSH) {
4202 if (ops[j].flags & (OPF_FARG|OPF_FARGNR))
4204 ret = scan_for_mod(&ops[j], j + 1, i, 1);
4208 if (pp->arg[arg].type.is_va_list)
4212 for (arg++; arg < pp->argc; arg++)
4213 if (pp->arg[arg].reg == NULL)
4222 for (arg = 0; arg < pp->argc; arg++)
4223 if (pp->arg[arg].reg == NULL)
4226 for (j = i; j > 0 && arg < pp->argc; )
4230 if (ops[j].op == OP_PUSH)
4232 ops[j].p_argnext = -1;
4233 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
4234 pp->arg[arg].datap = &ops[j];
4236 if (ops[j].operand[0].type == OPT_REG)
4237 *regmask |= 1 << ops[j].operand[0].reg;
4239 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4240 ops[j].flags &= ~OPF_RSAVE;
4243 for (arg++; arg < pp->argc; arg++)
4244 if (pp->arg[arg].reg == NULL)
4252 static int collect_call_args_r(struct parsed_op *po, int i,
4253 struct parsed_proto *pp, int *regmask, int *save_arg_vars,
4254 int *arg_grp, int arg, int magic, int need_op_saving, int may_reuse)
4256 struct parsed_proto *pp_tmp;
4257 struct parsed_op *po_tmp;
4258 struct label_ref *lr;
4259 int need_to_save_current;
4260 int arg_grp_current = 0;
4261 int save_args_seen = 0;
4269 ferr(po, "dead label encountered\n");
4273 for (; arg < pp->argc; arg++)
4274 if (pp->arg[arg].reg == NULL)
4276 magic = (magic & 0xffffff) | (arg << 24);
4278 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
4280 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
4281 if (ops[j].cc_scratch != magic) {
4282 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
4286 // ok: have already been here
4289 ops[j].cc_scratch = magic;
4291 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
4292 lr = &g_label_refs[j];
4293 if (lr->next != NULL)
4295 for (; lr->next; lr = lr->next) {
4296 check_i(&ops[j], lr->i);
4297 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4299 ret = collect_call_args_r(po, lr->i, pp, regmask, save_arg_vars,
4300 arg_grp, arg, magic, need_op_saving, may_reuse);
4305 check_i(&ops[j], lr->i);
4306 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4308 if (j > 0 && LAST_OP(j - 1)) {
4309 // follow last branch in reverse
4314 ret = collect_call_args_r(po, lr->i, pp, regmask, save_arg_vars,
4315 arg_grp, arg, magic, need_op_saving, may_reuse);
4321 if (ops[j].op == OP_CALL)
4323 if (pp->is_unresolved)
4328 ferr(po, "arg collect hit unparsed call '%s'\n",
4329 ops[j].operand[0].name);
4330 if (may_reuse && pp_tmp->argc_stack > 0)
4331 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
4332 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
4334 // esp adjust of 0 means we collected it before
4335 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
4336 && (ops[j].operand[1].type != OPT_CONST
4337 || ops[j].operand[1].val != 0))
4339 if (pp->is_unresolved)
4342 fnote(po, "(this call)\n");
4343 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
4344 arg, pp->argc, ops[j].operand[1].val);
4346 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
4348 if (pp->is_unresolved)
4351 fnote(po, "(this call)\n");
4352 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
4354 else if (ops[j].flags & OPF_CJMP)
4356 if (pp->is_unresolved)
4361 else if (ops[j].op == OP_PUSH
4362 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
4364 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
4367 ops[j].p_argnext = -1;
4368 po_tmp = pp->arg[arg].datap;
4370 ops[j].p_argnext = po_tmp - ops;
4371 pp->arg[arg].datap = &ops[j];
4373 need_to_save_current = 0;
4376 if (ops[j].operand[0].type == OPT_REG)
4377 reg = ops[j].operand[0].reg;
4379 if (!need_op_saving) {
4380 ret = scan_for_mod(&ops[j], j + 1, i, 1);
4381 need_to_save_current = (ret >= 0);
4383 if (need_op_saving || need_to_save_current) {
4384 // mark this push as one that needs operand saving
4385 ops[j].flags &= ~OPF_RMD;
4386 if (ops[j].p_argnum == 0) {
4387 ops[j].p_argnum = arg + 1;
4388 save_args |= 1 << arg;
4390 else if (ops[j].p_argnum < arg + 1) {
4391 // XXX: might kill valid var..
4392 //*save_arg_vars &= ~(1 << (ops[j].p_argnum - 1));
4393 ops[j].p_argnum = arg + 1;
4394 save_args |= 1 << arg;
4397 if (save_args_seen & (1 << (ops[j].p_argnum - 1))) {
4400 if (arg_grp_current >= MAX_ARG_GRP)
4401 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
4402 ops[j].p_argnum, pp->name);
4405 else if (ops[j].p_argnum == 0)
4406 ops[j].flags |= OPF_RMD;
4408 // some PUSHes are reused by different calls on other branches,
4409 // but that can't happen if we didn't branch, so they
4410 // can be removed from future searches (handles nested calls)
4412 ops[j].flags |= OPF_FARGNR;
4414 ops[j].flags |= OPF_FARG;
4415 ops[j].flags &= ~OPF_RSAVE;
4417 // check for __VALIST
4418 if (!pp->is_unresolved && g_func_pp != NULL
4419 && pp->arg[arg].type.is_va_list)
4422 ret = resolve_origin(j, &ops[j].operand[0],
4423 magic + 1, &k, NULL);
4424 if (ret == 1 && k >= 0)
4426 if (ops[k].op == OP_LEA) {
4427 if (!g_func_pp->is_vararg)
4428 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
4431 snprintf(buf, sizeof(buf), "arg_%X",
4432 g_func_pp->argc_stack * 4);
4433 if (strstr(ops[k].operand[1].name, buf)
4434 || strstr(ops[k].operand[1].name, "arglist"))
4436 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
4437 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
4438 save_args &= ~(1 << arg);
4442 ferr(&ops[k], "va_list arg detection failed\n");
4444 // check for va_list from g_func_pp arg too
4445 else if (ops[k].op == OP_MOV
4446 && is_stack_access(&ops[k], &ops[k].operand[1]))
4448 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
4449 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
4451 ops[k].flags |= OPF_RMD | OPF_DONE;
4452 ops[j].flags |= OPF_RMD;
4453 ops[j].p_argpass = ret + 1;
4454 save_args &= ~(1 << arg);
4461 *save_arg_vars |= save_args;
4463 // tracking reg usage
4465 *regmask |= 1 << reg;
4468 if (!pp->is_unresolved) {
4470 for (; arg < pp->argc; arg++)
4471 if (pp->arg[arg].reg == NULL)
4474 magic = (magic & 0xffffff) | (arg << 24);
4477 if (ops[j].p_arggrp > arg_grp_current) {
4479 arg_grp_current = ops[j].p_arggrp;
4481 if (ops[j].p_argnum > 0)
4482 save_args_seen |= 1 << (ops[j].p_argnum - 1);
4485 if (arg < pp->argc) {
4486 ferr(po, "arg collect failed for '%s': %d/%d\n",
4487 pp->name, arg, pp->argc);
4491 if (arg_grp_current > *arg_grp)
4492 *arg_grp = arg_grp_current;
4497 static int collect_call_args(struct parsed_op *po, int i,
4498 struct parsed_proto *pp, int *regmask, int *save_arg_vars,
4501 // arg group is for cases when pushes for
4502 // multiple funcs are going on
4503 struct parsed_op *po_tmp;
4504 int save_arg_vars_current = 0;
4509 ret = collect_call_args_r(po, i, pp, regmask,
4510 &save_arg_vars_current, &arg_grp, 0, magic, 0, 0);
4515 // propagate arg_grp
4516 for (a = 0; a < pp->argc; a++) {
4517 if (pp->arg[a].reg != NULL)
4520 po_tmp = pp->arg[a].datap;
4521 while (po_tmp != NULL) {
4522 po_tmp->p_arggrp = arg_grp;
4523 if (po_tmp->p_argnext > 0)
4524 po_tmp = &ops[po_tmp->p_argnext];
4530 save_arg_vars[arg_grp] |= save_arg_vars_current;
4532 if (pp->is_unresolved) {
4534 pp->argc_stack += ret;
4535 for (a = 0; a < pp->argc; a++)
4536 if (pp->arg[a].type.name == NULL)
4537 pp->arg[a].type.name = strdup("int");
4543 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
4544 int regmask_now, int *regmask,
4545 int regmask_save_now, int *regmask_save,
4546 int *regmask_init, int regmask_arg)
4548 struct parsed_op *po;
4557 for (; i < opcnt; i++)
4560 if (cbits[i >> 3] & (1 << (i & 7)))
4562 cbits[i >> 3] |= (1 << (i & 7));
4564 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4565 if (po->flags & (OPF_RMD|OPF_DONE))
4567 if (po->btj != NULL) {
4568 for (j = 0; j < po->btj->count; j++) {
4569 check_i(po, po->btj->d[j].bt_i);
4570 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
4571 regmask_now, regmask, regmask_save_now, regmask_save,
4572 regmask_init, regmask_arg);
4577 check_i(po, po->bt_i);
4578 if (po->flags & OPF_CJMP)
4579 reg_use_pass(po->bt_i, opcnt, cbits,
4580 regmask_now, regmask, regmask_save_now, regmask_save,
4581 regmask_init, regmask_arg);
4587 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
4588 && !g_func_pp->is_userstack
4589 && po->operand[0].type == OPT_REG)
4591 reg = po->operand[0].reg;
4592 ferr_assert(po, reg >= 0);
4595 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
4596 if (regmask_now & (1 << reg)) {
4597 already_saved = regmask_save_now & (1 << reg);
4598 flags_set = OPF_RSAVE | OPF_DONE;
4601 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0);
4603 scan_for_pop(i + 1, opcnt, i + opcnt * 4, reg, 0, flags_set);
4606 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
4608 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
4613 ferr_assert(po, !already_saved);
4614 po->flags |= flags_set;
4616 if (regmask_now & (1 << reg)) {
4617 regmask_save_now |= (1 << reg);
4618 *regmask_save |= regmask_save_now;
4623 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
4624 reg = po->operand[0].reg;
4625 ferr_assert(po, reg >= 0);
4627 if (regmask_save_now & (1 << reg))
4628 regmask_save_now &= ~(1 << reg);
4630 regmask_now &= ~(1 << reg);
4633 else if (po->op == OP_CALL) {
4634 if ((po->regmask_dst & (1 << xAX))
4635 && !(po->regmask_dst & (1 << xDX)))
4637 if (po->flags & OPF_TAIL)
4638 // don't need eax, will do "return f();" or "f(); return;"
4639 po->regmask_dst &= ~(1 << xAX);
4641 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
4643 find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
4646 po->regmask_dst &= ~(1 << xAX);
4651 if (po->flags & OPF_NOREGS)
4654 if (po->flags & OPF_FPUSH) {
4655 if (regmask_now & mxST1)
4656 ferr(po, "TODO: FPUSH on active ST1\n");
4657 if (regmask_now & mxST0)
4658 po->flags |= OPF_FSHIFT;
4659 mask = mxST0 | mxST1;
4660 regmask_now = (regmask_now & ~mask) | ((regmask_now & mxST0) << 1);
4663 // if incomplete register is used, clear it on init to avoid
4664 // later use of uninitialized upper part in some situations
4665 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
4666 && po->operand[0].lmod != OPLM_DWORD)
4668 reg = po->operand[0].reg;
4669 ferr_assert(po, reg >= 0);
4671 if (!(regmask_now & (1 << reg)))
4672 *regmask_init |= 1 << reg;
4675 regmask_op = po->regmask_src | po->regmask_dst;
4677 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
4678 regmask_new &= ~(1 << xSP);
4679 if (g_bp_frame && !(po->flags & OPF_EBP_S))
4680 regmask_new &= ~(1 << xBP);
4682 if (po->op == OP_CALL) {
4683 // allow fastcall calls from anywhere, calee may be also sitting
4684 // in some fastcall table even when it's not using reg args
4685 if (regmask_new & po->regmask_src & (1 << xCX)) {
4686 *regmask_init |= (1 << xCX);
4687 regmask_now |= (1 << xCX);
4688 regmask_new &= ~(1 << xCX);
4690 if (regmask_new & po->regmask_src & (1 << xDX)) {
4691 *regmask_init |= (1 << xDX);
4692 regmask_now |= (1 << xDX);
4693 regmask_new &= ~(1 << xDX);
4697 if (regmask_new != 0)
4698 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
4700 if (regmask_op & (1 << xBP)) {
4701 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
4702 if (po->regmask_dst & (1 << xBP))
4703 // compiler decided to drop bp frame and use ebp as scratch
4704 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
4706 regmask_op &= ~(1 << xBP);
4710 regmask_now |= regmask_op;
4711 *regmask |= regmask_now;
4714 if (po->flags & OPF_FPOP) {
4715 mask = mxST0 | mxST1;
4716 if (!(regmask_now & mask))
4717 ferr(po, "float pop on empty stack?\n");
4718 if (regmask_now & mxST1)
4719 po->flags |= OPF_FSHIFT;
4720 regmask_now = (regmask_now & ~mask) | ((regmask_now & mxST1) >> 1);
4723 if (po->flags & OPF_TAIL) {
4724 if (regmask_now & (mxST0 | mxST1))
4725 ferr(po, "float regs on tail: %x\n", regmask_now);
4731 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
4735 for (i = 0; i < pp->argc; i++)
4736 if (pp->arg[i].reg == NULL)
4740 memmove(&pp->arg[i + 1], &pp->arg[i],
4741 sizeof(pp->arg[0]) * pp->argc_stack);
4742 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
4743 pp->arg[i].reg = strdup(reg);
4744 pp->arg[i].type.name = strdup("int");
4749 static void output_std_flags(FILE *fout, struct parsed_op *po,
4750 int *pfomask, const char *dst_opr_text)
4752 if (*pfomask & (1 << PFO_Z)) {
4753 fprintf(fout, "\n cond_z = (%s%s == 0);",
4754 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
4755 *pfomask &= ~(1 << PFO_Z);
4757 if (*pfomask & (1 << PFO_S)) {
4758 fprintf(fout, "\n cond_s = (%s%s < 0);",
4759 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
4760 *pfomask &= ~(1 << PFO_S);
4765 OPP_FORCE_NORETURN = (1 << 0),
4766 OPP_SIMPLE_ARGS = (1 << 1),
4767 OPP_ALIGN = (1 << 2),
4770 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
4773 const char *cconv = "";
4775 if (pp->is_fastcall)
4776 cconv = "__fastcall ";
4777 else if (pp->is_stdcall && pp->argc_reg == 0)
4778 cconv = "__stdcall ";
4780 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
4782 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
4783 fprintf(fout, "noreturn ");
4786 static void output_pp(FILE *fout, const struct parsed_proto *pp,
4791 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
4795 output_pp_attrs(fout, pp, flags);
4798 fprintf(fout, "%s", pp->name);
4803 for (i = 0; i < pp->argc; i++) {
4805 fprintf(fout, ", ");
4806 if (pp->arg[i].fptr != NULL && !(flags & OPP_SIMPLE_ARGS)) {
4808 output_pp(fout, pp->arg[i].fptr, 0);
4810 else if (pp->arg[i].type.is_retreg) {
4811 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
4814 fprintf(fout, "%s", pp->arg[i].type.name);
4816 fprintf(fout, " a%d", i + 1);
4819 if (pp->is_vararg) {
4821 fprintf(fout, ", ");
4822 fprintf(fout, "...");
4827 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
4833 snprintf(buf1, sizeof(buf1), "%d", grp);
4834 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
4839 static void gen_x_cleanup(int opcnt);
4841 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
4843 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
4844 struct parsed_opr *last_arith_dst = NULL;
4845 char buf1[256], buf2[256], buf3[256], cast[64];
4846 struct parsed_proto *pp, *pp_tmp;
4847 struct parsed_data *pd;
4849 int save_arg_vars[MAX_ARG_GRP] = { 0, };
4850 unsigned char cbits[MAX_OPS / 8];
4852 int need_tmp_var = 0;
4855 int label_pending = 0;
4856 int regmask_save = 0; // regs saved/restored in this func
4857 int regmask_arg; // regs from this function args (fastcall, etc)
4858 int regmask_ret; // regs needed on ret
4859 int regmask_now; // temp
4860 int regmask_init = 0; // regs that need zero initialization
4861 int regmask_pp = 0; // regs used in complex push-pop graph
4862 int regmask = 0; // used regs
4871 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
4872 g_stack_frame_used = 0;
4874 g_func_pp = proto_parse(fhdr, funcn, 0);
4875 if (g_func_pp == NULL)
4876 ferr(ops, "proto_parse failed for '%s'\n", funcn);
4878 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
4879 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
4881 if (g_func_pp->has_retreg) {
4882 for (arg = 0; arg < g_func_pp->argc; arg++) {
4883 if (g_func_pp->arg[arg].type.is_retreg) {
4884 reg = char_array_i(regs_r32,
4885 ARRAY_SIZE(regs_r32), g_func_pp->arg[arg].reg);
4886 ferr_assert(ops, reg >= 0);
4887 regmask_ret |= 1 << reg;
4893 // - resolve all branches
4894 // - parse calls with labels
4895 resolve_branches_parse_calls(opcnt);
4898 // - handle ebp/esp frame, remove ops related to it
4899 scan_prologue_epilogue(opcnt);
4902 // - remove dead labels
4903 // - set regs needed at ret
4904 for (i = 0; i < opcnt; i++)
4906 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
4911 if (ops[i].op == OP_RET)
4912 ops[i].regmask_src |= regmask_ret;
4916 // - process trivial calls
4917 for (i = 0; i < opcnt; i++)
4920 if (po->flags & (OPF_RMD|OPF_DONE))
4923 if (po->op == OP_CALL)
4925 pp = process_call_early(i, opcnt, &j);
4927 if (!(po->flags & OPF_ATAIL))
4928 // since we know the args, try to collect them
4929 if (collect_call_args_early(po, i, pp, ®mask) != 0)
4935 // commit esp adjust
4936 if (ops[j].op != OP_POP)
4937 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
4939 for (l = 0; l < pp->argc_stack; l++)
4940 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
4944 if (strstr(pp->ret_type.name, "int64"))
4947 po->flags |= OPF_DONE;
4953 // - process calls, stage 2
4954 // - handle some push/pop pairs
4955 // - scan for STD/CLD, propagate DF
4956 for (i = 0; i < opcnt; i++)
4959 if (po->flags & OPF_RMD)
4962 if (po->op == OP_CALL)
4964 if (!(po->flags & OPF_DONE)) {
4965 pp = process_call(i, opcnt);
4967 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
4968 // since we know the args, collect them
4969 collect_call_args(po, i, pp, ®mask, save_arg_vars,
4972 // for unresolved, collect after other passes
4976 ferr_assert(po, pp != NULL);
4978 po->regmask_src |= get_pp_arg_regmask_src(pp);
4979 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
4981 if (po->regmask_dst & mxST0)
4982 po->flags |= OPF_FPUSH;
4984 if (strstr(pp->ret_type.name, "int64"))
4990 if (po->flags & OPF_DONE)
4993 if (po->op == OP_PUSH && !(po->flags & OPF_FARG)
4994 && !(po->flags & OPF_RSAVE) && po->operand[0].type == OPT_CONST)
4996 scan_for_pop_const(i, opcnt, i + opcnt * 12);
4998 else if (po->op == OP_POP)
4999 scan_pushes_for_pop(i, opcnt, ®mask_pp);
5000 else if (po->op == OP_STD) {
5001 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
5002 scan_propagate_df(i + 1, opcnt);
5007 // - find POPs for PUSHes, rm both
5008 // - scan for all used registers
5009 memset(cbits, 0, sizeof(cbits));
5010 reg_use_pass(0, opcnt, cbits, 0, ®mask,
5011 0, ®mask_save, ®mask_init, regmask_arg);
5014 // - find flag set ops for their users
5015 // - do unresolved calls
5016 // - declare indirect functions
5017 for (i = 0; i < opcnt; i++)
5020 if (po->flags & (OPF_RMD|OPF_DONE))
5023 if (po->flags & OPF_CC)
5025 int setters[16], cnt = 0, branched = 0;
5027 ret = scan_for_flag_set(i, i + opcnt * 6,
5028 &branched, setters, &cnt);
5029 if (ret < 0 || cnt <= 0)
5030 ferr(po, "unable to trace flag setter(s)\n");
5031 if (cnt > ARRAY_SIZE(setters))
5032 ferr(po, "too many flag setters\n");
5034 for (j = 0; j < cnt; j++)
5036 tmp_op = &ops[setters[j]]; // flag setter
5039 // to get nicer code, we try to delay test and cmp;
5040 // if we can't because of operand modification, or if we
5041 // have arith op, or branch, make it calculate flags explicitly
5042 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
5044 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
5045 pfomask = 1 << po->pfo;
5047 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
5048 pfomask = 1 << po->pfo;
5051 // see if we'll be able to handle based on op result
5052 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
5053 && po->pfo != PFO_Z && po->pfo != PFO_S
5054 && po->pfo != PFO_P)
5056 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
5058 pfomask = 1 << po->pfo;
5061 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
5062 propagate_lmod(tmp_op, &tmp_op->operand[0],
5063 &tmp_op->operand[1]);
5064 if (tmp_op->operand[0].lmod == OPLM_DWORD)
5069 tmp_op->pfomask |= pfomask;
5070 cond_vars |= pfomask;
5072 // note: may overwrite, currently not a problem
5076 if (po->op == OP_RCL || po->op == OP_RCR
5077 || po->op == OP_ADC || po->op == OP_SBB)
5078 cond_vars |= 1 << PFO_C;
5081 if (po->op == OP_CMPS || po->op == OP_SCAS) {
5082 cond_vars |= 1 << PFO_Z;
5084 else if (po->op == OP_MUL
5085 || (po->op == OP_IMUL && po->operand_cnt == 1))
5087 if (po->operand[0].lmod == OPLM_DWORD)
5090 else if (po->op == OP_CALL) {
5091 // note: resolved non-reg calls are OPF_DONE already
5093 ferr_assert(po, pp != NULL);
5095 if (pp->is_unresolved) {
5096 int regmask_stack = 0;
5097 collect_call_args(po, i, pp, ®mask, save_arg_vars,
5100 // this is pretty rough guess:
5101 // see ecx and edx were pushed (and not their saved versions)
5102 for (arg = 0; arg < pp->argc; arg++) {
5103 if (pp->arg[arg].reg != NULL)
5106 tmp_op = pp->arg[arg].datap;
5108 ferr(po, "parsed_op missing for arg%d\n", arg);
5109 if (tmp_op->p_argnum == 0 && tmp_op->operand[0].type == OPT_REG)
5110 regmask_stack |= 1 << tmp_op->operand[0].reg;
5113 if (!((regmask_stack & (1 << xCX))
5114 && (regmask_stack & (1 << xDX))))
5116 if (pp->argc_stack != 0
5117 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
5119 pp_insert_reg_arg(pp, "ecx");
5120 pp->is_fastcall = 1;
5121 regmask_init |= 1 << xCX;
5122 regmask |= 1 << xCX;
5124 if (pp->argc_stack != 0
5125 || ((regmask | regmask_arg) & (1 << xDX)))
5127 pp_insert_reg_arg(pp, "edx");
5128 regmask_init |= 1 << xDX;
5129 regmask |= 1 << xDX;
5133 // note: __cdecl doesn't fall into is_unresolved category
5134 if (pp->argc_stack > 0)
5138 else if (po->op == OP_MOV && po->operand[0].pp != NULL
5139 && po->operand[1].pp != NULL)
5141 // <var> = offset <something>
5142 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
5143 && !IS_START(po->operand[1].name, "off_"))
5145 if (!po->operand[0].pp->is_fptr)
5146 ferr(po, "%s not declared as fptr when it should be\n",
5147 po->operand[0].name);
5148 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
5149 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
5150 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
5151 fnote(po, "var: %s\n", buf1);
5152 fnote(po, "func: %s\n", buf2);
5153 ferr(po, "^ mismatch\n");
5157 else if (po->op == OP_DIV || po->op == OP_IDIV) {
5158 if (po->operand[0].lmod == OPLM_DWORD) {
5159 // 32bit division is common, look for it
5160 if (po->op == OP_DIV)
5161 ret = scan_for_reg_clear(i, xDX);
5163 ret = scan_for_cdq_edx(i);
5165 po->flags |= OPF_32BIT;
5172 else if (po->op == OP_CLD)
5173 po->flags |= OPF_RMD | OPF_DONE;
5174 else if (po->op == OPP_FTOL) {
5175 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
5177 find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
5179 po->flags |= OPF_32BIT;
5182 if (po->op == OP_RCL || po->op == OP_RCR || po->op == OP_XCHG)
5186 // output starts here
5188 // define userstack size
5189 if (g_func_pp->is_userstack) {
5190 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
5191 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
5192 fprintf(fout, "#endif\n");
5195 // the function itself
5196 ferr_assert(ops, !g_func_pp->is_fptr);
5197 output_pp(fout, g_func_pp,
5198 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
5199 fprintf(fout, "\n{\n");
5201 // declare indirect functions
5202 for (i = 0; i < opcnt; i++) {
5204 if (po->flags & OPF_RMD)
5207 if (po->op == OP_CALL) {
5210 ferr(po, "NULL pp\n");
5212 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
5213 if (pp->name[0] != 0) {
5214 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
5215 memcpy(pp->name, "i_", 2);
5217 // might be declared already
5219 for (j = 0; j < i; j++) {
5220 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
5221 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
5231 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
5234 output_pp(fout, pp, OPP_SIMPLE_ARGS);
5235 fprintf(fout, ";\n");
5240 // output LUTs/jumptables
5241 for (i = 0; i < g_func_pd_cnt; i++) {
5243 fprintf(fout, " static const ");
5244 if (pd->type == OPT_OFFSET) {
5245 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
5247 for (j = 0; j < pd->count; j++) {
5249 fprintf(fout, ", ");
5250 fprintf(fout, "&&%s", pd->d[j].u.label);
5254 fprintf(fout, "%s %s[] =\n { ",
5255 lmod_type_u(ops, pd->lmod), pd->label);
5257 for (j = 0; j < pd->count; j++) {
5259 fprintf(fout, ", ");
5260 fprintf(fout, "%u", pd->d[j].u.val);
5263 fprintf(fout, " };\n");
5267 // declare stack frame, va_arg
5269 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
5270 if (g_func_lmods & (1 << OPLM_WORD))
5271 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
5272 if (g_func_lmods & (1 << OPLM_BYTE))
5273 fprintf(fout, " u8 b[%d];", g_stack_fsz);
5274 if (g_func_lmods & (1 << OPLM_QWORD))
5275 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
5276 fprintf(fout, " } sf;\n");
5280 if (g_func_pp->is_userstack) {
5281 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
5282 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
5286 if (g_func_pp->is_vararg) {
5287 fprintf(fout, " va_list ap;\n");
5291 // declare arg-registers
5292 for (i = 0; i < g_func_pp->argc; i++) {
5293 if (g_func_pp->arg[i].reg != NULL) {
5294 reg = char_array_i(regs_r32,
5295 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
5296 if (regmask & (1 << reg)) {
5297 if (g_func_pp->arg[i].type.is_retreg)
5298 fprintf(fout, " u32 %s = *r_%s;\n",
5299 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
5301 fprintf(fout, " u32 %s = (u32)a%d;\n",
5302 g_func_pp->arg[i].reg, i + 1);
5305 if (g_func_pp->arg[i].type.is_retreg)
5306 ferr(ops, "retreg '%s' is unused?\n",
5307 g_func_pp->arg[i].reg);
5308 fprintf(fout, " // %s = a%d; // unused\n",
5309 g_func_pp->arg[i].reg, i + 1);
5315 // declare normal registers
5316 regmask_now = regmask & ~regmask_arg;
5317 regmask_now &= ~(1 << xSP);
5318 if (regmask_now & 0x00ff) {
5319 for (reg = 0; reg < 8; reg++) {
5320 if (regmask_now & (1 << reg)) {
5321 fprintf(fout, " u32 %s", regs_r32[reg]);
5322 if (regmask_init & (1 << reg))
5323 fprintf(fout, " = 0");
5324 fprintf(fout, ";\n");
5330 if (regmask_now & 0xff00) {
5331 for (reg = 8; reg < 16; reg++) {
5332 if (regmask_now & (1 << reg)) {
5333 fprintf(fout, " mmxr %s", regs_r32[reg]);
5334 if (regmask_init & (1 << reg))
5335 fprintf(fout, " = { 0, }");
5336 fprintf(fout, ";\n");
5342 if (regmask_now & 0xff0000) {
5343 for (reg = 16; reg < 24; reg++) {
5344 if (regmask_now & (1 << reg)) {
5345 fprintf(fout, " double f_st%d", reg - 16);
5346 if (regmask_init & (1 << reg))
5347 fprintf(fout, " = 0");
5348 fprintf(fout, ";\n");
5355 for (reg = 0; reg < 8; reg++) {
5356 if (regmask_save & (1 << reg)) {
5357 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
5363 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
5364 if (save_arg_vars[i] == 0)
5366 for (reg = 0; reg < 32; reg++) {
5367 if (save_arg_vars[i] & (1 << reg)) {
5368 fprintf(fout, " u32 %s;\n",
5369 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
5375 // declare push-pop temporaries
5377 for (reg = 0; reg < 8; reg++) {
5378 if (regmask_pp & (1 << reg)) {
5379 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
5386 for (i = 0; i < 8; i++) {
5387 if (cond_vars & (1 << i)) {
5388 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
5395 fprintf(fout, " u32 tmp;\n");
5400 fprintf(fout, " u64 tmp64;\n");
5405 fprintf(fout, "\n");
5407 if (g_func_pp->is_vararg) {
5408 if (g_func_pp->argc_stack == 0)
5409 ferr(ops, "vararg func without stack args?\n");
5410 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
5414 for (i = 0; i < opcnt; i++)
5416 if (g_labels[i] != NULL) {
5417 fprintf(fout, "\n%s:\n", g_labels[i]);
5420 delayed_flag_op = NULL;
5421 last_arith_dst = NULL;
5425 if (po->flags & OPF_RMD)
5430 #define assert_operand_cnt(n_) \
5431 if (po->operand_cnt != n_) \
5432 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
5434 // conditional/flag using op?
5435 if (po->flags & OPF_CC)
5441 // we go through all this trouble to avoid using parsed_flag_op,
5442 // which makes generated code much nicer
5443 if (delayed_flag_op != NULL)
5445 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
5446 po->pfo, po->pfo_inv);
5449 else if (last_arith_dst != NULL
5450 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
5451 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
5454 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
5455 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
5456 last_arith_dst->lmod, buf3);
5459 else if (tmp_op != NULL) {
5460 // use preprocessed flag calc results
5461 if (!(tmp_op->pfomask & (1 << po->pfo)))
5462 ferr(po, "not prepared for pfo %d\n", po->pfo);
5464 // note: pfo_inv was not yet applied
5465 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
5466 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
5469 ferr(po, "all methods of finding comparison failed\n");
5472 if (po->flags & OPF_JMP) {
5473 fprintf(fout, " if %s", buf1);
5475 else if (po->op == OP_RCL || po->op == OP_RCR
5476 || po->op == OP_ADC || po->op == OP_SBB)
5479 fprintf(fout, " cond_%s = %s;\n",
5480 parsed_flag_op_names[po->pfo], buf1);
5482 else if (po->flags & OPF_DATA) { // SETcc
5483 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
5484 fprintf(fout, " %s = %s;", buf2, buf1);
5487 ferr(po, "unhandled conditional op\n");
5491 pfomask = po->pfomask;
5493 if (po->flags & (OPF_REPZ|OPF_REPNZ)) {
5494 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
5495 ret = try_resolve_const(i, &opr, opcnt * 7 + i, &uval);
5497 if (ret != 1 || uval == 0) {
5498 // we need initial flags for ecx=0 case..
5499 if (i > 0 && ops[i - 1].op == OP_XOR
5500 && IS(ops[i - 1].operand[0].name,
5501 ops[i - 1].operand[1].name))
5503 fprintf(fout, " cond_z = ");
5504 if (pfomask & (1 << PFO_C))
5505 fprintf(fout, "cond_c = ");
5506 fprintf(fout, "0;\n");
5508 else if (last_arith_dst != NULL) {
5509 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
5510 out_test_for_cc(buf1, sizeof(buf1), po, PFO_Z, 0,
5511 last_arith_dst->lmod, buf3);
5512 fprintf(fout, " cond_z = %s;\n", buf1);
5515 ferr(po, "missing initial ZF\n");
5522 assert_operand_cnt(2);
5523 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5524 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5525 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
5526 fprintf(fout, " %s = %s;", buf1,
5527 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5532 assert_operand_cnt(2);
5533 po->operand[1].lmod = OPLM_DWORD; // always
5534 fprintf(fout, " %s = %s;",
5535 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5536 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5541 assert_operand_cnt(2);
5542 fprintf(fout, " %s = %s;",
5543 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5544 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5548 assert_operand_cnt(2);
5549 switch (po->operand[1].lmod) {
5551 strcpy(buf3, "(s8)");
5554 strcpy(buf3, "(s16)");
5557 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
5559 fprintf(fout, " %s = %s;",
5560 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5561 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5566 assert_operand_cnt(2);
5567 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5568 fprintf(fout, " tmp = %s;",
5569 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
5570 fprintf(fout, " %s = %s;",
5571 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5572 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5573 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
5574 fprintf(fout, " %s = %stmp;",
5575 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
5576 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
5577 snprintf(g_comment, sizeof(g_comment), "xchg");
5581 assert_operand_cnt(1);
5582 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5583 fprintf(fout, " %s = ~%s;", buf1, buf1);
5587 assert_operand_cnt(2);
5588 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5589 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
5590 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
5591 strcpy(g_comment, "xlat");
5595 assert_operand_cnt(2);
5596 fprintf(fout, " %s = (s32)%s >> 31;",
5597 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5598 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5599 strcpy(g_comment, "cdq");
5603 if (po->flags & OPF_REP) {
5604 assert_operand_cnt(3);
5609 assert_operand_cnt(2);
5610 fprintf(fout, " %s = %sesi; esi %c= %d;",
5611 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
5612 lmod_cast_u_ptr(po, po->operand[1].lmod),
5613 (po->flags & OPF_DF) ? '-' : '+',
5614 lmod_bytes(po, po->operand[1].lmod));
5615 strcpy(g_comment, "lods");
5620 if (po->flags & OPF_REP) {
5621 assert_operand_cnt(3);
5622 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
5623 (po->flags & OPF_DF) ? '-' : '+',
5624 lmod_bytes(po, po->operand[1].lmod));
5625 fprintf(fout, " %sedi = eax;",
5626 lmod_cast_u_ptr(po, po->operand[1].lmod));
5627 strcpy(g_comment, "rep stos");
5630 assert_operand_cnt(2);
5631 fprintf(fout, " %sedi = eax; edi %c= %d;",
5632 lmod_cast_u_ptr(po, po->operand[1].lmod),
5633 (po->flags & OPF_DF) ? '-' : '+',
5634 lmod_bytes(po, po->operand[1].lmod));
5635 strcpy(g_comment, "stos");
5640 j = lmod_bytes(po, po->operand[0].lmod);
5641 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
5642 l = (po->flags & OPF_DF) ? '-' : '+';
5643 if (po->flags & OPF_REP) {
5644 assert_operand_cnt(3);
5646 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
5649 " %sedi = %sesi;", buf1, buf1);
5650 strcpy(g_comment, "rep movs");
5653 assert_operand_cnt(2);
5654 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
5655 buf1, buf1, l, j, l, j);
5656 strcpy(g_comment, "movs");
5661 // repe ~ repeat while ZF=1
5662 j = lmod_bytes(po, po->operand[0].lmod);
5663 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
5664 l = (po->flags & OPF_DF) ? '-' : '+';
5665 if (po->flags & OPF_REP) {
5666 assert_operand_cnt(3);
5668 " for (; ecx != 0; ecx--) {\n");
5669 if (pfomask & (1 << PFO_C)) {
5672 " cond_c = %sesi < %sedi;\n", buf1, buf1);
5673 pfomask &= ~(1 << PFO_C);
5676 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
5677 buf1, buf1, l, j, l, j);
5679 " if (cond_z %s 0) break;\n",
5680 (po->flags & OPF_REPZ) ? "==" : "!=");
5683 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
5684 (po->flags & OPF_REPZ) ? "e" : "ne");
5687 assert_operand_cnt(2);
5689 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
5690 buf1, buf1, l, j, l, j);
5691 strcpy(g_comment, "cmps");
5693 pfomask &= ~(1 << PFO_Z);
5694 last_arith_dst = NULL;
5695 delayed_flag_op = NULL;
5699 // only does ZF (for now)
5700 // repe ~ repeat while ZF=1
5701 j = lmod_bytes(po, po->operand[1].lmod);
5702 l = (po->flags & OPF_DF) ? '-' : '+';
5703 if (po->flags & OPF_REP) {
5704 assert_operand_cnt(3);
5706 " for (; ecx != 0; ecx--) {\n");
5708 " cond_z = (%seax == %sedi); edi %c= %d;\n",
5709 lmod_cast_u(po, po->operand[1].lmod),
5710 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
5712 " if (cond_z %s 0) break;\n",
5713 (po->flags & OPF_REPZ) ? "==" : "!=");
5716 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
5717 (po->flags & OPF_REPZ) ? "e" : "ne");
5720 assert_operand_cnt(2);
5721 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
5722 lmod_cast_u(po, po->operand[1].lmod),
5723 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
5724 strcpy(g_comment, "scas");
5726 pfomask &= ~(1 << PFO_Z);
5727 last_arith_dst = NULL;
5728 delayed_flag_op = NULL;
5731 // arithmetic w/flags
5733 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
5734 goto dualop_arith_const;
5735 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5739 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5740 if (po->operand[1].type == OPT_CONST) {
5741 j = lmod_bytes(po, po->operand[0].lmod);
5742 if (((1ull << j * 8) - 1) == po->operand[1].val)
5743 goto dualop_arith_const;
5748 assert_operand_cnt(2);
5749 fprintf(fout, " %s %s= %s;",
5750 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5752 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5753 output_std_flags(fout, po, &pfomask, buf1);
5754 last_arith_dst = &po->operand[0];
5755 delayed_flag_op = NULL;
5759 // and 0, or ~0 used instead mov
5760 assert_operand_cnt(2);
5761 fprintf(fout, " %s = %s;",
5762 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5763 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5764 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
5765 output_std_flags(fout, po, &pfomask, buf1);
5766 last_arith_dst = &po->operand[0];
5767 delayed_flag_op = NULL;
5772 assert_operand_cnt(2);
5773 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5774 if (pfomask & (1 << PFO_C)) {
5775 if (po->operand[1].type == OPT_CONST) {
5776 l = lmod_bytes(po, po->operand[0].lmod) * 8;
5777 j = po->operand[1].val;
5780 if (po->op == OP_SHL)
5784 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
5788 ferr(po, "zero shift?\n");
5792 pfomask &= ~(1 << PFO_C);
5794 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
5795 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5796 if (po->operand[1].type != OPT_CONST)
5797 fprintf(fout, " & 0x1f");
5799 output_std_flags(fout, po, &pfomask, buf1);
5800 last_arith_dst = &po->operand[0];
5801 delayed_flag_op = NULL;
5805 assert_operand_cnt(2);
5806 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5807 fprintf(fout, " %s = %s%s >> %s;", buf1,
5808 lmod_cast_s(po, po->operand[0].lmod), buf1,
5809 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5810 output_std_flags(fout, po, &pfomask, buf1);
5811 last_arith_dst = &po->operand[0];
5812 delayed_flag_op = NULL;
5817 assert_operand_cnt(3);
5818 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5819 l = lmod_bytes(po, po->operand[0].lmod) * 8;
5820 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
5821 if (po->operand[2].type != OPT_CONST) {
5822 // no handling for "undefined" case, hopefully not needed
5823 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
5826 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
5827 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5828 if (po->op == OP_SHLD) {
5829 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
5830 buf1, buf3, buf1, buf2, l, buf3);
5831 strcpy(g_comment, "shld");
5834 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
5835 buf1, buf3, buf1, buf2, l, buf3);
5836 strcpy(g_comment, "shrd");
5838 output_std_flags(fout, po, &pfomask, buf1);
5839 last_arith_dst = &po->operand[0];
5840 delayed_flag_op = NULL;
5845 assert_operand_cnt(2);
5846 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5847 if (po->operand[1].type == OPT_CONST) {
5848 j = po->operand[1].val;
5849 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
5850 fprintf(fout, po->op == OP_ROL ?
5851 " %s = (%s << %d) | (%s >> %d);" :
5852 " %s = (%s >> %d) | (%s << %d);",
5853 buf1, buf1, j, buf1,
5854 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
5858 output_std_flags(fout, po, &pfomask, buf1);
5859 last_arith_dst = &po->operand[0];
5860 delayed_flag_op = NULL;
5865 assert_operand_cnt(2);
5866 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5867 l = lmod_bytes(po, po->operand[0].lmod) * 8;
5868 if (po->operand[1].type == OPT_CONST) {
5869 j = po->operand[1].val % l;
5871 ferr(po, "zero rotate\n");
5872 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
5873 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
5874 if (po->op == OP_RCL) {
5876 " %s = (%s << %d) | (cond_c << %d)",
5877 buf1, buf1, j, j - 1);
5879 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
5883 " %s = (%s >> %d) | (cond_c << %d)",
5884 buf1, buf1, j, l - j);
5886 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
5888 fprintf(fout, ";\n");
5889 fprintf(fout, " cond_c = tmp;");
5893 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
5894 output_std_flags(fout, po, &pfomask, buf1);
5895 last_arith_dst = &po->operand[0];
5896 delayed_flag_op = NULL;
5900 assert_operand_cnt(2);
5901 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5902 if (IS(opr_name(po, 0), opr_name(po, 1))) {
5903 // special case for XOR
5904 if (pfomask & (1 << PFO_BE)) { // weird, but it happens..
5905 fprintf(fout, " cond_be = 1;\n");
5906 pfomask &= ~(1 << PFO_BE);
5908 fprintf(fout, " %s = 0;",
5909 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
5910 last_arith_dst = &po->operand[0];
5911 delayed_flag_op = NULL;
5917 assert_operand_cnt(2);
5918 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5919 if (pfomask & (1 << PFO_C)) {
5920 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
5921 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
5922 if (po->operand[0].lmod == OPLM_DWORD) {
5923 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
5924 fprintf(fout, " cond_c = tmp64 >> 32;\n");
5925 fprintf(fout, " %s = (u32)tmp64;",
5926 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
5927 strcat(g_comment, " add64");
5930 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
5931 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
5932 fprintf(fout, " %s += %s;",
5933 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5936 pfomask &= ~(1 << PFO_C);
5937 output_std_flags(fout, po, &pfomask, buf1);
5938 last_arith_dst = &po->operand[0];
5939 delayed_flag_op = NULL;
5945 assert_operand_cnt(2);
5946 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5947 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
5948 for (j = 0; j <= PFO_LE; j++) {
5949 if (!(pfomask & (1 << j)))
5951 if (j == PFO_Z || j == PFO_S)
5954 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0);
5955 fprintf(fout, " cond_%s = %s;\n",
5956 parsed_flag_op_names[j], buf1);
5957 pfomask &= ~(1 << j);
5964 assert_operand_cnt(2);
5965 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5966 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5967 if (po->op == OP_SBB
5968 && IS(po->operand[0].name, po->operand[1].name))
5970 // avoid use of unitialized var
5971 fprintf(fout, " %s = -cond_c;", buf1);
5972 // carry remains what it was
5973 pfomask &= ~(1 << PFO_C);
5976 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
5977 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5979 output_std_flags(fout, po, &pfomask, buf1);
5980 last_arith_dst = &po->operand[0];
5981 delayed_flag_op = NULL;
5985 assert_operand_cnt(2);
5986 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
5987 fprintf(fout, " %s = %s ? __builtin_ffs(%s) - 1 : 0;",
5988 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5990 output_std_flags(fout, po, &pfomask, buf1);
5991 last_arith_dst = &po->operand[0];
5992 delayed_flag_op = NULL;
5993 strcat(g_comment, " bsf");
5997 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
5998 for (j = 0; j <= PFO_LE; j++) {
5999 if (!(pfomask & (1 << j)))
6001 if (j == PFO_Z || j == PFO_S || j == PFO_C)
6004 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0);
6005 fprintf(fout, " cond_%s = %s;\n",
6006 parsed_flag_op_names[j], buf1);
6007 pfomask &= ~(1 << j);
6013 if (pfomask & (1 << PFO_C))
6014 // carry is unaffected by inc/dec.. wtf?
6015 ferr(po, "carry propagation needed\n");
6017 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6018 if (po->operand[0].type == OPT_REG) {
6019 strcpy(buf2, po->op == OP_INC ? "++" : "--");
6020 fprintf(fout, " %s%s;", buf1, buf2);
6023 strcpy(buf2, po->op == OP_INC ? "+" : "-");
6024 fprintf(fout, " %s %s= 1;", buf1, buf2);
6026 output_std_flags(fout, po, &pfomask, buf1);
6027 last_arith_dst = &po->operand[0];
6028 delayed_flag_op = NULL;
6032 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6033 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
6034 fprintf(fout, " %s = -%s%s;", buf1,
6035 lmod_cast_s(po, po->operand[0].lmod), buf2);
6036 last_arith_dst = &po->operand[0];
6037 delayed_flag_op = NULL;
6038 if (pfomask & (1 << PFO_C)) {
6039 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
6040 pfomask &= ~(1 << PFO_C);
6045 if (po->operand_cnt == 2) {
6046 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6049 if (po->operand_cnt == 3)
6050 ferr(po, "TODO imul3\n");
6053 assert_operand_cnt(1);
6054 switch (po->operand[0].lmod) {
6056 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
6057 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
6058 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
6059 fprintf(fout, " edx = tmp64 >> 32;\n");
6060 fprintf(fout, " eax = tmp64;");
6063 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
6064 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
6065 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
6069 ferr(po, "TODO: unhandled mul type\n");
6072 last_arith_dst = NULL;
6073 delayed_flag_op = NULL;
6078 assert_operand_cnt(1);
6079 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6080 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
6081 po->op == OP_IDIV));
6082 switch (po->operand[0].lmod) {
6084 if (po->flags & OPF_32BIT)
6085 snprintf(buf2, sizeof(buf2), "%seax", cast);
6087 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
6088 snprintf(buf2, sizeof(buf2), "%stmp64",
6089 (po->op == OP_IDIV) ? "(s64)" : "");
6091 if (po->operand[0].type == OPT_REG
6092 && po->operand[0].reg == xDX)
6094 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
6095 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
6098 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
6099 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
6103 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
6104 snprintf(buf2, sizeof(buf2), "%stmp",
6105 (po->op == OP_IDIV) ? "(s32)" : "");
6106 if (po->operand[0].type == OPT_REG
6107 && po->operand[0].reg == xDX)
6109 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
6111 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
6115 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
6117 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
6120 strcat(g_comment, " div16");
6123 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
6125 last_arith_dst = NULL;
6126 delayed_flag_op = NULL;
6131 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6133 for (j = 0; j < 8; j++) {
6134 if (pfomask & (1 << j)) {
6135 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
6136 fprintf(fout, " cond_%s = %s;",
6137 parsed_flag_op_names[j], buf1);
6144 last_arith_dst = NULL;
6145 delayed_flag_op = po;
6149 // SETcc - should already be handled
6152 // note: we reuse OP_Jcc for SETcc, only flags differ
6154 fprintf(fout, "\n goto %s;", po->operand[0].name);
6158 fprintf(fout, " if (ecx == 0)\n");
6159 fprintf(fout, " goto %s;", po->operand[0].name);
6160 strcat(g_comment, " jecxz");
6164 fprintf(fout, " if (--ecx != 0)\n");
6165 fprintf(fout, " goto %s;", po->operand[0].name);
6166 strcat(g_comment, " loop");
6170 assert_operand_cnt(1);
6171 last_arith_dst = NULL;
6172 delayed_flag_op = NULL;
6174 if (po->operand[0].type == OPT_REGMEM) {
6175 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
6178 ferr(po, "parse failure for jmp '%s'\n",
6179 po->operand[0].name);
6180 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
6183 else if (po->operand[0].type != OPT_LABEL)
6184 ferr(po, "unhandled jmp type\n");
6186 fprintf(fout, " goto %s;", po->operand[0].name);
6190 assert_operand_cnt(1);
6192 my_assert_not(pp, NULL);
6195 if (po->flags & OPF_CC) {
6196 // we treat conditional branch to another func
6197 // (yes such code exists..) as conditional tailcall
6199 fprintf(fout, " {\n");
6202 if (pp->is_fptr && !pp->is_arg) {
6203 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
6204 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6206 if (pp->is_unresolved)
6207 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
6208 buf3, asmfn, po->asmln, pp->name);
6211 fprintf(fout, "%s", buf3);
6212 if (strstr(pp->ret_type.name, "int64")) {
6213 if (po->flags & OPF_TAIL)
6214 ferr(po, "int64 and tail?\n");
6215 fprintf(fout, "tmp64 = ");
6217 else if (!IS(pp->ret_type.name, "void")) {
6218 if (po->flags & OPF_TAIL) {
6219 if (regmask_ret & mxAX) {
6220 fprintf(fout, "return ");
6221 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
6222 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
6224 else if (regmask_ret & mxST0)
6225 ferr(po, "float tailcall\n");
6227 else if (po->regmask_dst & mxAX) {
6228 fprintf(fout, "eax = ");
6229 if (pp->ret_type.is_ptr)
6230 fprintf(fout, "(u32)");
6232 else if (po->regmask_dst & mxST0) {
6233 fprintf(fout, "f_st0 = ");
6237 if (pp->name[0] == 0)
6238 ferr(po, "missing pp->name\n");
6239 fprintf(fout, "%s%s(", pp->name,
6240 pp->has_structarg ? "_sa" : "");
6242 if (po->flags & OPF_ATAIL) {
6243 if (pp->argc_stack != g_func_pp->argc_stack
6244 || (pp->argc_stack > 0
6245 && pp->is_stdcall != g_func_pp->is_stdcall))
6246 ferr(po, "incompatible tailcall\n");
6247 if (g_func_pp->has_retreg)
6248 ferr(po, "TODO: retreg+tailcall\n");
6250 for (arg = j = 0; arg < pp->argc; arg++) {
6252 fprintf(fout, ", ");
6255 if (pp->arg[arg].type.is_ptr)
6256 snprintf(cast, sizeof(cast), "(%s)",
6257 pp->arg[arg].type.name);
6259 if (pp->arg[arg].reg != NULL) {
6260 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6264 for (; j < g_func_pp->argc; j++)
6265 if (g_func_pp->arg[j].reg == NULL)
6267 fprintf(fout, "%sa%d", cast, j + 1);
6272 for (arg = 0; arg < pp->argc; arg++) {
6274 fprintf(fout, ", ");
6277 if (pp->arg[arg].type.is_ptr)
6278 snprintf(cast, sizeof(cast), "(%s)",
6279 pp->arg[arg].type.name);
6281 if (pp->arg[arg].reg != NULL) {
6282 if (pp->arg[arg].type.is_retreg)
6283 fprintf(fout, "&%s", pp->arg[arg].reg);
6285 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6290 tmp_op = pp->arg[arg].datap;
6292 ferr(po, "parsed_op missing for arg%d\n", arg);
6294 if (tmp_op->flags & OPF_VAPUSH) {
6295 fprintf(fout, "ap");
6297 else if (tmp_op->p_argpass != 0) {
6298 fprintf(fout, "a%d", tmp_op->p_argpass);
6300 else if (tmp_op->p_argnum != 0) {
6301 fprintf(fout, "%s%s", cast,
6302 saved_arg_name(buf1, sizeof(buf1),
6303 tmp_op->p_arggrp, tmp_op->p_argnum));
6307 out_src_opr(buf1, sizeof(buf1),
6308 tmp_op, &tmp_op->operand[0], cast, 0));
6312 fprintf(fout, ");");
6314 if (strstr(pp->ret_type.name, "int64")) {
6315 fprintf(fout, "\n");
6316 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
6317 fprintf(fout, "%seax = tmp64;", buf3);
6320 if (pp->is_unresolved) {
6321 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
6323 strcat(g_comment, buf2);
6326 if (po->flags & OPF_TAIL) {
6328 if (i == opcnt - 1 || pp->is_noreturn)
6330 else if (IS(pp->ret_type.name, "void"))
6332 else if (!(regmask_ret & (1 << xAX)))
6334 // else already handled as 'return f()'
6337 fprintf(fout, "\n%sreturn;", buf3);
6338 strcat(g_comment, " ^ tailcall");
6341 strcat(g_comment, " tailcall");
6343 if ((regmask_ret & (1 << xAX))
6344 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
6346 ferr(po, "int func -> void func tailcall?\n");
6349 if (pp->is_noreturn)
6350 strcat(g_comment, " noreturn");
6351 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
6352 strcat(g_comment, " argframe");
6353 if (po->flags & OPF_CC)
6354 strcat(g_comment, " cond");
6356 if (po->flags & OPF_CC)
6357 fprintf(fout, "\n }");
6359 delayed_flag_op = NULL;
6360 last_arith_dst = NULL;
6364 if (g_func_pp->is_vararg)
6365 fprintf(fout, " va_end(ap);\n");
6366 if (g_func_pp->has_retreg) {
6367 for (arg = 0; arg < g_func_pp->argc; arg++)
6368 if (g_func_pp->arg[arg].type.is_retreg)
6369 fprintf(fout, " *r_%s = %s;\n",
6370 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
6373 if (!(regmask_ret & (1 << xAX))) {
6374 if (i != opcnt - 1 || label_pending)
6375 fprintf(fout, " return;");
6377 else if (g_func_pp->ret_type.is_ptr) {
6378 fprintf(fout, " return (%s)eax;",
6379 g_func_pp->ret_type.name);
6381 else if (IS(g_func_pp->ret_type.name, "__int64"))
6382 fprintf(fout, " return ((u64)edx << 32) | eax;");
6384 fprintf(fout, " return eax;");
6386 last_arith_dst = NULL;
6387 delayed_flag_op = NULL;
6391 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6392 if (po->p_argnum != 0) {
6393 // special case - saved func arg
6394 fprintf(fout, " %s = %s;",
6395 saved_arg_name(buf2, sizeof(buf2),
6396 po->p_arggrp, po->p_argnum), buf1);
6399 else if (po->flags & OPF_RSAVE) {
6400 fprintf(fout, " s_%s = %s;", buf1, buf1);
6403 else if (po->flags & OPF_PPUSH) {
6405 ferr_assert(po, tmp_op != NULL);
6406 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
6407 fprintf(fout, " pp_%s = %s;", buf2, buf1);
6410 else if (g_func_pp->is_userstack) {
6411 fprintf(fout, " *(--esp) = %s;", buf1);
6414 if (!(g_ida_func_attr & IDAFA_NORETURN))
6415 ferr(po, "stray push encountered\n");
6420 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6421 if (po->flags & OPF_RSAVE) {
6422 fprintf(fout, " %s = s_%s;", buf1, buf1);
6425 else if (po->flags & OPF_PPUSH) {
6426 // push/pop graph / non-const
6427 ferr_assert(po, po->datap == NULL);
6428 fprintf(fout, " %s = pp_%s;", buf1, buf1);
6431 else if (po->datap != NULL) {
6434 fprintf(fout, " %s = %s;", buf1,
6435 out_src_opr(buf2, sizeof(buf2),
6436 tmp_op, &tmp_op->operand[0],
6437 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6440 else if (g_func_pp->is_userstack) {
6441 fprintf(fout, " %s = *esp++;", buf1);
6445 ferr(po, "stray pop encountered\n");
6454 if (po->flags & OPF_FSHIFT)
6455 fprintf(fout, " f_st1 = f_st0;\n");
6456 if (po->operand[0].type == OPT_REG
6457 && po->operand[0].reg == xST0)
6459 strcat(g_comment, " fld st");
6462 fprintf(fout, " f_st0 = %s;",
6463 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0]));
6464 strcat(g_comment, " fld");
6468 if (po->flags & OPF_FSHIFT)
6469 fprintf(fout, " f_st1 = f_st0;\n");
6470 fprintf(fout, " f_st0 = (double)%s;",
6471 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6472 lmod_cast(po, po->operand[0].lmod, 1), 0));
6473 strcat(g_comment, " fild");
6477 if (po->flags & OPF_FSHIFT)
6478 fprintf(fout, " f_st1 = f_st0;\n");
6479 fprintf(fout, " f_st0 = ");
6480 switch (po->operand[0].val) {
6481 case X87_CONST_1: fprintf(fout, "1.0;"); break;
6482 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
6483 default: ferr(po, "TODO\n"); break;
6488 if ((po->flags & OPF_FPOP) && po->operand[0].type == OPT_REG
6489 && po->operand[0].reg == xST0)
6494 fprintf(fout, " %s = f_st0;",
6495 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0]));
6496 if (po->flags & OPF_FSHIFT)
6497 fprintf(fout, "\n f_st0 = f_st1;");
6498 strcat(g_comment, " fst");
6506 case OP_FADD: j = '+'; break;
6507 case OP_FDIV: j = '/'; break;
6508 case OP_FMUL: j = '*'; break;
6509 case OP_FSUB: j = '-'; break;
6510 default: j = 'x'; break;
6512 if (po->flags & OPF_FSHIFT) {
6513 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
6516 fprintf(fout, " %s %c= %s;",
6517 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0]),
6519 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1]));
6525 if (po->flags & OPF_FSHIFT)
6526 snprintf(buf1, sizeof(buf1), "f_st0");
6528 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0]);
6529 fprintf(fout, " %s = %s %c %s;", buf1,
6530 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1]),
6531 po->op == OP_FDIVR ? '/' : '-',
6532 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0]));
6540 case OP_FIADD: j = '+'; break;
6541 case OP_FIDIV: j = '/'; break;
6542 case OP_FIMUL: j = '*'; break;
6543 case OP_FISUB: j = '-'; break;
6544 default: j = 'x'; break;
6546 fprintf(fout, " f_st0 %c= (double)%s;", j,
6547 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6548 lmod_cast(po, po->operand[0].lmod, 1), 0));
6553 fprintf(fout, " f_st0 = %s %c f_st0;",
6554 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1]),
6555 po->op == OP_FIDIVR ? '/' : '-');
6559 ferr_assert(po, po->flags & OPF_32BIT);
6560 fprintf(fout, " eax = (s32)f_st0;");
6561 if (po->flags & OPF_FSHIFT)
6562 fprintf(fout, "\n f_st0 = f_st1;");
6563 strcat(g_comment, " ftol");
6568 strcpy(g_comment, " (emms)");
6573 ferr(po, "unhandled op type %d, flags %x\n",
6578 if (g_comment[0] != 0) {
6579 char *p = g_comment;
6580 while (my_isblank(*p))
6582 fprintf(fout, " // %s", p);
6587 fprintf(fout, "\n");
6589 // some sanity checking
6590 if (po->flags & OPF_REP) {
6591 if (po->op != OP_STOS && po->op != OP_MOVS
6592 && po->op != OP_CMPS && po->op != OP_SCAS)
6593 ferr(po, "unexpected rep\n");
6594 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
6595 && (po->op == OP_CMPS || po->op == OP_SCAS))
6596 ferr(po, "cmps/scas with plain rep\n");
6598 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
6599 && po->op != OP_CMPS && po->op != OP_SCAS)
6600 ferr(po, "unexpected repz/repnz\n");
6603 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
6605 // see is delayed flag stuff is still valid
6606 if (delayed_flag_op != NULL && delayed_flag_op != po) {
6607 if (is_any_opr_modified(delayed_flag_op, po, 0))
6608 delayed_flag_op = NULL;
6611 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
6612 if (is_opr_modified(last_arith_dst, po))
6613 last_arith_dst = NULL;
6619 if (g_stack_fsz && !g_stack_frame_used)
6620 fprintf(fout, " (void)sf;\n");
6622 fprintf(fout, "}\n\n");
6624 gen_x_cleanup(opcnt);
6627 static void gen_x_cleanup(int opcnt)
6631 for (i = 0; i < opcnt; i++) {
6632 struct label_ref *lr, *lr_del;
6634 lr = g_label_refs[i].next;
6635 while (lr != NULL) {
6640 g_label_refs[i].i = -1;
6641 g_label_refs[i].next = NULL;
6643 if (ops[i].op == OP_CALL) {
6645 proto_release(ops[i].pp);
6651 struct func_proto_dep;
6653 struct func_prototype {
6658 int has_ret:3; // -1, 0, 1: unresolved, no, yes
6659 unsigned int dep_resolved:1;
6660 unsigned int is_stdcall:1;
6661 struct func_proto_dep *dep_func;
6663 const struct parsed_proto *pp; // seed pp, if any
6666 struct func_proto_dep {
6668 struct func_prototype *proto;
6669 int regmask_live; // .. at the time of call
6670 unsigned int ret_dep:1; // return from this is caller's return
6673 static struct func_prototype *hg_fp;
6674 static int hg_fp_cnt;
6676 static struct scanned_var {
6678 enum opr_lenmod lmod;
6679 unsigned int is_seeded:1;
6680 unsigned int is_c_str:1;
6681 const struct parsed_proto *pp; // seed pp, if any
6683 static int hg_var_cnt;
6685 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
6688 struct func_prototype *hg_fp_add(const char *funcn)
6690 struct func_prototype *fp;
6692 if ((hg_fp_cnt & 0xff) == 0) {
6693 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
6694 my_assert_not(hg_fp, NULL);
6695 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
6698 fp = &hg_fp[hg_fp_cnt];
6699 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
6701 fp->argc_stack = -1;
6707 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
6712 for (i = 0; i < fp->dep_func_cnt; i++)
6713 if (IS(fp->dep_func[i].name, name))
6714 return &fp->dep_func[i];
6719 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
6722 if (hg_fp_find_dep(fp, name))
6725 if ((fp->dep_func_cnt & 0xff) == 0) {
6726 fp->dep_func = realloc(fp->dep_func,
6727 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
6728 my_assert_not(fp->dep_func, NULL);
6729 memset(&fp->dep_func[fp->dep_func_cnt], 0,
6730 sizeof(fp->dep_func[0]) * 0x100);
6732 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
6736 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
6738 const struct func_prototype *p1 = p1_, *p2 = p2_;
6739 return strcmp(p1->name, p2->name);
6743 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
6745 const struct func_prototype *p1 = p1_, *p2 = p2_;
6746 return p1->id - p2->id;
6750 // recursive register dep pass
6751 // - track saved regs (part 2)
6752 // - try to figure out arg-regs
6753 // - calculate reg deps
6754 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
6755 struct func_prototype *fp, int regmask_save, int regmask_dst,
6756 int *regmask_dep, int *has_ret)
6758 struct func_proto_dep *dep;
6759 struct parsed_op *po;
6760 int from_caller = 0;
6765 for (; i < opcnt; i++)
6767 if (cbits[i >> 3] & (1 << (i & 7)))
6769 cbits[i >> 3] |= (1 << (i & 7));
6773 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
6774 if (po->flags & OPF_RMD)
6777 if (po->btj != NULL) {
6779 for (j = 0; j < po->btj->count; j++) {
6780 check_i(po, po->btj->d[j].bt_i);
6781 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
6782 regmask_save, regmask_dst, regmask_dep, has_ret);
6787 check_i(po, po->bt_i);
6788 if (po->flags & OPF_CJMP) {
6789 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
6790 regmask_save, regmask_dst, regmask_dep, has_ret);
6798 if (po->flags & OPF_FARG)
6799 /* (just calculate register deps) */;
6800 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
6802 reg = po->operand[0].reg;
6803 ferr_assert(po, reg >= 0);
6805 if (po->flags & OPF_RSAVE) {
6806 regmask_save |= 1 << reg;
6809 if (po->flags & OPF_DONE)
6812 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0);
6814 regmask_save |= 1 << reg;
6815 po->flags |= OPF_RMD;
6816 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, OPF_RMD);
6820 else if (po->flags & OPF_RMD)
6822 else if (po->op == OP_CALL) {
6823 po->regmask_dst |= 1 << xAX;
6825 dep = hg_fp_find_dep(fp, po->operand[0].name);
6827 dep->regmask_live = regmask_save | regmask_dst;
6829 else if (po->op == OP_RET) {
6830 if (po->operand_cnt > 0) {
6832 if (fp->argc_stack >= 0
6833 && fp->argc_stack != po->operand[0].val / 4)
6834 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
6835 fp->argc_stack = po->operand[0].val / 4;
6839 // if has_ret is 0, there is uninitialized eax path,
6840 // which means it's most likely void func
6841 if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
6842 if (po->op == OP_CALL) {
6847 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
6850 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
6853 if (ret != 1 && from_caller) {
6854 // unresolved eax - probably void func
6858 if (j >= 0 && ops[j].op == OP_CALL) {
6859 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
6870 l = regmask_save | regmask_dst;
6871 if (g_bp_frame && !(po->flags & OPF_EBP_S))
6874 l = po->regmask_src & ~l;
6877 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
6878 l, regmask_dst, regmask_save, po->flags);
6881 regmask_dst |= po->regmask_dst;
6883 if (po->flags & OPF_TAIL)
6888 static void gen_hdr(const char *funcn, int opcnt)
6890 int save_arg_vars[MAX_ARG_GRP] = { 0, };
6891 unsigned char cbits[MAX_OPS / 8];
6892 const struct parsed_proto *pp_c;
6893 struct parsed_proto *pp;
6894 struct func_prototype *fp;
6895 struct parsed_op *po;
6896 int regmask_dummy = 0;
6898 int max_bp_offset = 0;
6903 pp_c = proto_parse(g_fhdr, funcn, 1);
6905 // already in seed, will add to hg_fp later
6908 fp = hg_fp_add(funcn);
6910 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
6911 g_stack_frame_used = 0;
6914 // - resolve all branches
6915 // - parse calls with labels
6916 resolve_branches_parse_calls(opcnt);
6919 // - handle ebp/esp frame, remove ops related to it
6920 scan_prologue_epilogue(opcnt);
6923 // - remove dead labels
6925 for (i = 0; i < opcnt; i++)
6927 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
6933 if (po->flags & (OPF_RMD|OPF_DONE))
6936 if (po->op == OP_CALL) {
6937 if (po->operand[0].type == OPT_LABEL)
6938 hg_fp_add_dep(fp, opr_name(po, 0));
6939 else if (po->pp != NULL)
6940 hg_fp_add_dep(fp, po->pp->name);
6945 // - remove dead labels
6946 // - handle push <const>/pop pairs
6947 for (i = 0; i < opcnt; i++)
6949 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
6955 if (po->flags & (OPF_RMD|OPF_DONE))
6958 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
6959 scan_for_pop_const(i, opcnt, i + opcnt * 13);
6963 // - process trivial calls
6964 for (i = 0; i < opcnt; i++)
6967 if (po->flags & (OPF_RMD|OPF_DONE))
6970 if (po->op == OP_CALL)
6972 pp = process_call_early(i, opcnt, &j);
6974 if (!(po->flags & OPF_ATAIL))
6975 // since we know the args, try to collect them
6976 if (collect_call_args_early(po, i, pp, ®mask_dummy) != 0)
6982 // commit esp adjust
6983 if (ops[j].op != OP_POP)
6984 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
6986 for (l = 0; l < pp->argc_stack; l++)
6987 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
6991 po->flags |= OPF_DONE;
6997 // - track saved regs (simple)
6999 for (i = 0; i < opcnt; i++)
7002 if (po->flags & (OPF_RMD|OPF_DONE))
7005 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
7006 && po->operand[0].reg != xCX)
7008 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
7010 // regmask_save |= 1 << po->operand[0].reg; // do it later
7011 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
7012 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
7015 else if (po->op == OP_CALL)
7017 pp = process_call(i, opcnt);
7019 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
7020 // since we know the args, collect them
7021 ret = collect_call_args(po, i, pp, ®mask_dummy, save_arg_vars,
7028 memset(cbits, 0, sizeof(cbits));
7032 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, ®mask_dep, &has_ret);
7034 // find unreachable code - must be fixed in IDA
7035 for (i = 0; i < opcnt; i++)
7037 if (cbits[i >> 3] & (1 << (i & 7)))
7040 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
7041 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
7043 // the compiler sometimes still generates code after
7044 // noreturn OS functions
7047 if (ops[i].op != OP_NOP)
7048 ferr(&ops[i], "unreachable code\n");
7051 for (i = 0; i < g_eqcnt; i++) {
7052 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
7053 max_bp_offset = g_eqs[i].offset;
7056 if (fp->argc_stack < 0) {
7057 max_bp_offset = (max_bp_offset + 3) & ~3;
7058 fp->argc_stack = max_bp_offset / 4;
7059 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
7063 fp->regmask_dep = regmask_dep & ~(1 << xSP);
7064 fp->has_ret = has_ret;
7066 printf("// has_ret %d, regmask_dep %x\n",
7067 fp->has_ret, fp->regmask_dep);
7068 output_hdr_fp(stdout, fp, 1);
7069 if (IS(funcn, "sub_10007F72")) exit(1);
7072 gen_x_cleanup(opcnt);
7075 static void hg_fp_resolve_deps(struct func_prototype *fp)
7077 struct func_prototype fp_s;
7081 // this thing is recursive, so mark first..
7082 fp->dep_resolved = 1;
7084 for (i = 0; i < fp->dep_func_cnt; i++) {
7085 strcpy(fp_s.name, fp->dep_func[i].name);
7086 fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
7087 sizeof(hg_fp[0]), hg_fp_cmp_name);
7088 if (fp->dep_func[i].proto != NULL) {
7089 if (!fp->dep_func[i].proto->dep_resolved)
7090 hg_fp_resolve_deps(fp->dep_func[i].proto);
7092 dep = ~fp->dep_func[i].regmask_live
7093 & fp->dep_func[i].proto->regmask_dep;
7094 fp->regmask_dep |= dep;
7095 // printf("dep %s %s |= %x\n", fp->name,
7096 // fp->dep_func[i].name, dep);
7098 if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
7099 fp->has_ret = fp->dep_func[i].proto->has_ret;
7104 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7107 const struct parsed_proto *pp;
7108 char *p, namebuf[NAMELEN];
7114 for (; count > 0; count--, fp++) {
7115 if (fp->has_ret == -1)
7116 fprintf(fout, "// ret unresolved\n");
7118 fprintf(fout, "// dep:");
7119 for (j = 0; j < fp->dep_func_cnt; j++) {
7120 fprintf(fout, " %s/", fp->dep_func[j].name);
7121 if (fp->dep_func[j].proto != NULL)
7122 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
7123 fp->dep_func[j].proto->has_ret);
7125 fprintf(fout, "\n");
7128 p = strchr(fp->name, '@');
7130 memcpy(namebuf, fp->name, p - fp->name);
7131 namebuf[p - fp->name] = 0;
7139 pp = proto_parse(g_fhdr, name, 1);
7140 if (pp != NULL && pp->is_include)
7143 if (fp->pp != NULL) {
7144 // part of seed, output later
7148 regmask_dep = fp->regmask_dep;
7149 argc_stack = fp->argc_stack;
7151 fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
7152 (fp->has_ret ? "int" : "void"));
7153 if (regmask_dep && (fp->is_stdcall || argc_stack == 0)
7154 && (regmask_dep & ~((1 << xCX) | (1 << xDX))) == 0)
7156 fprintf(fout, " __fastcall ");
7157 if (!(regmask_dep & (1 << xDX)) && argc_stack == 0)
7163 else if (regmask_dep && !fp->is_stdcall) {
7164 fprintf(fout, "/*__usercall*/ ");
7166 else if (regmask_dep) {
7167 fprintf(fout, "/*__userpurge*/ ");
7169 else if (fp->is_stdcall)
7170 fprintf(fout, " __stdcall ");
7172 fprintf(fout, " __cdecl ");
7174 fprintf(fout, "%s(", name);
7177 for (j = 0; j < xSP; j++) {
7178 if (regmask_dep & (1 << j)) {
7181 fprintf(fout, ", ");
7183 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
7185 fprintf(fout, "int");
7186 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
7190 for (j = 0; j < argc_stack; j++) {
7193 fprintf(fout, ", ");
7194 if (fp->pp != NULL) {
7195 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
7196 if (!fp->pp->arg[arg - 1].type.is_ptr)
7200 fprintf(fout, "int ");
7201 fprintf(fout, "a%d", arg);
7204 fprintf(fout, ");\n");
7208 static void output_hdr(FILE *fout)
7210 static const char *lmod_c_names[] = {
7211 [OPLM_UNSPEC] = "???",
7212 [OPLM_BYTE] = "uint8_t",
7213 [OPLM_WORD] = "uint16_t",
7214 [OPLM_DWORD] = "uint32_t",
7215 [OPLM_QWORD] = "uint64_t",
7217 const struct scanned_var *var;
7218 struct func_prototype *fp;
7219 char line[256] = { 0, };
7223 // add stuff from headers
7224 for (i = 0; i < pp_cache_size; i++) {
7225 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
7226 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
7228 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
7229 fp = hg_fp_add(name);
7230 fp->pp = &pp_cache[i];
7231 fp->argc_stack = fp->pp->argc_stack;
7232 fp->is_stdcall = fp->pp->is_stdcall;
7233 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
7234 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
7238 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
7239 for (i = 0; i < hg_fp_cnt; i++)
7240 hg_fp_resolve_deps(&hg_fp[i]);
7242 // note: messes up .proto ptr, don't use
7243 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
7246 for (i = 0; i < hg_var_cnt; i++) {
7249 if (var->pp != NULL)
7252 else if (var->is_c_str)
7253 fprintf(fout, "extern %-8s %s[];", "char", var->name);
7255 fprintf(fout, "extern %-8s %s;",
7256 lmod_c_names[var->lmod], var->name);
7259 fprintf(fout, " // seeded");
7260 fprintf(fout, "\n");
7263 fprintf(fout, "\n");
7265 // output function prototypes
7266 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
7269 fprintf(fout, "\n// - seed -\n");
7272 while (fgets(line, sizeof(line), g_fhdr))
7273 fwrite(line, 1, strlen(line), fout);
7276 // '=' needs special treatment
7278 static char *next_word_s(char *w, size_t wsize, char *s)
7287 for (i = 1; i < wsize - 1; i++) {
7289 printf("warning: missing closing quote: \"%s\"\n", s);
7298 for (; i < wsize - 1; i++) {
7299 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
7305 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
7306 printf("warning: '%s' truncated\n", w);
7311 static void scan_variables(FILE *fasm)
7313 struct scanned_var *var;
7314 char line[256] = { 0, };
7322 // skip to next data section
7323 while (my_fgets(line, sizeof(line), fasm))
7328 if (*p == 0 || *p == ';')
7331 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
7332 if (*p == 0 || *p == ';')
7335 if (*p != 's' || !IS_START(p, "segment para public"))
7341 if (p == NULL || !IS_START(p, "segment para public"))
7345 if (!IS_START(p, "'DATA'"))
7349 while (my_fgets(line, sizeof(line), fasm))
7358 if (*p == 0 || *p == ';')
7361 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
7362 words[wordc][0] = 0;
7363 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
7364 if (*p == 0 || *p == ';') {
7370 if (wordc == 2 && IS(words[1], "ends"))
7375 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
7376 // when this starts, we don't need anything from this section
7380 if ((hg_var_cnt & 0xff) == 0) {
7381 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
7382 * (hg_var_cnt + 0x100));
7383 my_assert_not(hg_vars, NULL);
7384 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
7387 var = &hg_vars[hg_var_cnt++];
7388 snprintf(var->name, sizeof(var->name), "%s", words[0]);
7390 // maybe already in seed header?
7391 var->pp = proto_parse(g_fhdr, var->name, 1);
7392 if (var->pp != NULL) {
7393 if (var->pp->is_fptr) {
7394 var->lmod = OPLM_DWORD;
7397 else if (var->pp->is_func)
7399 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
7400 aerr("unhandled C type '%s' for '%s'\n",
7401 var->pp->type.name, var->name);
7407 if (IS(words[1], "dd"))
7408 var->lmod = OPLM_DWORD;
7409 else if (IS(words[1], "dw"))
7410 var->lmod = OPLM_WORD;
7411 else if (IS(words[1], "db")) {
7412 var->lmod = OPLM_BYTE;
7413 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
7414 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
7418 else if (IS(words[1], "dq"))
7419 var->lmod = OPLM_QWORD;
7420 //else if (IS(words[1], "dt"))
7422 aerr("type '%s' not known\n", words[1]);
7430 static void set_label(int i, const char *name)
7436 p = strchr(name, ':');
7440 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
7441 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
7442 g_labels[i] = realloc(g_labels[i], len + 1);
7443 my_assert_not(g_labels[i], NULL);
7444 memcpy(g_labels[i], name, len);
7445 g_labels[i][len] = 0;
7454 static struct chunk_item *func_chunks;
7455 static int func_chunk_cnt;
7456 static int func_chunk_alloc;
7458 static void add_func_chunk(FILE *fasm, const char *name, int line)
7460 if (func_chunk_cnt >= func_chunk_alloc) {
7461 func_chunk_alloc *= 2;
7462 func_chunks = realloc(func_chunks,
7463 func_chunk_alloc * sizeof(func_chunks[0]));
7464 my_assert_not(func_chunks, NULL);
7466 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
7467 func_chunks[func_chunk_cnt].name = strdup(name);
7468 func_chunks[func_chunk_cnt].asmln = line;
7472 static int cmp_chunks(const void *p1, const void *p2)
7474 const struct chunk_item *c1 = p1, *c2 = p2;
7475 return strcmp(c1->name, c2->name);
7478 static int cmpstringp(const void *p1, const void *p2)
7480 return strcmp(*(char * const *)p1, *(char * const *)p2);
7483 static void scan_ahead(FILE *fasm)
7493 oldpos = ftell(fasm);
7496 while (my_fgets(line, sizeof(line), fasm))
7507 // get rid of random tabs
7508 for (i = 0; line[i] != 0; i++)
7509 if (line[i] == '\t')
7512 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
7515 next_word(words[0], sizeof(words[0]), p);
7516 if (words[0][0] == 0)
7517 aerr("missing name for func chunk?\n");
7519 add_func_chunk(fasm, words[0], asmln);
7521 else if (IS_START(p, "; sctend"))
7527 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
7528 words[wordc][0] = 0;
7529 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
7530 if (*p == 0 || *p == ';') {
7536 if (wordc == 2 && IS(words[1], "ends"))
7540 fseek(fasm, oldpos, SEEK_SET);
7544 int main(int argc, char *argv[])
7546 FILE *fout, *fasm, *frlist;
7547 struct parsed_data *pd = NULL;
7549 char **rlist = NULL;
7551 int rlist_alloc = 0;
7552 int func_chunks_used = 0;
7553 int func_chunks_sorted = 0;
7554 int func_chunk_i = -1;
7555 long func_chunk_ret = 0;
7556 int func_chunk_ret_ln = 0;
7557 int scanned_ahead = 0;
7559 char words[20][256];
7560 enum opr_lenmod lmod;
7561 char *sctproto = NULL;
7563 int pending_endp = 0;
7565 int skip_warned = 0;
7578 for (arg = 1; arg < argc; arg++) {
7579 if (IS(argv[arg], "-v"))
7581 else if (IS(argv[arg], "-rf"))
7582 g_allow_regfunc = 1;
7583 else if (IS(argv[arg], "-m"))
7585 else if (IS(argv[arg], "-hdr"))
7586 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
7591 if (argc < arg + 3) {
7592 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
7593 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
7595 " -hdr - header generation mode\n"
7596 " -rf - allow unannotated indirect calls\n"
7597 " -m - allow multiple .text sections\n"
7598 "[rlist] is a file with function names to skip,"
7606 asmfn = argv[arg++];
7607 fasm = fopen(asmfn, "r");
7608 my_assert_not(fasm, NULL);
7610 hdrfn = argv[arg++];
7611 g_fhdr = fopen(hdrfn, "r");
7612 my_assert_not(g_fhdr, NULL);
7615 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
7616 my_assert_not(rlist, NULL);
7617 // needs special handling..
7618 rlist[rlist_len++] = "__alloca_probe";
7620 func_chunk_alloc = 32;
7621 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
7622 my_assert_not(func_chunks, NULL);
7624 memset(words, 0, sizeof(words));
7626 for (; arg < argc; arg++) {
7627 frlist = fopen(argv[arg], "r");
7628 my_assert_not(frlist, NULL);
7630 while (my_fgets(line, sizeof(line), frlist)) {
7632 if (*p == 0 || *p == ';')
7635 if (IS_START(p, "#if 0")
7636 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
7640 else if (IS_START(p, "#endif"))
7647 p = next_word(words[0], sizeof(words[0]), p);
7648 if (words[0][0] == 0)
7651 if (rlist_len >= rlist_alloc) {
7652 rlist_alloc = rlist_alloc * 2 + 64;
7653 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
7654 my_assert_not(rlist, NULL);
7656 rlist[rlist_len++] = strdup(words[0]);
7665 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
7667 fout = fopen(argv[arg_out], "w");
7668 my_assert_not(fout, NULL);
7671 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
7672 my_assert_not(g_eqs, NULL);
7674 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
7675 g_label_refs[i].i = -1;
7676 g_label_refs[i].next = NULL;
7680 scan_variables(fasm);
7682 while (my_fgets(line, sizeof(line), fasm))
7691 // get rid of random tabs
7692 for (i = 0; line[i] != 0; i++)
7693 if (line[i] == '\t')
7698 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
7699 goto do_pending_endp; // eww..
7701 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
7703 static const char *attrs[] = {
7712 // parse IDA's attribute-list comment
7713 g_ida_func_attr = 0;
7716 for (; *p != 0; p = sskip(p)) {
7717 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
7718 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
7719 g_ida_func_attr |= 1 << i;
7720 p += strlen(attrs[i]);
7724 if (i == ARRAY_SIZE(attrs)) {
7725 anote("unparsed IDA attr: %s\n", p);
7728 if (IS(attrs[i], "fpd=")) {
7729 p = next_word(words[0], sizeof(words[0]), p);
7734 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
7737 next_word(words[0], sizeof(words[0]), p);
7738 if (words[0][0] == 0)
7739 aerr("missing name for func chunk?\n");
7741 if (!scanned_ahead) {
7742 add_func_chunk(fasm, words[0], asmln);
7743 func_chunks_sorted = 0;
7746 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
7748 if (func_chunk_i >= 0) {
7749 if (func_chunk_i < func_chunk_cnt
7750 && IS(func_chunks[func_chunk_i].name, g_func))
7752 // move on to next chunk
7753 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
7755 aerr("seek failed for '%s' chunk #%d\n",
7756 g_func, func_chunk_i);
7757 asmln = func_chunks[func_chunk_i].asmln;
7761 if (func_chunk_ret == 0)
7762 aerr("no return from chunk?\n");
7763 fseek(fasm, func_chunk_ret, SEEK_SET);
7764 asmln = func_chunk_ret_ln;
7770 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
7771 func_chunks_used = 1;
7773 if (IS_START(g_func, "sub_")) {
7774 unsigned long addr = strtoul(p, NULL, 16);
7775 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
7776 if (addr > f_addr && !scanned_ahead) {
7777 //anote("scan_ahead caused by '%s', addr %lx\n",
7781 func_chunks_sorted = 0;
7789 for (i = wordc; i < ARRAY_SIZE(words); i++)
7791 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
7792 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
7793 if (*p == 0 || *p == ';') {
7798 if (*p != 0 && *p != ';')
7799 aerr("too many words\n");
7801 // alow asm patches in comments
7803 if (IS_START(p, "; sctpatch:")) {
7805 if (*p == 0 || *p == ';')
7807 goto parse_words; // lame
7809 if (IS_START(p, "; sctproto:")) {
7810 sctproto = strdup(p + 11);
7812 else if (IS_START(p, "; sctend")) {
7821 awarn("wordc == 0?\n");
7825 // don't care about this:
7826 if (words[0][0] == '.'
7827 || IS(words[0], "include")
7828 || IS(words[0], "assume") || IS(words[1], "segment")
7829 || IS(words[0], "align"))
7835 // do delayed endp processing to collect switch jumptables
7837 if (in_func && !g_skip_func && !end && wordc >= 2
7838 && ((words[0][0] == 'd' && words[0][2] == 0)
7839 || (words[1][0] == 'd' && words[1][2] == 0)))
7842 if (words[1][0] == 'd' && words[1][2] == 0) {
7844 if (g_func_pd_cnt >= pd_alloc) {
7845 pd_alloc = pd_alloc * 2 + 16;
7846 g_func_pd = realloc(g_func_pd,
7847 sizeof(g_func_pd[0]) * pd_alloc);
7848 my_assert_not(g_func_pd, NULL);
7850 pd = &g_func_pd[g_func_pd_cnt];
7852 memset(pd, 0, sizeof(*pd));
7853 strcpy(pd->label, words[0]);
7854 pd->type = OPT_CONST;
7855 pd->lmod = lmod_from_directive(words[1]);
7861 anote("skipping alignment byte?\n");
7864 lmod = lmod_from_directive(words[0]);
7865 if (lmod != pd->lmod)
7866 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
7869 if (pd->count_alloc < pd->count + wordc) {
7870 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
7871 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
7872 my_assert_not(pd->d, NULL);
7874 for (; i < wordc; i++) {
7875 if (IS(words[i], "offset")) {
7876 pd->type = OPT_OFFSET;
7879 p = strchr(words[i], ',');
7882 if (pd->type == OPT_OFFSET)
7883 pd->d[pd->count].u.label = strdup(words[i]);
7885 pd->d[pd->count].u.val = parse_number(words[i]);
7886 pd->d[pd->count].bt_i = -1;
7892 if (in_func && !g_skip_func) {
7894 gen_hdr(g_func, pi);
7896 gen_func(fout, g_fhdr, g_func, pi);
7901 g_ida_func_attr = 0;
7905 func_chunks_used = 0;
7908 memset(&ops, 0, pi * sizeof(ops[0]));
7913 for (i = 0; i < g_func_pd_cnt; i++) {
7915 if (pd->type == OPT_OFFSET) {
7916 for (j = 0; j < pd->count; j++)
7917 free(pd->d[j].u.label);
7932 if (IS(words[1], "proc")) {
7934 aerr("proc '%s' while in_func '%s'?\n",
7937 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
7939 strcpy(g_func, words[0]);
7940 set_label(0, words[0]);
7945 if (IS(words[1], "endp"))
7948 aerr("endp '%s' while not in_func?\n", words[0]);
7949 if (!IS(g_func, words[0]))
7950 aerr("endp '%s' while in_func '%s'?\n",
7953 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
7954 && ops[0].op == OP_JMP && ops[0].operand[0].had_ds)
7960 if (!g_skip_func && func_chunks_used) {
7961 // start processing chunks
7962 struct chunk_item *ci, key = { g_func, 0 };
7964 func_chunk_ret = ftell(fasm);
7965 func_chunk_ret_ln = asmln;
7966 if (!func_chunks_sorted) {
7967 qsort(func_chunks, func_chunk_cnt,
7968 sizeof(func_chunks[0]), cmp_chunks);
7969 func_chunks_sorted = 1;
7971 ci = bsearch(&key, func_chunks, func_chunk_cnt,
7972 sizeof(func_chunks[0]), cmp_chunks);
7974 aerr("'%s' needs chunks, but none found\n", g_func);
7975 func_chunk_i = ci - func_chunks;
7976 for (; func_chunk_i > 0; func_chunk_i--)
7977 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
7980 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
7982 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
7983 asmln = func_chunks[func_chunk_i].asmln;
7991 if (wordc == 2 && IS(words[1], "ends")) {
7995 goto do_pending_endp;
7999 // scan for next text segment
8000 while (my_fgets(line, sizeof(line), fasm)) {
8003 if (*p == 0 || *p == ';')
8006 if (strstr(p, "segment para public 'CODE' use32"))
8013 p = strchr(words[0], ':');
8015 set_label(pi, words[0]);
8019 if (!in_func || g_skip_func) {
8020 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
8022 anote("skipping from '%s'\n", g_labels[pi]);
8026 g_labels[pi] = NULL;
8030 if (wordc > 1 && IS(words[1], "="))
8033 aerr("unhandled equ, wc=%d\n", wordc);
8034 if (g_eqcnt >= eq_alloc) {
8036 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
8037 my_assert_not(g_eqs, NULL);
8040 len = strlen(words[0]);
8041 if (len > sizeof(g_eqs[0].name) - 1)
8042 aerr("equ name too long: %d\n", len);
8043 strcpy(g_eqs[g_eqcnt].name, words[0]);
8045 if (!IS(words[3], "ptr"))
8046 aerr("unhandled equ\n");
8047 if (IS(words[2], "dword"))
8048 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
8049 else if (IS(words[2], "word"))
8050 g_eqs[g_eqcnt].lmod = OPLM_WORD;
8051 else if (IS(words[2], "byte"))
8052 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
8053 else if (IS(words[2], "qword"))
8054 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
8056 aerr("bad lmod: '%s'\n", words[2]);
8058 g_eqs[g_eqcnt].offset = parse_number(words[4]);
8063 if (pi >= ARRAY_SIZE(ops))
8064 aerr("too many ops\n");
8066 parse_op(&ops[pi], words, wordc);
8068 if (sctproto != NULL) {
8069 if (ops[pi].op == OP_CALL || ops[pi].op == OP_JMP)
8070 ops[pi].datap = sctproto;
8086 // vim:ts=2:shiftwidth=2:expandtab