X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=tools%2Ftranslate.c;h=1ae5c27e76e115e5b10cf2959c3bd9fa7b9c591b;hb=eadfb2b62ac7f81f1d8483e208b84e60031b448d;hp=79413a278af31c7a78889c2369f2be27c7303430;hpb=354f5504799c060e73037aa5de26da9ab75c2289;p=ia32rtools.git diff --git a/tools/translate.c b/tools/translate.c index 79413a2..1ae5c27 100644 --- a/tools/translate.c +++ b/tools/translate.c @@ -96,6 +96,8 @@ enum op_op { OP_MOVS, OP_CMPS, OP_SCAS, + OP_RDTSC, + OP_CPUID, OP_STD, OP_CLD, OP_RET, @@ -282,8 +284,9 @@ enum ida_func_attr { enum sct_func_attr { SCTFA_CLEAR_SF = (1 << 0), // clear stack frame SCTFA_CLEAR_REGS = (1 << 1), // clear registers (mask) - SCTFA_RM_REGS = (1 << 2), // don't emit regs + SCTFA_RM_REGS = (1 << 2), // don't emit regs (mask) SCTFA_NOWARN = (1 << 3), // don't try to detect problems + SCTFA_ARGFRAME = (1 << 4), // copy all args to a struct, in order }; enum x87_const { @@ -376,6 +379,7 @@ enum x86_regs { }; #define mxAX (1 << xAX) +#define mxBX (1 << xBX) #define mxCX (1 << xCX) #define mxDX (1 << xDX) #define mxSP (1 << xSP) @@ -954,7 +958,7 @@ static const struct { { "repz", OPF_REP|OPF_REPZ }, { "repne", OPF_REP|OPF_REPNZ }, { "repnz", OPF_REP|OPF_REPNZ }, - { "lock", OPF_LOCK }, // ignored for now.. + { "lock", OPF_LOCK }, }; #define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC) @@ -998,6 +1002,8 @@ static const struct { { "scasb",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS }, { "scasw",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS }, { "scasd",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS }, + { "rdtsc",OP_RDTSC, 0, 0, OPF_DATA }, + { "cpuid",OP_CPUID, 0, 0, OPF_DATA }, { "std", OP_STD, 0, 0, OPF_DATA }, // special flag { "cld", OP_CLD, 0, 0, OPF_DATA }, { "add", OP_ADD, 2, 2, OPF_DATA|OPF_FLAGS }, @@ -1325,6 +1331,16 @@ static void parse_op(struct parsed_op *op, char words[16][256], int wordc) op->regmask_dst = op->regmask_src; break; + case OP_RDTSC: + op->regmask_dst = mxAX | mxDX; + break; + + case OP_CPUID: + // for now, ignore ecx dep for eax={4,7,b,d} + op->regmask_src = mxAX; + op->regmask_dst = mxAX | mxBX | mxCX | mxDX; + break; + case OP_LOOP: op->regmask_dst = 1 << xCX; // fallthrough @@ -1926,6 +1942,7 @@ static int stack_frame_access(struct parsed_op *po, const char *prefix = ""; const char *bp_arg = NULL; char ofs_reg[16] = { 0, }; + char argname[8]; int i, arg_i, arg_s; int unaligned = 0; int stack_ra = 0; @@ -1956,7 +1973,7 @@ static int stack_frame_access(struct parsed_op *po, snprintf(buf, buf_size, "%sap", cast); return -1; } - ferr(po, "offset %d (%s,%d) doesn't map to any arg\n", + ferr(po, "offset 0x%x (%s,%d) doesn't map to any arg\n", offset, bp_arg, arg_i); } if (ofs_reg[0] != 0) @@ -1975,17 +1992,20 @@ static int stack_frame_access(struct parsed_op *po, popr->is_ptr = g_func_pp->arg[i].type.is_ptr; retval = i; + snprintf(argname, sizeof(argname), "%sa%d", + g_sct_func_attr & SCTFA_ARGFRAME ? "af." : "", i + 1); + switch (popr->lmod) { case OPLM_BYTE: if (is_lea) ferr(po, "lea/byte to arg?\n"); if (is_src && (offset & 3) == 0) - snprintf(buf, buf_size, "%sa%d", - simplify_cast(cast, "(u8)"), i + 1); + snprintf(buf, buf_size, "%s%s", + simplify_cast(cast, "(u8)"), argname); else - snprintf(buf, buf_size, "%sBYTE%d(a%d)", - cast, offset & 3, i + 1); + snprintf(buf, buf_size, "%sBYTE%d(%s)", + cast, offset & 3, argname); break; case OPLM_WORD: @@ -1996,18 +2016,18 @@ static int stack_frame_access(struct parsed_op *po, if (!is_src) { if (offset & 2) ferr(po, "problematic arg store\n"); - snprintf(buf, buf_size, "%s((char *)&a%d + 1)", - simplify_cast(cast, "*(u16 *)"), i + 1); + snprintf(buf, buf_size, "%s((char *)&%s + 1)", + simplify_cast(cast, "*(u16 *)"), argname); } else ferr(po, "unaligned arg word load\n"); } else if (is_src && (offset & 2) == 0) - snprintf(buf, buf_size, "%sa%d", - simplify_cast(cast, "(u16)"), i + 1); + snprintf(buf, buf_size, "%s%s", + simplify_cast(cast, "(u16)"), argname); else - snprintf(buf, buf_size, "%s%sWORD(a%d)", - cast, (offset & 2) ? "HI" : "LO", i + 1); + snprintf(buf, buf_size, "%s%sWORD(%s)", + cast, (offset & 2) ? "HI" : "LO", argname); break; case OPLM_DWORD: @@ -2019,19 +2039,19 @@ static int stack_frame_access(struct parsed_op *po, if (offset & 3) { unaligned = 1; if (is_lea) - snprintf(buf, buf_size, "(u32)&a%d + %d", - i + 1, offset & 3); + snprintf(buf, buf_size, "(u32)&%s + %d", + argname, offset & 3); else if (!is_src) ferr(po, "unaligned arg store\n"); else { // mov edx, [ebp+arg_4+2]; movsx ecx, dx - snprintf(buf, buf_size, "%s(a%d >> %d)", - prefix, i + 1, (offset & 3) * 8); + snprintf(buf, buf_size, "%s(%s >> %d)", + prefix, argname, (offset & 3) * 8); } } else { - snprintf(buf, buf_size, "%s%sa%d", - prefix, is_lea ? "&" : "", i + 1); + snprintf(buf, buf_size, "%s%s%s", + prefix, is_lea ? "&" : "", argname); } break; @@ -2039,8 +2059,8 @@ static int stack_frame_access(struct parsed_op *po, ferr_assert(po, !(offset & 7)); if (cast[0]) prefix = cast; - snprintf(buf, buf_size, "%s%sa%d", - prefix, is_lea ? "&" : "", i + 1); + snprintf(buf, buf_size, "%s%s%s", + prefix, is_lea ? "&" : "", argname); break; default: @@ -3525,6 +3545,11 @@ static const struct parsed_proto *try_recover_pp( char buf[256]; char *p; + if (po->pp != NULL && (po->flags & OPF_DATA)) { + // hint given in asm + return po->pp; + } + // maybe an arg of g_func? if (opr->type == OPT_REGMEM && is_stack_access(po, opr)) { @@ -3917,8 +3942,10 @@ static void resolve_branches_parse_calls(int opcnt) && IS(po->operand[0].name, g_labels[l])) { if (l == i + 1 && po->op == OP_JMP) { - // yet another alignment type.. - po->flags |= OPF_RMD|OPF_DONE; + // yet another alignment type... + po->flags |= OPF_RMD | OPF_DONE; + po->flags &= ~OPF_JMP; + po->op = OP_NOP; break; } add_label_ref(&g_label_refs[l], i); @@ -4146,9 +4173,72 @@ static void eliminate_seh_calls(int opcnt) eliminate_seh_finally(opcnt); } +// check for prologue of many pushes and epilogue with pops +static void check_simple_sequence(int opcnt, int *fsz) +{ + int found = 0; + int seq_len; + int seq_p; + int seq[4]; + int reg; + int i, j; + + for (i = 0; i < opcnt && i < ARRAY_SIZE(seq); i++) { + if (ops[i].op != OP_PUSH || ops[i].operand[0].type != OPT_REG) + break; + reg = ops[i].operand[0].reg; + if (reg != xBX && reg != xSI && reg != xDI && reg != xBP) + break; + for (j = 0; j < i; j++) + if (seq[j] == reg) + break; + if (j != i) + // probably something else is going on here + break; + seq[i] = reg; + } + seq_len = i; + if (seq_len == 0) + return; + + for (; i < opcnt && seq_len > 0; i++) { + if (!(ops[i].flags & OPF_TAIL)) + continue; + + for (j = i - 1, seq_p = 0; j >= 0 && seq_p < seq_len; j--) { + if (ops[j].op != OP_POP || ops[j].operand[0].type != OPT_REG) + break; + if (ops[j].operand[0].reg != seq[seq_p]) + break; + seq_p++; + } + found = seq_len = seq_p; + } + if (!found) + return; + + for (i = 0; i < seq_len; i++) + ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS; + + for (; i < opcnt && seq_len > 0; i++) { + if (!(ops[i].flags & OPF_TAIL)) + continue; + + for (j = i - 1, seq_p = 0; j >= 0 && seq_p < seq_len; j--) { + ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS; + seq_p++; + } + } + + // unlike pushes after sub esp, + // IDA treats pushed like this as part of var area + *fsz += seq_len * 4; +} + static int scan_prologue(int i, int opcnt, int *ecx_push, int *esp_sub) { - int j; + const char *name; + int j, len, ret; for (; i < opcnt; i++) if (!(ops[i].flags & OPF_DONE)) @@ -4175,6 +4265,19 @@ static int scan_prologue(int i, int opcnt, int *ecx_push, int *esp_sub) *esp_sub = 1; break; } + if (ops[i].op == OP_LEA && ops[i].operand[0].reg == xSP + && ops[i].operand[1].type == OPT_REGMEM + && IS_START(ops[i].operand[1].name, "esp-")) + { + name = ops[i].operand[1].name; + ret = sscanf(name, "esp-%x%n", &j, &len); + ferr_assert(&ops[i], ret == 1 && len == strlen(name)); + g_stack_fsz += j; + ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS; + i++; + *esp_sub = 1; + break; + } if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX && ops[i].operand[1].type == OPT_CONST) { @@ -4201,7 +4304,8 @@ static void scan_prologue_epilogue(int opcnt, int *stack_align) { int ecx_push = 0, esp_sub = 0, pusha = 0; int sandard_epilogue; - int found; + int found, ret, len; + int push_fsz = 0; int i, j, l; if (g_seh_found == 2) { @@ -4325,6 +4429,7 @@ static void scan_prologue_epilogue(int opcnt, int *stack_align) } // non-bp frame + check_simple_sequence(opcnt, &push_fsz); i = scan_prologue(0, opcnt, &ecx_push, &esp_sub); if (ecx_push && !esp_sub) { @@ -4389,6 +4494,12 @@ static void scan_prologue_epilogue(int opcnt, int *stack_align) } } + for (; j >= 0; j--) { + if ((ops[j].flags & (OPF_RMD | OPF_DONE | OPF_NOREGS)) != + (OPF_RMD | OPF_DONE | OPF_NOREGS)) + break; + } + if (ecx_push > 0 && !esp_sub) { for (l = 0; l < ecx_push && j >= 0; l++) { if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx")) @@ -4422,28 +4533,37 @@ static void scan_prologue_epilogue(int opcnt, int *stack_align) } if (esp_sub) { - if (ops[j].op != OP_ADD - || !IS(opr_name(&ops[j], 0), "esp") - || ops[j].operand[1].type != OPT_CONST) + if (ops[j].op == OP_ADD + && IS(opr_name(&ops[j], 0), "esp") + && ops[j].operand[1].type == OPT_CONST) { - if (i < opcnt && ops[i].op == OP_CALL - && ops[i].pp != NULL && ops[i].pp->is_noreturn) - { - // noreturn tailcall with no epilogue - i++; - found = 1; - continue; - } - ferr(&ops[j], "'add esp' expected\n"); - } + if (ops[j].operand[1].val < g_stack_fsz) + ferr(&ops[j], "esp adj is too low (need %d)\n", g_stack_fsz); - if (ops[j].operand[1].val < g_stack_fsz) - ferr(&ops[j], "esp adj is too low (need %d)\n", g_stack_fsz); - - ops[j].operand[1].val -= g_stack_fsz; // for stack arg scanner - if (ops[j].operand[1].val == 0) + ops[j].operand[1].val -= g_stack_fsz; // for stack arg scanner + if (ops[j].operand[1].val == 0) + ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS; + found = 1; + } + else if (ops[j].op == OP_LEA && ops[j].operand[0].reg == xSP + && ops[j].operand[1].type == OPT_REGMEM + && IS_START(ops[j].operand[1].name, "esp+")) + { + const char *name = ops[j].operand[1].name; + ret = sscanf(name, "esp+%x%n", &l, &len); + ferr_assert(&ops[j], ret == 1 && len == strlen(name)); + ferr_assert(&ops[j], l <= g_stack_fsz); ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS; - found = 1; + found = 1; + } + else if (i < opcnt && ops[i].op == OP_CALL + && ops[i].pp != NULL && ops[i].pp->is_noreturn) + { + // noreturn tailcall with no epilogue + found = 1; + } + else + ferr(&ops[j], "'add esp' expected\n"); } i++; @@ -4452,6 +4572,10 @@ static void scan_prologue_epilogue(int opcnt, int *stack_align) if (!found) ferr(ops, "missing esp epilogue\n"); } + + if (g_stack_fsz != 0) + // see check_simple_sequence + g_stack_fsz += push_fsz; } // find an instruction that changed opr before i op @@ -5902,6 +6026,7 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) int need_double = 0; int stack_align = 0; int stack_fsz_adj = 0; + int lock_handled = 0; int regmask_save = 0; // used regs saved/restored in this func int regmask_arg; // regs from this function args (fastcall, etc) int regmask_ret; // regs needed on ret @@ -6320,6 +6445,7 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) need_double = 1; break; + case OP_RDTSC: case OPP_ALLSHL: case OPP_ALLSHR: need_tmp64 = 1; @@ -6458,6 +6584,28 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) had_decl = 1; } + if ((g_sct_func_attr & SCTFA_ARGFRAME) && g_func_pp->argc_stack) { + fprintf(fout, " struct { u32 "); + for (i = j = 0; i < g_func_pp->argc; i++) { + if (g_func_pp->arg[i].reg != NULL) + continue; + if (j++ != 0) + fprintf(fout, ", "); + fprintf(fout, "a%d", i + 1); + } + fprintf(fout, "; } af = {\n "); + for (i = j = 0; i < g_func_pp->argc; i++) { + if (g_func_pp->arg[i].reg != NULL) + continue; + if (j++ != 0) + fprintf(fout, ", "); + if (g_func_pp->arg[i].type.is_ptr) + fprintf(fout, "(u32)"); + fprintf(fout, "a%d", i + 1); + } + fprintf(fout, "\n };\n"); + } + if (g_func_pp->is_userstack) { fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name); fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n"); @@ -6645,6 +6793,7 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) if (po->flags & OPF_RMD) continue; + lock_handled = 0; no_output = 0; #define assert_operand_cnt(n_) \ @@ -6822,9 +6971,10 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n", (po->flags & OPF_DF) ? '-' : '+', lmod_bytes(po, po->operand[1].lmod)); - fprintf(fout, " %sedi = eax;", + fprintf(fout, " %sedi = eax;\n", lmod_cast_u_ptr(po, po->operand[1].lmod)); - strcpy(g_comment, "rep stos"); + fprintf(fout, " barrier();"); + strcpy(g_comment, "^ rep stos"); } else { assert_operand_cnt(2); @@ -6846,8 +6996,10 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n", l, j, l, j); fprintf(fout, - " %sedi = %sesi;", buf1, buf1); - strcpy(g_comment, "rep movs"); + " %sedi = %sesi;\n", buf1, buf1); + // this can overwrite many variables + fprintf(fout, " barrier();"); + strcpy(g_comment, "^ rep movs"); } else { assert_operand_cnt(2); @@ -6930,6 +7082,16 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) delayed_flag_op = NULL; break; + case OP_RDTSC: + fprintf(fout, " tmp64 = ext_rdtsc();\n"); + fprintf(fout, " edx = tmp64 >> 32;\n"); + fprintf(fout, " eax = tmp64;"); + break; + + case OP_CPUID: + fprintf(fout, " ext_cpuid(&eax, &ebx, &ecx, &edx);"); + break; + // arithmetic w/flags case OP_AND: if (po->operand[1].type == OPT_CONST && !po->operand[1].val) @@ -7233,9 +7395,18 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]); if (po->operand[0].type == OPT_REG) { + ferr_assert(po, !(po->flags & OPF_LOCK)); strcpy(buf2, po->op == OP_INC ? "++" : "--"); fprintf(fout, " %s%s;", buf1, buf2); } + else if (po->flags & OPF_LOCK) { + out_src_opr(buf2, sizeof(buf2), po, &po->operand[0], "", 1); + fprintf(fout, " __sync_fetch_and_%s((%s *)(%s), 1);", + po->op == OP_INC ? "add" : "sub", + lmod_type_u(po, po->operand[0].lmod), buf2); + strcat(g_comment, " lock"); + lock_handled = 1; + } else { strcpy(buf2, po->op == OP_INC ? "+" : "-"); fprintf(fout, " %s %s= 1;", buf1, buf2); @@ -8095,6 +8266,9 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) if (pfomask != 0) ferr(po, "missed flag calc, pfomask=%x\n", pfomask); + if ((po->flags & OPF_LOCK) && !lock_handled) + ferr(po, "unhandled lock\n"); + // see is delayed flag stuff is still valid if (delayed_flag_op != NULL && delayed_flag_op != po) { if (is_any_opr_modified(delayed_flag_op, po, 0)) @@ -9427,6 +9601,7 @@ int main(int argc, char *argv[]) "clear_regmask", "rm_regmask", "nowarn", + "argframe", }; // parse manual attribute-list comment @@ -9550,16 +9725,18 @@ parse_words: continue; goto parse_words; // lame } - if (IS_START(p, "; sctproto:")) { - sctproto = strdup(p + 11); - } else if (IS_START(p, "; sctend")) { end = 1; if (!pending_endp) break; } + else if (g_skip_func) + /* ignore remaining attrs */; + else if (IS_START(p, "; sctproto:")) { + sctproto = strdup(p + 11); + } else if (IS_START(p, "; sctskip_start")) { - if (in_func && !g_skip_func) { + if (in_func) { if (!skip_code) { ops[pi].op = OPP_ABORT; ops[pi].asmln = asmln;