X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=ia32rtools.git;a=blobdiff_plain;f=tools%2Ftranslate.c;h=a7f629ee4dccea9daee3ec74244d93a334112aba;hp=dadf7a915098cf64c3d2c4acebca801228046f30;hb=497a6d6b4c2992fc9cbd2591985d108bc8859f72;hpb=d4a985bd88473515445c6f9f0ae51be9895b9d60 diff --git a/tools/translate.c b/tools/translate.c index dadf7a9..a7f629e 100644 --- a/tools/translate.c +++ b/tools/translate.c @@ -136,6 +136,11 @@ enum op_op { OP_FISUB, OP_FIDIVR, OP_FISUBR, + OP_FCOS, + OP_FPATAN, + OP_FPTAN, + OP_FSIN, + OP_FSQRT, // mmx OP_EMMS, // pseudo-ops for lib calls @@ -208,7 +213,8 @@ struct parsed_op { }; // datap: -// OP_CALL - parser proto hint (str) +// on start: function/data type hint (sctproto) +// after analysis: // (OPF_CC) - points to one of (OPF_FLAGS) that affects cc op // OP_PUSH - points to OP_POP in complex push/pop graph // OP_POP - points to OP_PUSH in simple push/pop pair @@ -248,6 +254,11 @@ enum ida_func_attr { IDAFA_FPD = (1 << 5), }; +enum sct_func_attr { + SCTFA_CLEAR_SF = (1 << 0), // clear stack frame + SCTFA_CLEAR_REGS = (1 << 1), // clear registers (mask) +}; + enum x87_const { X87_CONST_1 = 1, X87_CONST_2T, @@ -278,6 +289,10 @@ static int g_sp_frame; static int g_stack_frame_used; static int g_stack_fsz; static int g_ida_func_attr; +static int g_sct_func_attr; +static int g_stack_clear_start; // in dwords +static int g_stack_clear_len; +static int g_regmask_init; static int g_skip_func; static int g_allow_regfunc; static int g_quiet_pp; @@ -318,6 +333,7 @@ enum x86_regs { }; #define mxAX (1 << xAX) +#define mxCX (1 << xCX) #define mxDX (1 << xDX) #define mxST0 (1 << xST0) #define mxST1 (1 << xST1) @@ -641,7 +657,7 @@ static char *default_cast_to(char *buf, size_t buf_size, { buf[0] = 0; - if (!opr->is_ptr) + if (!opr->is_ptr || strchr(opr->name, '[')) return buf; if (opr->pp == NULL || opr->pp->type.name == NULL || opr->pp->is_fptr) @@ -1034,6 +1050,11 @@ static const struct { { "fisub", OP_FISUB, 1, 1, 0 }, { "fidivr", OP_FIDIVR, 1, 1, 0 }, { "fisubr", OP_FISUBR, 1, 1, 0 }, + { "fcos", OP_FCOS, 0, 0, 0 }, + { "fpatan", OP_FPATAN, 0, 0, OPF_FPOP }, + { "fptan", OP_FPTAN, 0, 0, OPF_FPUSH }, + { "fsin", OP_FSIN, 0, 0, 0 }, + { "fsqrt", OP_FSQRT, 0, 0, 0 }, // mmx { "emms", OP_EMMS, 0, 0, OPF_DATA }, { "movq", OP_MOV, 2, 2, OPF_DATA }, @@ -1361,10 +1382,22 @@ static void parse_op(struct parsed_op *op, char words[16][256], int wordc) case OP_FISUB: case OP_FIDIVR: case OP_FISUBR: + case OP_FCOS: + case OP_FSIN: + case OP_FSQRT: op->regmask_src |= mxST0; op->regmask_dst |= mxST0; break; + case OP_FPATAN: + op->regmask_src |= mxST0 | mxST1; + op->regmask_dst |= mxST0; + break; + + case OP_FPTAN: + aerr("TODO\n"); + break; + default: break; } @@ -3450,17 +3483,31 @@ static int get_pp_arg_regmask_src(const struct parsed_proto *pp) static int get_pp_arg_regmask_dst(const struct parsed_proto *pp) { + int regmask = 0; + int i, reg; + + if (pp->has_retreg) { + for (i = 0; i < pp->argc; i++) { + if (pp->arg[i].type.is_retreg) { + reg = char_array_i(regs_r32, + ARRAY_SIZE(regs_r32), pp->arg[i].reg); + ferr_assert(ops, reg >= 0); + regmask |= 1 << reg; + } + } + } + if (strstr(pp->ret_type.name, "int64")) - return (1 << xAX) | (1 << xDX); + return regmask | (1 << xAX) | (1 << xDX); if (IS(pp->ret_type.name, "float") || IS(pp->ret_type.name, "double")) { - return mxST0; + return regmask | mxST0; } if (strcasecmp(pp->ret_type.name, "void") == 0) - return 0; + return regmask; - return mxAX; + return regmask | mxAX; } static void resolve_branches_parse_calls(int opcnt) @@ -3488,10 +3535,25 @@ static void resolve_branches_parse_calls(int opcnt) po->bt_i = -1; po->btj = NULL; + if (po->datap != NULL) { + pp = calloc(1, sizeof(*pp)); + my_assert_not(pp, NULL); + + ret = parse_protostr(po->datap, pp); + if (ret < 0) + ferr(po, "bad protostr supplied: %s\n", (char *)po->datap); + free(po->datap); + po->datap = NULL; + po->pp = pp; + } + if (po->op == OP_CALL) { pp = NULL; - if (po->operand[0].type == OPT_LABEL) { + if (po->pp != NULL) + pp = po->pp; + else if (po->operand[0].type == OPT_LABEL) + { tmpname = opr_name(po, 0); if (IS_START(tmpname, "loc_")) ferr(po, "call to loc_*\n"); @@ -3521,16 +3583,6 @@ static void resolve_branches_parse_calls(int opcnt) my_assert_not(pp, NULL); } } - else if (po->datap != NULL) { - pp = calloc(1, sizeof(*pp)); - my_assert_not(pp, NULL); - - ret = parse_protostr(po->datap, pp); - if (ret < 0) - ferr(po, "bad protostr supplied: %s\n", (char *)po->datap); - free(po->datap); - po->datap = NULL; - } if (pp != NULL) { if (pp->is_fptr) @@ -3807,36 +3859,11 @@ static void scan_prologue_epilogue(int opcnt) } } -static const struct parsed_proto *resolve_icall(int i, int opcnt, - int *pp_i, int *multi_src) -{ - const struct parsed_proto *pp = NULL; - int search_advice = 0; - - *multi_src = 0; - *pp_i = -1; - - switch (ops[i].operand[0].type) { - case OPT_REGMEM: - case OPT_LABEL: - case OPT_OFFSET: - pp = try_recover_pp(&ops[i], &ops[i].operand[0], &search_advice); - if (!search_advice) - break; - // fallthrough - default: - scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp, - pp_i, multi_src); - break; - } - - return pp; -} - // find an instruction that changed opr before i op // *op_i must be set to -1 by the caller -// *entry is set to 1 if one source is determined to be the caller +// *is_caller is set to 1 if one source is determined to be g_func arg // returns 1 if found, *op_i is then set to origin +// returns -1 if multiple origins are found static int resolve_origin(int i, const struct parsed_opr *opr, int magic, int *op_i, int *is_caller) { @@ -4015,6 +4042,96 @@ static int try_resolve_const(int i, const struct parsed_opr *opr, return -1; } +static const struct parsed_proto *resolve_icall(int i, int opcnt, + int *pp_i, int *multi_src) +{ + const struct parsed_proto *pp = NULL; + int search_advice = 0; + int offset = -1; + char name[256]; + char s_reg[4]; + int reg, len; + int ret; + + *multi_src = 0; + *pp_i = -1; + + switch (ops[i].operand[0].type) { + case OPT_REGMEM: + // try to resolve struct member calls + ret = sscanf(ops[i].operand[0].name, "%3s+%x%n", + s_reg, &offset, &len); + if (ret == 2 && len == strlen(ops[i].operand[0].name)) + { + reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg); + if (reg >= 0) { + struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, reg); + int j = -1; + ret = resolve_origin(i, &opr, i + opcnt * 19, &j, NULL); + if (ret != 1) + break; + if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM + && ops[j].operand[0].lmod == OPLM_DWORD + && ops[j].pp == NULL) // no hint + { + // allow one simple dereference (directx) + reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), + ops[j].operand[1].name); + if (reg < 0) + break; + struct parsed_opr opr2 = OPR_INIT(OPT_REG, OPLM_DWORD, reg); + int k = -1; + ret = resolve_origin(j, &opr2, j + opcnt * 19, &k, NULL); + if (ret != 1) + break; + j = k; + } + if (ops[j].op != OP_MOV) + break; + if (ops[j].operand[0].lmod != OPLM_DWORD) + break; + if (ops[j].pp != NULL) { + // type hint in asm + pp = ops[j].pp; + } + else if (ops[j].operand[1].type == OPT_REGMEM) { + // allow 'hello[ecx]' - assume array of same type items + ret = sscanf(ops[j].operand[1].name, "%[^[][e%2s]", + name, s_reg); + if (ret != 2) + break; + pp = proto_parse(g_fhdr, name, g_quiet_pp); + } + else if (ops[j].operand[1].type == OPT_LABEL) + pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp); + else + break; + if (pp == NULL) + break; + if (pp->is_func || pp->is_fptr || !pp->type.is_struct) { + pp = NULL; + break; + } + pp = proto_lookup_struct(g_fhdr, pp->type.name, offset); + } + break; + } + // fallthrough + case OPT_LABEL: + case OPT_OFFSET: + pp = try_recover_pp(&ops[i], &ops[i].operand[0], &search_advice); + if (!search_advice) + break; + // fallthrough + default: + scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp, + pp_i, multi_src); + break; + } + + return pp; +} + static struct parsed_proto *process_call_early(int i, int opcnt, int *adj_i) { @@ -4679,21 +4796,6 @@ static void reg_use_pass(int i, int opcnt, unsigned char *cbits, if (g_bp_frame && !(po->flags & OPF_EBP_S)) regmask_new &= ~(1 << xBP); - if (po->op == OP_CALL) { - // allow fastcall calls from anywhere, calee may be also sitting - // in some fastcall table even when it's not using reg args - if (regmask_new & po->regmask_src & (1 << xCX)) { - *regmask_init |= (1 << xCX); - regmask_now |= (1 << xCX); - regmask_new &= ~(1 << xCX); - } - if (regmask_new & po->regmask_src & (1 << xDX)) { - *regmask_init |= (1 << xDX); - regmask_now |= (1 << xDX); - regmask_new &= ~(1 << xDX); - } - } - if (regmask_new != 0) fnote(po, "uninitialized reg mask: %x\n", regmask_new); @@ -4723,7 +4825,10 @@ static void reg_use_pass(int i, int opcnt, unsigned char *cbits, if (po->flags & OPF_TAIL) { if (regmask_now & (mxST0 | mxST1)) ferr(po, "float regs on tail: %x\n", regmask_now); - return; + + // there is support for "conditional tailcall", sort of + if (!(po->flags & OPF_CC)) + return; } } } @@ -4848,11 +4953,13 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) unsigned int uval; int save_arg_vars[MAX_ARG_GRP] = { 0, }; unsigned char cbits[MAX_OPS / 8]; + const char *float_type; int cond_vars = 0; int need_tmp_var = 0; int need_tmp64 = 0; int had_decl = 0; int label_pending = 0; + int need_double = 0; int regmask_save = 0; // regs saved/restored in this func int regmask_arg; // regs from this function args (fastcall, etc) int regmask_ret; // regs needed on ret @@ -4870,6 +4977,8 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) g_bp_frame = g_sp_frame = g_stack_fsz = 0; g_stack_frame_used = 0; + if (g_sct_func_attr & SCTFA_CLEAR_REGS) + regmask_init = g_regmask_init; g_func_pp = proto_parse(fhdr, funcn, 0); if (g_func_pp == NULL) @@ -4878,17 +4987,6 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) regmask_arg = get_pp_arg_regmask_src(g_func_pp); regmask_ret = get_pp_arg_regmask_dst(g_func_pp); - if (g_func_pp->has_retreg) { - for (arg = 0; arg < g_func_pp->argc; arg++) { - if (g_func_pp->arg[arg].type.is_retreg) { - reg = char_array_i(regs_r32, - ARRAY_SIZE(regs_r32), g_func_pp->arg[arg].reg); - ferr_assert(ops, reg >= 0); - regmask_ret |= 1 << reg; - } - } - } - // pass1: // - resolve all branches // - parse calls with labels @@ -5007,7 +5105,7 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) // - find POPs for PUSHes, rm both // - scan for all used registers memset(cbits, 0, sizeof(cbits)); - reg_use_pass(0, opcnt, cbits, 0, ®mask, + reg_use_pass(0, opcnt, cbits, regmask_init, ®mask, 0, ®mask_save, ®mask_init, regmask_arg); // pass7: @@ -5178,11 +5276,15 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) if (j == -1) po->flags |= OPF_32BIT; } + else if (po->op == OP_FLD && po->operand[0].lmod == OPLM_QWORD) + need_double = 1; if (po->op == OP_RCL || po->op == OP_RCR || po->op == OP_XCHG) need_tmp_var = 1; } + float_type = need_double ? "double" : "float"; + // output starts here // define userstack size @@ -5342,7 +5444,7 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) if (regmask_now & 0xff0000) { for (reg = 16; reg < 24; reg++) { if (regmask_now & (1 << reg)) { - fprintf(fout, " double f_st%d", reg - 16); + fprintf(fout, " %s f_st%d", float_type, reg - 16); if (regmask_init & (1 << reg)) fprintf(fout, " = 0"); fprintf(fout, ";\n"); @@ -5404,6 +5506,24 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) if (had_decl) fprintf(fout, "\n"); + // do stack clear, if needed + if (g_sct_func_attr & SCTFA_CLEAR_SF) { + fprintf(fout, " "); + if (g_stack_clear_len != 0) { + if (g_stack_clear_len <= 4) { + for (i = 0; i < g_stack_clear_len; i++) + fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i); + fprintf(fout, "0;\n"); + } + else { + fprintf(fout, "memset(&sf[%d], 0, %d);\n", + g_stack_clear_start, g_stack_clear_len * 4); + } + } + else + fprintf(fout, "memset(&sf, 0, sizeof(sf));\n"); + } + if (g_func_pp->is_vararg) { if (g_func_pp->argc_stack == 0) ferr(ops, "vararg func without stack args?\n"); @@ -6467,7 +6587,7 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) case OP_FILD: if (po->flags & OPF_FSHIFT) fprintf(fout, " f_st1 = f_st0;\n"); - fprintf(fout, " f_st0 = (double)%s;", + fprintf(fout, " f_st0 = (%s)%s;", float_type, out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], lmod_cast(po, po->operand[0].lmod, 1), 0)); strcat(g_comment, " fild"); @@ -6543,7 +6663,7 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) case OP_FISUB: j = '-'; break; default: j = 'x'; break; } - fprintf(fout, " f_st0 %c= (double)%s;", j, + fprintf(fout, " f_st0 %c= (%s)%s;", j, float_type, out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], lmod_cast(po, po->operand[0].lmod, 1), 0)); break; @@ -6555,6 +6675,26 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) po->op == OP_FIDIVR ? '/' : '-'); break; + case OP_FCOS: + fprintf(fout, " f_st0 = cos%s(f_st0);", + need_double ? "" : "f"); + break; + + case OP_FPATAN: + fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);", + need_double ? "" : "f"); + break; + + case OP_FSIN: + fprintf(fout, " f_st0 = sin%s(f_st0);", + need_double ? "" : "f"); + break; + + case OP_FSQRT: + fprintf(fout, " f_st0 = sqrt%s(f_st0);", + need_double ? "" : "f"); + break; + case OPP_FTOL: ferr_assert(po, po->flags & OPF_32BIT); fprintf(fout, " eax = (s32)f_st0;"); @@ -6682,10 +6822,13 @@ static struct scanned_var { } *hg_vars; static int hg_var_cnt; +static char **hg_refs; +static int hg_ref_cnt; + static void output_hdr_fp(FILE *fout, const struct func_prototype *fp, int count); -struct func_prototype *hg_fp_add(const char *funcn) +static struct func_prototype *hg_fp_add(const char *funcn) { struct func_prototype *fp; @@ -6747,6 +6890,19 @@ static int hg_fp_cmp_id(const void *p1_, const void *p2_) } #endif +static void hg_ref_add(const char *name) +{ + if ((hg_ref_cnt & 0xff) == 0) { + hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100)); + my_assert_not(hg_refs, NULL); + memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100); + } + + hg_refs[hg_ref_cnt] = strdup(name); + my_assert_not(hg_refs[hg_ref_cnt], NULL); + hg_ref_cnt++; +} + // recursive register dep pass // - track saved regs (part 2) // - try to figure out arg-regs @@ -7101,6 +7257,24 @@ static void hg_fp_resolve_deps(struct func_prototype *fp) } } +// make all thiscall/edx arg functions referenced from .data fastcall +static void do_func_refs_from_data(void) +{ + struct func_prototype *fp, fp_s; + int i; + + for (i = 0; i < hg_ref_cnt; i++) { + strcpy(fp_s.name, hg_refs[i]); + fp = bsearch(&fp_s, hg_fp, hg_fp_cnt, + sizeof(hg_fp[0]), hg_fp_cmp_name); + if (fp == NULL) + continue; + + if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX))) + fp->regmask_dep |= mxCX | mxDX; + } +} + static void output_hdr_fp(FILE *fout, const struct func_prototype *fp, int count) { @@ -7108,7 +7282,7 @@ static void output_hdr_fp(FILE *fout, const struct func_prototype *fp, char *p, namebuf[NAMELEN]; const char *name; int regmask_dep; - int argc_stack; + int argc_normal; int j, arg; for (; count > 0; count--, fp++) { @@ -7146,18 +7320,25 @@ static void output_hdr_fp(FILE *fout, const struct func_prototype *fp, } regmask_dep = fp->regmask_dep; - argc_stack = fp->argc_stack; + argc_normal = fp->argc_stack; fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name : (fp->has_ret ? "int" : "void")); - if (regmask_dep && (fp->is_stdcall || argc_stack == 0) - && (regmask_dep & ~((1 << xCX) | (1 << xDX))) == 0) + if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0) + && (regmask_dep & ~mxCX) == 0) + { + fprintf(fout, "/*__thiscall*/ "); + argc_normal++; + regmask_dep = 0; + } + else if (regmask_dep && (fp->is_stdcall || fp->argc_stack == 0) + && (regmask_dep & ~(mxCX | mxDX)) == 0) { fprintf(fout, " __fastcall "); - if (!(regmask_dep & (1 << xDX)) && argc_stack == 0) - argc_stack = 1; + if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0) + argc_normal = 1; else - argc_stack += 2; + argc_normal += 2; regmask_dep = 0; } else if (regmask_dep && !fp->is_stdcall) { @@ -7187,7 +7368,7 @@ static void output_hdr_fp(FILE *fout, const struct func_prototype *fp, } } - for (j = 0; j < argc_stack; j++) { + for (j = 0; j < argc_normal; j++) { arg++; if (arg != 1) fprintf(fout, ", "); @@ -7239,6 +7420,9 @@ static void output_hdr(FILE *fout) for (i = 0; i < hg_fp_cnt; i++) hg_fp_resolve_deps(&hg_fp[i]); + // adjust functions referenced from data segment + do_func_refs_from_data(); + // note: messes up .proto ptr, don't use //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id); @@ -7282,7 +7466,7 @@ static char *next_word_s(char *w, size_t wsize, char *s) s = sskip(s); i = 0; - if (*s == '\'') { + if (*s == '\'' && s[1] != '\r' && s[1] != '\n') { w[0] = s[0]; for (i = 1; i < wsize - 1; i++) { if (s[i] == 0) { @@ -7308,11 +7492,83 @@ static char *next_word_s(char *w, size_t wsize, char *s) return s + i; } -static void scan_variables(FILE *fasm) +static int cmpstringp(const void *p1, const void *p2) +{ + return strcmp(*(char * const *)p1, *(char * const *)p2); +} + +static int is_xref_needed(char *p, char **rlist, int rlist_len) +{ + char *p2; + + p = sskip(p); + if (strstr(p, "...")) + // unable to determine, assume needed + return 1; + + if (*p == '.') // .text, .data, ... + // ref from other data or non-function -> no + return 0; + + p2 = strpbrk(p, "+:\r\n\x18"); + if (p2 != NULL) + *p2 = 0; + if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp)) + // referenced from removed code + return 0; + + return 1; +} + +static int ida_xrefs_show_need(FILE *fasm, char *p, + char **rlist, int rlist_len) +{ + int found_need = 0; + char line[256]; + long pos; + + p = strrchr(p, ';'); + if (p != NULL && *p == ';' && IS_START(p + 2, "DATA XREF: ")) { + p += 13; + if (is_xref_needed(p, rlist, rlist_len)) + return 1; + } + + pos = ftell(fasm); + while (1) + { + if (!my_fgets(line, sizeof(line), fasm)) + break; + // non-first line is always indented + if (!my_isblank(line[0])) + break; + + // should be no content, just comment + p = sskip(line); + if (*p != ';') + break; + + p = strrchr(p, ';'); + p += 2; + // it's printed once, but no harm to check again + if (IS_START(p, "DATA XREF: ")) + p += 11; + + if (is_xref_needed(p, rlist, rlist_len)) { + found_need = 1; + break; + } + } + fseek(fasm, pos, SEEK_SET); + return found_need; +} + +static void scan_variables(FILE *fasm, char **rlist, int rlist_len) { struct scanned_var *var; char line[256] = { 0, }; - char words[3][256]; + char words[4][256]; + int no_identifier; char *p = NULL; int wordc; int l; @@ -7351,8 +7607,7 @@ static void scan_variables(FILE *fasm) asmln++; p = line; - if (my_isblank(*p)) - continue; + no_identifier = my_isblank(*p); p = sskip(p); if (*p == 0 || *p == ';') @@ -7372,11 +7627,21 @@ static void scan_variables(FILE *fasm) if (wordc < 2) continue; + if (no_identifier) { + if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset")) + hg_ref_add(words[2]); + continue; + } + if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) { // when this starts, we don't need anything from this section break; } + // check refs comment(s) + if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len)) + continue; + if ((hg_var_cnt & 0xff) == 0) { hg_vars = realloc(hg_vars, sizeof(hg_vars[0]) * (hg_var_cnt + 0x100)); @@ -7404,8 +7669,11 @@ static void scan_variables(FILE *fasm) continue; } - if (IS(words[1], "dd")) + if (IS(words[1], "dd")) { var->lmod = OPLM_DWORD; + if (wordc >= 4 && IS(words[2], "offset")) + hg_ref_add(words[3]); + } else if (IS(words[1], "dw")) var->lmod = OPLM_WORD; else if (IS(words[1], "db")) { @@ -7475,11 +7743,6 @@ static int cmp_chunks(const void *p1, const void *p2) return strcmp(c1->name, c2->name); } -static int cmpstringp(const void *p1, const void *p2) -{ - return strcmp(*(char * const *)p1, *(char * const *)p2); -} - static void scan_ahead(FILE *fasm) { char words[2][256]; @@ -7677,7 +7940,7 @@ int main(int argc, char *argv[]) } if (g_header_mode) - scan_variables(fasm); + scan_variables(fasm, rlist, rlist_len); while (my_fgets(line, sizeof(line), fasm)) { @@ -7731,6 +7994,46 @@ int main(int argc, char *argv[]) } } } + else if (p[2] == 's' && IS_START(p, "; sctattr:")) + { + static const char *attrs[] = { + "clear_sf", + "clear_regmask", + }; + + // parse manual attribute-list comment + g_sct_func_attr = 0; + p = sskip(p + 10); + + for (; *p != 0; p = sskip(p)) { + for (i = 0; i < ARRAY_SIZE(attrs); i++) { + if (!strncmp(p, attrs[i], strlen(attrs[i]))) { + g_sct_func_attr |= 1 << i; + p += strlen(attrs[i]); + break; + } + } + if (*p == '=') { + j = ret = 0; + if (i == 0) + // clear_sf=start,len (in dwords) + ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start, + &g_stack_clear_len, &j); + else if (i == 1) + // clear_regmask= + ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1; + if (ret < 2) { + anote("unparsed attr value: %s\n", p); + break; + } + p += j; + } + else if (i == ARRAY_SIZE(attrs)) { + anote("unparsed sct attr: %s\n", p); + break; + } + } + } else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR ")) { p += 30; @@ -7899,6 +8202,10 @@ do_pending_endp: pending_endp = 0; in_func = 0; g_ida_func_attr = 0; + g_sct_func_attr = 0; + g_stack_clear_start = 0; + g_stack_clear_len = 0; + g_regmask_init = 0; skip_warned = 0; g_skip_func = 0; g_func[0] = 0; @@ -8065,11 +8372,8 @@ do_pending_endp: parse_op(&ops[pi], words, wordc); - if (sctproto != NULL) { - if (ops[pi].op == OP_CALL || ops[pi].op == OP_JMP) - ops[pi].datap = sctproto; - sctproto = NULL; - } + ops[pi].datap = sctproto; + sctproto = NULL; pi++; }