};
enum sct_func_attr {
- SCTFA_CLEAR_SF = (1 << 0), // clear stack frame
+ SCTFA_CLEAR_SF = (1 << 0), // clear stack frame
+ SCTFA_CLEAR_REGS = (1 << 1), // clear registers (mask)
};
enum x87_const {
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;
};
#define mxAX (1 << xAX)
+#define mxCX (1 << xCX)
#define mxDX (1 << xDX)
#define mxST0 (1 << xST0)
#define mxST1 (1 << xST1)
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);
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)
// - 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:
} *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;
}
#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
}
}
+// 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)
{
char *p, namebuf[NAMELEN];
const char *name;
int regmask_dep;
- int argc_stack;
+ int argc_normal;
int j, arg;
for (; count > 0; count--, 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) {
}
}
- for (j = 0; j < argc_stack; j++) {
+ for (j = 0; j < argc_normal; j++) {
arg++;
if (arg != 1)
fprintf(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);
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) {
return 1;
}
-static int xrefs_show_need(FILE *fasm, char *p,
+static int ida_xrefs_show_need(FILE *fasm, char *p,
char **rlist, int rlist_len)
{
int found_need = 0;
{
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;
asmln++;
p = line;
- if (my_isblank(*p))
- continue;
+ no_identifier = my_isblank(*p);
p = sskip(p);
if (*p == 0 || *p == ';')
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 (!xrefs_show_need(fasm, p, rlist, rlist_len))
+ if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
continue;
if ((hg_var_cnt & 0xff) == 0) {
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")) {
{
static const char *attrs[] = {
"clear_sf",
+ "clear_regmask",
};
// parse manual attribute-list comment
break;
}
}
- if (i == 0 && *p == '=') {
- // clear_sf=start,len (in dwords)
- ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
- &g_stack_clear_len, &j);
+ 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=<mask>
+ ret = sscanf(p, "=%d%n", &g_regmask_init, &j) + 1;
if (ret < 2) {
- anote("unparsed clear_sf attr value: %s\n", p);
+ anote("unparsed attr value: %s\n", p);
break;
}
p += j;
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;