IDAFA_FPD = (1 << 5),
};
+enum sct_func_attr {
+ SCTFA_CLEAR_SF = (1 << 0), // clear stack frame
+};
+
enum x87_const {
X87_CONST_1 = 1,
X87_CONST_2T,
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_skip_func;
static int g_allow_regfunc;
static int g_quiet_pp;
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");
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 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, };
break;
}
+ // check refs comment(s)
+ if (!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));
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];
}
if (g_header_mode)
- scan_variables(fasm);
+ scan_variables(fasm, rlist, rlist_len);
while (my_fgets(line, sizeof(line), fasm))
{
}
}
}
+ else if (p[2] == 's' && IS_START(p, "; sctattr:"))
+ {
+ static const char *attrs[] = {
+ "clear_sf",
+ };
+
+ // 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 (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 (ret < 2) {
+ anote("unparsed clear_sf 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;
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;
skip_warned = 0;
g_skip_func = 0;
g_func[0] = 0;