aboutsummaryrefslogtreecommitdiff
path: root/target-i386/translate.c
diff options
context:
space:
mode:
authorRichard Henderson <rth@twiddle.net>2015-12-17 11:19:24 -0800
committerPaolo Bonzini <pbonzini@redhat.com>2016-02-09 15:46:54 +0100
commit2045f04c3ae030bda650f84035f114bbd84909a9 (patch)
treea869479a6ac714dd521a270129494a7202d1c4bd /target-i386/translate.c
parent743e398e2fbf2f7183bf7a53c9d011fabcaa1770 (diff)
target-i386: Rewrite leave
Unify the code across stack pointer widths. Fix the note about not updating ESP before the potential exception. Signed-off-by: Richard Henderson <rth@twiddle.net> Message-Id: <1450379966-28198-9-git-send-email-rth@twiddle.net> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'target-i386/translate.c')
-rw-r--r--target-i386/translate.c29
1 files changed, 15 insertions, 14 deletions
diff --git a/target-i386/translate.c b/target-i386/translate.c
index 5aeac0567c..7a71425988 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -2359,6 +2359,20 @@ static void gen_enter(DisasContext *s, int esp_addend, int level)
gen_op_mov_reg_v(a_ot, R_ESP, cpu_T[1]);
}
+static void gen_leave(DisasContext *s)
+{
+ TCGMemOp d_ot = mo_pushpop(s, s->dflag);
+ TCGMemOp a_ot = mo_stacksize(s);
+
+ gen_lea_v_seg(s, a_ot, cpu_regs[R_EBP], R_SS, -1);
+ gen_op_ld_v(s, d_ot, cpu_T[0], cpu_A0);
+
+ tcg_gen_addi_tl(cpu_T[1], cpu_regs[R_EBP], 1 << d_ot);
+
+ gen_op_mov_reg_v(d_ot, R_EBP, cpu_T[0]);
+ gen_op_mov_reg_v(a_ot, R_ESP, cpu_T[1]);
+}
+
static void gen_exception(DisasContext *s, int trapno, target_ulong cur_eip)
{
gen_update_cc_op(s);
@@ -5114,20 +5128,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
}
break;
case 0xc9: /* leave */
- /* XXX: exception not precise (ESP is updated before potential exception) */
- if (CODE64(s)) {
- gen_op_mov_v_reg(MO_64, cpu_T[0], R_EBP);
- gen_op_mov_reg_v(MO_64, R_ESP, cpu_T[0]);
- } else if (s->ss32) {
- gen_op_mov_v_reg(MO_32, cpu_T[0], R_EBP);
- gen_op_mov_reg_v(MO_32, R_ESP, cpu_T[0]);
- } else {
- gen_op_mov_v_reg(MO_16, cpu_T[0], R_EBP);
- gen_op_mov_reg_v(MO_16, R_ESP, cpu_T[0]);
- }
- ot = gen_pop_T0(s);
- gen_op_mov_reg_v(ot, R_EBP, cpu_T[0]);
- gen_pop_update(s, ot);
+ gen_leave(s);
break;
case 0x06: /* push es */
case 0x0e: /* push cs */