notaz.gp2x.de
/
ia32rtools.git
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
translate: handle various cases from smacker
[ia32rtools.git]
/
tools
/
translate.c
diff --git
a/tools/translate.c
b/tools/translate.c
index
7493761
..
aff7b61
100644
(file)
--- a/
tools/translate.c
+++ b/
tools/translate.c
@@
-45,6
+45,7
@@
enum op_flags {
OPF_DF = (1 << 13), /* DF flag set */
OPF_ATAIL = (1 << 14), /* tail call with reused arg frame */
OPF_32BIT = (1 << 15), /* 32bit division */
OPF_DF = (1 << 13), /* DF flag set */
OPF_ATAIL = (1 << 14), /* tail call with reused arg frame */
OPF_32BIT = (1 << 15), /* 32bit division */
+ OPF_LOCK = (1 << 16), /* op has lock prefix */
};
enum op_op {
};
enum op_op {
@@
-204,7
+205,7
@@
enum ida_func_attr {
static struct parsed_op ops[MAX_OPS];
static struct parsed_equ *g_eqs;
static int g_eqcnt;
static struct parsed_op ops[MAX_OPS];
static struct parsed_equ *g_eqs;
static int g_eqcnt;
-static char g_labels[MAX_OPS][
32
];
+static char g_labels[MAX_OPS][
48
];
static struct label_ref g_label_refs[MAX_OPS];
static const struct parsed_proto *g_func_pp;
static struct parsed_data *g_func_pd;
static struct label_ref g_label_refs[MAX_OPS];
static const struct parsed_proto *g_func_pp;
static struct parsed_data *g_func_pd;
@@
-406,12
+407,21
@@
static const char *parse_stack_el(const char *name, char *extra_reg)
if (!IS_START(name, "esp+"))
return NULL;
if (!IS_START(name, "esp+"))
return NULL;
- p = strchr(name + 4, '+');
+ s = name + 4;
+ p = strchr(s, '+');
if (p) {
if (p) {
- // must be a number after esp+, already converted to 0x..
- s = name + 4;
+ if (is_reg_in_str(s)) {
+ if (extra_reg != NULL) {
+ strncpy(extra_reg, s, p - s);
+ extra_reg[p - s] = 0;
+ }
+ s = p + 1;
+ p = strchr(s, '+');
+ if (p == NULL)
+ aerr("%s IDA stackvar not set?\n", __func__);
+ }
if (!('0' <= *s && *s <= '9')) {
if (!('0' <= *s && *s <= '9')) {
- aerr("%s
nan
?\n", __func__);
+ aerr("%s
IDA stackvar offset not set
?\n", __func__);
return NULL;
}
if (s[0] == '0' && s[1] == 'x')
return NULL;
}
if (s[0] == '0' && s[1] == 'x')
@@
-712,6
+722,7
@@
static const struct {
{ "repz", OPF_REP|OPF_REPZ },
{ "repne", OPF_REP|OPF_REPNZ },
{ "repnz", OPF_REP|OPF_REPNZ },
{ "repz", OPF_REP|OPF_REPZ },
{ "repne", OPF_REP|OPF_REPNZ },
{ "repnz", OPF_REP|OPF_REPNZ },
+ { "lock", OPF_LOCK }, // ignored for now..
};
#define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
};
#define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
@@
-1257,7
+1268,7
@@
static int is_stack_access(struct parsed_op *po,
static void parse_stack_access(struct parsed_op *po,
const char *name, char *ofs_reg, int *offset_out,
static void parse_stack_access(struct parsed_op *po,
const char *name, char *ofs_reg, int *offset_out,
- int *stack_ra_out, const char **bp_arg_out)
+ int *stack_ra_out, const char **bp_arg_out
, int is_lea
)
{
const char *bp_arg = "";
const char *p = NULL;
{
const char *bp_arg = "";
const char *p = NULL;
@@
-1292,8
+1303,12
@@
static void parse_stack_access(struct parsed_op *po,
if (!strncmp(name, "ebp", 3))
stack_ra = 4;
if (!strncmp(name, "ebp", 3))
stack_ra = 4;
- if (ofs_reg[0] == 0 && stack_ra <= offset && offset < stack_ra + 4)
+ // yes it sometimes LEAs ra for compares..
+ if (!is_lea && ofs_reg[0] == 0
+ && stack_ra <= offset && offset < stack_ra + 4)
+ {
ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
+ }
*offset_out = offset;
*stack_ra_out = stack_ra;
*offset_out = offset;
*stack_ra_out = stack_ra;
@@
-1319,7
+1334,8
@@
static void stack_frame_access(struct parsed_op *po,
if (po->flags & OPF_EBP_S)
ferr(po, "stack_frame_access while ebp is scratch\n");
if (po->flags & OPF_EBP_S)
ferr(po, "stack_frame_access while ebp is scratch\n");
- parse_stack_access(po, name, ofs_reg, &offset, &stack_ra, &bp_arg);
+ parse_stack_access(po, name, ofs_reg, &offset,
+ &stack_ra, &bp_arg, is_lea);
if (offset > stack_ra)
{
if (offset > stack_ra)
{
@@
-1504,7
+1520,8
@@
static void check_func_pp(struct parsed_op *po,
}
}
}
}
-static void check_label_read_ref(struct parsed_op *po, const char *name)
+static const char *check_label_read_ref(struct parsed_op *po,
+ const char *name)
{
const struct parsed_proto *pp;
{
const struct parsed_proto *pp;
@@
-1514,6
+1531,8
@@
static void check_label_read_ref(struct parsed_op *po, const char *name)
if (pp->is_func)
check_func_pp(po, pp, "ref");
if (pp->is_func)
check_func_pp(po, pp, "ref");
+
+ return pp->name;
}
static char *out_src_opr(char *buf, size_t buf_size,
}
static char *out_src_opr(char *buf, size_t buf_size,
@@
-1522,6
+1541,7
@@
static char *out_src_opr(char *buf, size_t buf_size,
{
char tmp1[256], tmp2[256];
char expr[256];
{
char tmp1[256], tmp2[256];
char expr[256];
+ const char *name;
char *p;
int ret;
char *p;
int ret;
@@
-1589,29
+1609,28
@@
static char *out_src_opr(char *buf, size_t buf_size,
break;
case OPT_LABEL:
break;
case OPT_LABEL:
- check_label_read_ref(po, popr->name);
+
name =
check_label_read_ref(po, popr->name);
if (cast[0] == 0 && popr->is_ptr)
cast = "(u32)";
if (is_lea)
if (cast[0] == 0 && popr->is_ptr)
cast = "(u32)";
if (is_lea)
- snprintf(buf, buf_size, "(u32)&%s",
popr->
name);
+ snprintf(buf, buf_size, "(u32)&%s", name);
else if (popr->size_lt)
snprintf(buf, buf_size, "%s%s%s%s", cast,
lmod_cast_u_ptr(po, popr->lmod),
else if (popr->size_lt)
snprintf(buf, buf_size, "%s%s%s%s", cast,
lmod_cast_u_ptr(po, popr->lmod),
- popr->is_array ? "" : "&",
- popr->name);
+ popr->is_array ? "" : "&", name);
else
else
- snprintf(buf, buf_size, "%s%s%s", cast,
popr->
name,
+ snprintf(buf, buf_size, "%s%s%s", cast, name,
popr->is_array ? "[0]" : "");
break;
case OPT_OFFSET:
popr->is_array ? "[0]" : "");
break;
case OPT_OFFSET:
- check_label_read_ref(po, popr->name);
+
name =
check_label_read_ref(po, popr->name);
if (cast[0] == 0)
cast = "(u32)";
if (is_lea)
ferr(po, "lea an offset?\n");
if (cast[0] == 0)
cast = "(u32)";
if (is_lea)
ferr(po, "lea an offset?\n");
- snprintf(buf, buf_size, "%s&%s", cast,
popr->
name);
+ snprintf(buf, buf_size, "%s&%s", cast, name);
break;
case OPT_CONST:
break;
case OPT_CONST:
@@
-1956,7
+1975,8
@@
static void op_set_clear_flag(struct parsed_op *po,
// last op in stream - unconditional branch or ret
#define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
// last op in stream - unconditional branch or ret
#define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
- || (ops[_i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
+ || ((ops[_i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP \
+ && ops[_i].op != OP_CALL))
static int scan_for_pop(int i, int opcnt, const char *reg,
int magic, int depth, int *maxdepth, int do_flags)
static int scan_for_pop(int i, int opcnt, const char *reg,
int magic, int depth, int *maxdepth, int do_flags)
@@
-2422,7
+2442,7
@@
static const struct parsed_proto *try_recover_pp(
int offset = 0;
parse_stack_access(po, opr->name, ofs_reg,
int offset = 0;
parse_stack_access(po, opr->name, ofs_reg,
- &offset, &stack_ra, NULL);
+ &offset, &stack_ra, NULL
, 0
);
if (ofs_reg[0] != 0)
ferr(po, "offset reg on arg access?\n");
if (offset <= stack_ra) {
if (ofs_reg[0] != 0)
ferr(po, "offset reg on arg access?\n");
if (offset <= stack_ra) {
@@
-2472,11
+2492,9
@@
static void scan_for_call_type(int i, const struct parsed_opr *opr,
struct parsed_op *po;
struct label_ref *lr;
struct parsed_op *po;
struct label_ref *lr;
- while (i >= 0) {
- if (ops[i].cc_scratch == magic)
- return;
- ops[i].cc_scratch = magic;
+ ops[i].cc_scratch = magic;
+ while (1) {
if (g_labels[i][0] != 0) {
lr = &g_label_refs[i];
for (; lr != NULL; lr = lr->next)
if (g_labels[i][0] != 0) {
lr = &g_label_refs[i];
for (; lr != NULL; lr = lr->next)
@@
-2484,7
+2502,14
@@
static void scan_for_call_type(int i, const struct parsed_opr *opr,
if (i > 0 && LAST_OP(i - 1))
return;
}
if (i > 0 && LAST_OP(i - 1))
return;
}
+
i--;
i--;
+ if (i < 0)
+ break;
+
+ if (ops[i].cc_scratch == magic)
+ return;
+ ops[i].cc_scratch = magic;
if (!(ops[i].flags & OPF_DATA))
continue;
if (!(ops[i].flags & OPF_DATA))
continue;
@@
-2740,6
+2765,22
@@
static int collect_call_args(struct parsed_op *po, int i,
return ret;
}
return ret;
}
+// early check for tail call or branch back
+static int is_like_tailjmp(int j)
+{
+ if (!(ops[j].flags & OPF_JMP))
+ return 0;
+
+ if (ops[j].op == OP_JMP && !ops[j].operand[0].had_ds)
+ // probably local branch back..
+ return 1;
+ if (ops[j].op == OP_CALL)
+ // probably noreturn call..
+ return 1;
+
+ return 0;
+}
+
static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
{
int i;
static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
{
int i;
@@
-2857,6
+2898,11
@@
static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
ferr(ops, "nested fptr\n");
fprintf(fout, "%s", pp->arg[j].type.name);
}
ferr(ops, "nested fptr\n");
fprintf(fout, "%s", pp->arg[j].type.name);
}
+ if (pp->is_vararg) {
+ if (j > 0)
+ fprintf(fout, ", ");
+ fprintf(fout, "...");
+ }
fprintf(fout, ")");
}
else {
fprintf(fout, ")");
}
else {
@@
-2927,14
+2973,8
@@
static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
break;
j = i - 1;
if (i == opcnt && (ops[j].flags & OPF_JMP)) {
break;
j = i - 1;
if (i == opcnt && (ops[j].flags & OPF_JMP)) {
- if (found) {
- if (ops[j].op == OP_JMP && !ops[j].operand[0].had_ds)
- // probably local branch back..
+ if (found && is_like_tailjmp(j))
break;
break;
- if (ops[j].op == OP_CALL)
- // probably noreturn call..
- break;
- }
j--;
}
j--;
}
@@
-2982,6
+3022,7
@@
static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
}
}
}
}
+ found = 0;
if (g_sp_frame)
{
g_stack_fsz = ops[i].operand[1].val;
if (g_sp_frame)
{
g_stack_fsz = ops[i].operand[1].val;
@@
-2992,13
+3033,21
@@
static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
for (; i < opcnt; i++)
if (ops[i].op == OP_RET)
break;
for (; i < opcnt; i++)
if (ops[i].op == OP_RET)
break;
- if (ops[i - 1].op != OP_ADD
- || !IS(opr_name(&ops[i - 1], 0), "esp")
- || ops[i - 1].operand[1].type != OPT_CONST
- || ops[i - 1].operand[1].val != g_stack_fsz)
-
ferr(&ops[i - 1], "'add esp' expected\n")
;
- ops[i - 1].flags |= OPF_RMD;
+ j = i - 1;
+ if (i == opcnt && (ops[j].flags & OPF_JMP)) {
+ if (found && is_like_tailjmp(j))
+ break;
+
j--
;
+ }
+ if (ops[j].op != OP_ADD
+ || !IS(opr_name(&ops[j], 0), "esp")
+ || ops[j].operand[1].type != OPT_CONST
+ || ops[j].operand[1].val != g_stack_fsz)
+ ferr(&ops[j], "'add esp' expected\n");
+ ops[j].flags |= OPF_RMD;
+
+ found = 1;
i++;
} while (i < opcnt);
}
i++;
} while (i < opcnt);
}
@@
-3140,6
+3189,9
@@
tailcall:
if (l)
// not resolved just to single func
pp->is_fptr = 1;
if (l)
// not resolved just to single func
pp->is_fptr = 1;
+ if (po->operand[0].type == OPT_REG)
+ // we resolved this call and no longer need the register
+ po->regmask_src &= ~(1 << po->operand[0].reg);
}
if (pp == NULL) {
pp = calloc(1, sizeof(*pp));
}
if (pp == NULL) {
pp = calloc(1, sizeof(*pp));
@@
-3300,7
+3352,7
@@
tailcall:
if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
if (po->regmask_dst & (1 << xBP))
// compiler decided to drop bp frame and use ebp as scratch
if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
if (po->regmask_dst & (1 << xBP))
// compiler decided to drop bp frame and use ebp as scratch
- scan_fwd_set_flags(i, opcnt, i + opcnt * 5, OPF_EBP_S);
+ scan_fwd_set_flags(i
+ 1
, opcnt, i + opcnt * 5, OPF_EBP_S);
else
regmask_now &= ~(1 << xBP);
}
else
regmask_now &= ~(1 << xBP);
}
@@
-3428,7
+3480,8
@@
tailcall:
}
}
}
}
- if (pp->is_fptr) {
+ // declare indirect funcs
+ if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
if (pp->name[0] != 0) {
memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
memcpy(pp->name, "i_", 2);
if (pp->name[0] != 0) {
memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
memcpy(pp->name, "i_", 2);
@@
-3473,6
+3526,8
@@
tailcall:
else
need_tmp64 = 1;
}
else
need_tmp64 = 1;
}
+ else if (po->op == OP_CLD)
+ po->flags |= OPF_RMD;
if (po->op == OP_RCL || po->op == OP_RCR || po->op == OP_XCHG) {
need_tmp_var = 1;
if (po->op == OP_RCL || po->op == OP_RCR || po->op == OP_XCHG) {
need_tmp_var = 1;
@@
-4208,7
+4263,7
@@
tailcall:
pp = po->datap;
my_assert_not(pp, NULL);
pp = po->datap;
my_assert_not(pp, NULL);
- if (pp->is_fptr)
+ if (pp->is_fptr
&& !pp->is_arg
)
fprintf(fout, " %s = %s;\n", pp->name,
out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
"(void *)", 0));
fprintf(fout, " %s = %s;\n", pp->name,
out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
"(void *)", 0));