OPF_FARG = (1 << 11), /* push collected as func arg (no reuse) */
OPF_EBP_S = (1 << 12), /* ebp used as scratch here, not BP */
OPF_DF = (1 << 13), /* DF flag set */
+ OPF_ATAIL = (1 << 14), /* tail call with reused arg frame */
+ OPF_32BIT = (1 << 15), /* 32bit division */
};
enum op_op {
OP_SAR,
OP_ROL,
OP_ROR,
+ OP_RCL,
+ OP_RCR,
OP_ADC,
OP_SBB,
OP_INC,
{
static const char *dword_types[] = {
"int", "_DWORD", "UINT_PTR", "DWORD",
- "WPARAM", "LPARAM", "UINT",
- "HIMC",
+ "WPARAM", "LPARAM", "UINT", "__int32",
+ "LONG", "HIMC",
};
static const char *word_types[] = {
"uint16_t", "int16_t", "_WORD",
static const char *byte_types[] = {
"uint8_t", "int8_t", "char",
"unsigned __int8", "__int8", "BYTE", "_BYTE",
- "_UNKNOWN",
+ "CHAR", "_UNKNOWN",
};
const char *n;
int i;
{ "sar", OP_SAR, 2, 2, OPF_DATA|OPF_FLAGS },
{ "rol", OP_ROL, 2, 2, OPF_DATA|OPF_FLAGS },
{ "ror", OP_ROR, 2, 2, OPF_DATA|OPF_FLAGS },
+ { "rcl", OP_RCL, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC },
+ { "rcr", OP_RCR, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC },
{ "adc", OP_ADC, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC },
{ "sbb", OP_SBB, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC },
{ "inc", OP_INC, 1, 1, OPF_DATA|OPF_FLAGS },
ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
i + 1, offset, g_func_pp->arg[i].type.name);
}
- if (popr->is_ptr && popr->lmod != OPLM_DWORD)
- ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
+ // can't check this because msvc likes to reuse
+ // arg space for scratch..
+ //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
+ // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
}
else
{
*is_inv = 1;
return PFO_LE;
+ case OP_RCL:
+ case OP_RCR:
case OP_ADC:
case OP_SBB:
return PFO_C;
}
// scan for positive, constant esp adjust
-static int scan_for_esp_adjust(int i, int opcnt, int *adj)
+static int scan_for_esp_adjust(int i, int opcnt, int *adj,
+ int *multipath)
{
const struct parsed_proto *pp;
struct parsed_op *po;
int first_pop = -1;
- *adj = 0;
+
+ *adj = *multipath = 0;
for (; i < opcnt; i++) {
po = &ops[i];
if (g_labels[i][0] != 0)
- break;
+ *multipath = 1;
if (po->op == OP_ADD && po->operand[0].reg == xSP) {
if (po->operand[1].type != OPT_CONST)
*adj += lmod_bytes(po, po->operand[0].lmod);
}
else if (po->flags & (OPF_JMP|OPF_TAIL)) {
+ if (po->op == OP_JMP && po->btj == NULL) {
+ i = po->bt_i - 1;
+ continue;
+ }
if (po->op != OP_CALL)
break;
if (po->operand[0].type != OPT_LABEL)
const char *tmpname;
enum parsed_flag_op pfo;
int save_arg_vars = 0;
- int cmp_result_vars = 0;
+ int cond_vars = 0;
int need_tmp_var = 0;
- int need_mul_var = 0;
+ int need_tmp64 = 0;
int had_decl = 0;
int label_pending = 0;
int regmask_save = 0;
fprintf(fout, "%s ", g_func_pp->ret_type.name);
output_pp_attrs(fout, g_func_pp, g_ida_func_attr & IDAFA_NORETURN);
- fprintf(fout, "%s(", funcn);
+ fprintf(fout, "%s(", g_func_pp->name);
for (i = 0; i < g_func_pp->argc; i++) {
if (i > 0)
for (; i < opcnt; i++)
if (ops[i].op == OP_RET)
break;
- if (i == opcnt && (ops[i - 1].flags & OPF_JMP) && found)
- 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..
+ break;
+ if (ops[j].op == OP_CALL)
+ // probably noreturn call..
+ break;
+ }
+ j--;
+ }
- if ((ops[i - 1].op == OP_POP && IS(opr_name(&ops[i - 1], 0), "ebp"))
- || ops[i - 1].op == OP_LEAVE)
+ if ((ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
+ || ops[j].op == OP_LEAVE)
{
- ops[i - 1].flags |= OPF_RMD;
+ ops[j].flags |= OPF_RMD;
}
else if (!(g_ida_func_attr & IDAFA_NORETURN))
- ferr(&ops[i - 1], "'pop ebp' expected\n");
+ ferr(&ops[j], "'pop ebp' expected\n");
if (g_stack_fsz != 0) {
- if (ops[i - 2].op == OP_MOV
- && IS(opr_name(&ops[i - 2], 0), "esp")
- && IS(opr_name(&ops[i - 2], 1), "ebp"))
+ if (ops[j - 1].op == OP_MOV
+ && IS(opr_name(&ops[j - 1], 0), "esp")
+ && IS(opr_name(&ops[j - 1], 1), "ebp"))
{
- ops[i - 2].flags |= OPF_RMD;
+ ops[j - 1].flags |= OPF_RMD;
}
- else if (ops[i - 1].op != OP_LEAVE
+ else if (ops[j].op != OP_LEAVE
&& !(g_ida_func_attr & IDAFA_NORETURN))
{
- ferr(&ops[i - 2], "esp restore expected\n");
+ ferr(&ops[j - 1], "esp restore expected\n");
}
- if (ecx_push && ops[i - 3].op == OP_POP
- && IS(opr_name(&ops[i - 3], 0), "ecx"))
+ if (ecx_push && ops[j - 2].op == OP_POP
+ && IS(opr_name(&ops[j - 2], 0), "ecx"))
{
- ferr(&ops[i - 3], "unexpected ecx pop\n");
+ ferr(&ops[j - 2], "unexpected ecx pop\n");
}
}
tailcall:
po->op = OP_CALL;
po->flags |= OPF_TAIL;
+ if (i > 0 && ops[i - 1].op == OP_POP)
+ po->flags |= OPF_ATAIL;
i--; // reprocess
}
pp = calloc(1, sizeof(*pp));
my_assert_not(pp, NULL);
pp->is_fptr = 1;
- ret = scan_for_esp_adjust(i + 1, opcnt, &j);
+ ret = scan_for_esp_adjust(i + 1, opcnt, &j, &l);
if (ret < 0) {
if (!g_allow_regfunc)
ferr(po, "non-__cdecl indirect call unhandled yet\n");
// look for and make use of esp adjust
ret = -1;
if (!pp->is_stdcall && pp->argc_stack > 0)
- ret = scan_for_esp_adjust(i + 1, opcnt, &j);
+ ret = scan_for_esp_adjust(i + 1, opcnt, &j, &l);
if (ret >= 0) {
if (pp->is_vararg) {
if (j / 4 < pp->argc_stack)
ret++;
}
}
- else {
+ else if (!l) {
// a bit of a hack, but deals with use of
// single adj for multiple calls
ops[ret].operand[1].val -= j;
ferr(po, "missing esp_adjust for vararg func '%s'\n",
pp->name);
- if (!pp->is_unresolved) {
+ if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
// since we know the args, collect them
collect_call_args(po, i, pp, ®mask, &save_arg_vars,
i + opcnt * 2);
}
if (strstr(pp->ret_type.name, "int64"))
- need_mul_var = 1;
+ need_tmp64 = 1;
}
}
if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
pfomask = 1 << pfo;
}
- else if (tmp_op->op == OP_SCAS) {
+ else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
pfomask = 1 << pfo;
}
- else if (tmp_op->op == OP_CMPS) {
- pfomask = 1 << PFO_Z;
- }
else {
// see if we'll be able to handle based on op result
if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
|| branched
|| scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
pfomask = 1 << pfo;
+
+ if (tmp_op->op == OP_ADD && pfo == PFO_C)
+ need_tmp64 = 1;
}
if (pfomask) {
tmp_op->pfomask |= pfomask;
- cmp_result_vars |= pfomask;
+ cond_vars |= pfomask;
}
// note: may overwrite, currently not a problem
po->datap = tmp_op;
}
- if (po->op == OP_ADC || po->op == OP_SBB)
- cmp_result_vars |= 1 << PFO_C;
+ if (po->op == OP_RCL || po->op == OP_RCR
+ || po->op == OP_ADC || po->op == OP_SBB)
+ cond_vars |= 1 << PFO_C;
}
else if (po->op == OP_CMPS || po->op == OP_SCAS) {
- cmp_result_vars |= 1 << PFO_Z;
+ cond_vars |= 1 << PFO_Z;
}
else if (po->op == OP_MUL
|| (po->op == OP_IMUL && po->operand_cnt == 1))
{
- need_mul_var = 1;
- }
- else if (po->op == OP_XCHG) {
- need_tmp_var = 1;
+ need_tmp64 = 1;
}
else if (po->op == OP_CALL) {
pp = po->datap;
}
else if (po->op == OP_RET && !IS(g_func_pp->ret_type.name, "void"))
regmask |= 1 << xAX;
+ else if (po->op == OP_DIV || po->op == OP_IDIV) {
+ // 32bit division is common, look for it
+ if (po->op == OP_DIV)
+ ret = scan_for_reg_clear(i, xDX);
+ else
+ ret = scan_for_cdq_edx(i);
+ if (ret >= 0)
+ po->flags |= OPF_32BIT;
+ else
+ need_tmp64 = 1;
+ }
+
+ if (po->op == OP_RCL || po->op == OP_RCR || po->op == OP_XCHG) {
+ need_tmp_var = 1;
+ }
}
// pass4:
}
}
- if (cmp_result_vars) {
+ if (cond_vars) {
for (i = 0; i < 8; i++) {
- if (cmp_result_vars & (1 << i)) {
+ if (cond_vars & (1 << i)) {
fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
had_decl = 1;
}
had_decl = 1;
}
- if (need_mul_var) {
- fprintf(fout, " u64 mul_tmp;\n");
+ if (need_tmp64) {
+ fprintf(fout, " u64 tmp64;\n");
had_decl = 1;
}
if (po->flags & OPF_JMP) {
fprintf(fout, " if %s\n", buf1);
}
- else if (po->op == OP_ADC || po->op == OP_SBB) {
+ else if (po->op == OP_RCL || po->op == OP_RCR
+ || po->op == OP_ADC || po->op == OP_SBB)
+ {
if (is_delayed)
fprintf(fout, " cond_%s = %s;\n",
parsed_flag_op_names[pfo], buf1);
pfomask = po->pfomask;
+ if (po->flags & (OPF_REPZ|OPF_REPNZ)) {
+ // we need initial flags for ecx=0 case..
+ if (i > 0 && ops[i - 1].op == OP_XOR
+ && IS(ops[i - 1].operand[0].name,
+ ops[i - 1].operand[1].name))
+ {
+ fprintf(fout, " cond_z = ");
+ if (pfomask & (1 << PFO_C))
+ fprintf(fout, "cond_c = ");
+ fprintf(fout, "0;\n");
+ }
+ else if (last_arith_dst != NULL) {
+ out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
+ out_test_for_cc(buf1, sizeof(buf1), po, PFO_Z, 0,
+ last_arith_dst->lmod, buf3);
+ fprintf(fout, " cond_z = %s;\n", buf1);
+ }
+ else
+ ferr(po, "missing initial ZF\n");
+ }
+
switch (po->op)
{
case OP_MOV:
l = (po->flags & OPF_DF) ? '-' : '+';
if (po->flags & OPF_REP) {
fprintf(fout,
- " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
+ " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d) {\n",
l, j, l, j);
+ if (pfomask & (1 << PFO_C)) {
+ // ugh..
+ fprintf(fout,
+ " cond_c = %sedi < %sesi;\n", buf1, buf1);
+ pfomask &= ~(1 << PFO_C);
+ }
fprintf(fout,
" if ((cond_z = (%sedi == %sesi)) %s 0)\n",
buf1, buf1, (po->flags & OPF_REPZ) ? "==" : "!=");
fprintf(fout,
- " break;");
+ " break;\n"
+ " }");
snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
(po->flags & OPF_REPZ) ? "e" : "ne");
}
break;
// arithmetic w/flags
- case OP_ADD:
- case OP_SUB:
case OP_AND:
case OP_OR:
propagate_lmod(po, &po->operand[0], &po->operand[1]);
j = l - j;
else
j -= 1;
- fprintf(fout, " cond_c = (%s & 0x%02x) ? 1 : 0;\n",
- buf1, 1 << j);
+ fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
+ buf1, j);
}
else
ferr(po, "zero shift?\n");
delayed_flag_op = NULL;
break;
+ case OP_RCL:
+ case OP_RCR:
+ assert_operand_cnt(2);
+ out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
+ l = lmod_bytes(po, po->operand[0].lmod) * 8;
+ if (po->operand[1].type == OPT_CONST) {
+ j = po->operand[1].val % l;
+ if (j == 0)
+ ferr(po, "zero rotate\n");
+ fprintf(fout, " tmp = (%s >> %d) & 1;\n",
+ buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
+ if (po->op == OP_RCL) {
+ fprintf(fout,
+ " %s = (%s << %d) | (cond_c << %d)",
+ buf1, buf1, j, j - 1);
+ if (j != 1)
+ fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
+ }
+ else {
+ fprintf(fout,
+ " %s = (%s >> %d) | (cond_c << %d)",
+ buf1, buf1, j, l - j);
+ if (j != 1)
+ fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
+ }
+ fprintf(fout, ";\n");
+ fprintf(fout, " cond_c = tmp;");
+ }
+ else
+ ferr(po, "TODO\n");
+ strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
+ output_std_flags(fout, po, &pfomask, buf1);
+ last_arith_dst = &po->operand[0];
+ delayed_flag_op = NULL;
+ break;
+
case OP_XOR:
assert_operand_cnt(2);
propagate_lmod(po, &po->operand[0], &po->operand[1]);
if (IS(opr_name(po, 0), opr_name(po, 1))) {
// special case for XOR
+ if (pfomask & (1 << PFO_BE)) { // weird, but it happens..
+ fprintf(fout, " cond_be = 1;\n");
+ pfomask &= ~(1 << PFO_BE);
+ }
fprintf(fout, " %s = 0;",
out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
last_arith_dst = &po->operand[0];
}
goto dualop_arith;
+ case OP_ADD:
+ assert_operand_cnt(2);
+ propagate_lmod(po, &po->operand[0], &po->operand[1]);
+ if (pfomask & (1 << PFO_C)) {
+ fprintf(fout, " tmp64 = (u64)%s + %s;\n",
+ out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]),
+ out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
+ fprintf(fout, " cond_c = tmp64 >> 32;\n");
+ fprintf(fout, " %s = (u32)tmp64;",
+ out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
+ strcat(g_comment, "add64");
+ pfomask &= ~(1 << PFO_C);
+ output_std_flags(fout, po, &pfomask, buf1);
+ last_arith_dst = &po->operand[0];
+ delayed_flag_op = NULL;
+ break;
+ }
+ goto dualop_arith;
+
+ case OP_SUB:
+ assert_operand_cnt(2);
+ propagate_lmod(po, &po->operand[0], &po->operand[1]);
+ if (pfomask & (1 << PFO_C)) {
+ fprintf(fout, " cond_c = %s < %s;\n",
+ out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]),
+ out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
+ pfomask &= ~(1 << PFO_C);
+ }
+ goto dualop_arith;
+
case OP_ADC:
case OP_SBB:
assert_operand_cnt(2);
case OP_MUL:
assert_operand_cnt(1);
strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
- fprintf(fout, " mul_tmp = %seax * %s%s;\n", buf1, buf1,
+ fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
- fprintf(fout, " edx = mul_tmp >> 32;\n");
- fprintf(fout, " eax = mul_tmp;");
+ fprintf(fout, " edx = tmp64 >> 32;\n");
+ fprintf(fout, " eax = tmp64;");
last_arith_dst = NULL;
delayed_flag_op = NULL;
break;
if (po->operand[0].lmod != OPLM_DWORD)
ferr(po, "unhandled lmod %d\n", po->operand[0].lmod);
- // 32bit division is common, look for it
- if (po->op == OP_DIV)
- ret = scan_for_reg_clear(i, xDX);
- else
- ret = scan_for_cdq_edx(i);
- if (ret >= 0) {
- out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
- strcpy(buf2, lmod_cast(po, po->operand[0].lmod,
- po->op == OP_IDIV));
- fprintf(fout, " edx = %seax %% %s%s;\n", buf2, buf2, buf1);
- fprintf(fout, " eax = %seax / %s%s;", buf2, buf2, buf1);
+ out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
+ strcpy(buf2, lmod_cast(po, po->operand[0].lmod,
+ po->op == OP_IDIV));
+ switch (po->operand[0].lmod) {
+ case OPLM_DWORD:
+ if (po->flags & OPF_32BIT)
+ snprintf(buf3, sizeof(buf3), "%seax", buf2);
+ else {
+ fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
+ snprintf(buf3, sizeof(buf3), "%stmp64",
+ (po->op == OP_IDIV) ? "(s64)" : "");
+ }
+ if (po->operand[0].type == OPT_REG
+ && po->operand[0].reg == xDX)
+ {
+ fprintf(fout, " eax = %s / %s%s;", buf3, buf2, buf1);
+ fprintf(fout, " edx = %s %% %s%s;\n", buf3, buf2, buf1);
+ }
+ else {
+ fprintf(fout, " edx = %s %% %s%s;\n", buf3, buf2, buf1);
+ fprintf(fout, " eax = %s / %s%s;", buf3, buf2, buf1);
+ }
+ break;
+ default:
+ ferr(po, "unhandled division type\n");
}
- else
- ferr(po, "TODO 64bit divident\n");
last_arith_dst = NULL;
delayed_flag_op = NULL;
break;
if (strstr(pp->ret_type.name, "int64")) {
if (po->flags & OPF_TAIL)
ferr(po, "int64 and tail?\n");
- fprintf(fout, "mul_tmp = ");
+ fprintf(fout, "tmp64 = ");
}
else if (!IS(pp->ret_type.name, "void")) {
if (po->flags & OPF_TAIL) {
fprintf(fout, "%s%s(", pp->name,
pp->has_structarg ? "_sa" : "");
- for (arg = 0; arg < pp->argc; arg++) {
- if (arg > 0)
- fprintf(fout, ", ");
+ if (po->flags & OPF_ATAIL) {
+ if (pp->argc_stack != g_func_pp->argc_stack
+ || (pp->argc_stack > 0
+ && pp->is_stdcall != g_func_pp->is_stdcall))
+ ferr(po, "incompatible tailcall\n");
- cast[0] = 0;
- if (pp->arg[arg].type.is_ptr)
- snprintf(cast, sizeof(cast), "(%s)", pp->arg[arg].type.name);
+ for (arg = j = 0; arg < pp->argc; arg++) {
+ if (arg > 0)
+ fprintf(fout, ", ");
- if (pp->arg[arg].reg != NULL) {
- fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
- continue;
- }
+ cast[0] = 0;
+ if (pp->arg[arg].type.is_ptr)
+ snprintf(cast, sizeof(cast), "(%s)",
+ pp->arg[arg].type.name);
- // stack arg
- tmp_op = pp->arg[arg].datap;
- if (tmp_op == NULL)
- ferr(po, "parsed_op missing for arg%d\n", arg);
- if (tmp_op->argnum != 0) {
- fprintf(fout, "%ss_a%d", cast, tmp_op->argnum);
+ if (pp->arg[arg].reg != NULL) {
+ fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
+ continue;
+ }
+ // stack arg
+ for (; j < g_func_pp->argc; j++)
+ if (g_func_pp->arg[j].reg == NULL)
+ break;
+ fprintf(fout, "%sa%d", cast, j + 1);
+ j++;
}
- else {
- fprintf(fout, "%s",
- out_src_opr(buf1, sizeof(buf1),
- tmp_op, &tmp_op->operand[0], cast, 0));
+ }
+ else {
+ for (arg = 0; arg < pp->argc; arg++) {
+ if (arg > 0)
+ fprintf(fout, ", ");
+
+ cast[0] = 0;
+ if (pp->arg[arg].type.is_ptr)
+ snprintf(cast, sizeof(cast), "(%s)",
+ pp->arg[arg].type.name);
+
+ if (pp->arg[arg].reg != NULL) {
+ fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
+ continue;
+ }
+
+ // stack arg
+ tmp_op = pp->arg[arg].datap;
+ if (tmp_op == NULL)
+ ferr(po, "parsed_op missing for arg%d\n", arg);
+ if (tmp_op->argnum != 0) {
+ fprintf(fout, "%ss_a%d", cast, tmp_op->argnum);
+ }
+ else {
+ fprintf(fout, "%s",
+ out_src_opr(buf1, sizeof(buf1),
+ tmp_op, &tmp_op->operand[0], cast, 0));
+ }
}
}
fprintf(fout, ");");
if (strstr(pp->ret_type.name, "int64")) {
fprintf(fout, "\n");
- fprintf(fout, " edx = mul_tmp >> 32;\n");
- fprintf(fout, " eax = mul_tmp;");
+ fprintf(fout, " edx = tmp64 >> 32;\n");
+ fprintf(fout, " eax = tmp64;");
}
if (pp->is_unresolved) {
}
if (pp->is_noreturn)
strcat(g_comment, " noreturn");
+ if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
+ strcat(g_comment, " argframe");
delayed_flag_op = NULL;
last_arith_dst = NULL;
break;
fprintf(fout, " return (%s)eax;",
g_func_pp->ret_type.name);
}
+ else if (IS(g_func_pp->ret_type.name, "__int64"))
+ fprintf(fout, " return ((u64)edx << 32) | eax;");
else
fprintf(fout, " return eax;");