target/i386: Create gen_jmp_rel

Create a common helper for pc-relative branches.  The jmp jb insn
was missing a mask for CODE32.  In all cases the CODE64 check was
incorrectly placed, allowing PREFIX_DATA to truncate %rip to 16 bits.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20221001140935.465607-18-richard.henderson@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Richard Henderson 2022-10-01 07:09:26 -07:00 committed by Paolo Bonzini
parent 202005f1f8
commit 8760ded661
1 changed files with 29 additions and 29 deletions

View File

@ -226,6 +226,7 @@ static void gen_eob(DisasContext *s);
static void gen_jr(DisasContext *s); static void gen_jr(DisasContext *s);
static void gen_jmp(DisasContext *s, target_ulong eip); static void gen_jmp(DisasContext *s, target_ulong eip);
static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num); static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num);
static void gen_jmp_rel(DisasContext *s, MemOp ot, int diff, int tb_num);
static void gen_op(DisasContext *s1, int op, MemOp ot, int d); static void gen_op(DisasContext *s1, int op, MemOp ot, int d);
static void gen_exception_gpf(DisasContext *s); static void gen_exception_gpf(DisasContext *s);
@ -2792,6 +2793,21 @@ static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num)
} }
} }
static void gen_jmp_rel(DisasContext *s, MemOp ot, int diff, int tb_num)
{
target_ulong dest = s->pc - s->cs_base + diff;
/* In 64-bit mode, operand size is fixed at 64 bits. */
if (!CODE64(s)) {
if (ot == MO_16) {
dest &= 0xffff;
} else {
dest &= 0xffffffff;
}
}
gen_jmp_tb(s, dest, tb_num);
}
static void gen_jmp(DisasContext *s, target_ulong eip) static void gen_jmp(DisasContext *s, target_ulong eip)
{ {
gen_jmp_tb(s, eip, 0); gen_jmp_tb(s, eip, 0);
@ -6862,20 +6878,12 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
break; break;
case 0xe8: /* call im */ case 0xe8: /* call im */
{ {
if (dflag != MO_16) { int diff = (dflag != MO_16
tval = (int32_t)insn_get(env, s, MO_32); ? (int32_t)insn_get(env, s, MO_32)
} else { : (int16_t)insn_get(env, s, MO_16));
tval = (int16_t)insn_get(env, s, MO_16);
}
tval += s->pc - s->cs_base;
if (dflag == MO_16) {
tval &= 0xffff;
} else if (!CODE64(s)) {
tval &= 0xffffffff;
}
gen_push_v(s, eip_next_tl(s)); gen_push_v(s, eip_next_tl(s));
gen_bnd_jmp(s); gen_bnd_jmp(s);
gen_jmp(s, tval); gen_jmp_rel(s, dflag, diff, 0);
} }
break; break;
case 0x9a: /* lcall im */ case 0x9a: /* lcall im */
@ -6893,19 +6901,13 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
} }
goto do_lcall; goto do_lcall;
case 0xe9: /* jmp im */ case 0xe9: /* jmp im */
if (dflag != MO_16) { {
tval = (int32_t)insn_get(env, s, MO_32); int diff = (dflag != MO_16
} else { ? (int32_t)insn_get(env, s, MO_32)
tval = (int16_t)insn_get(env, s, MO_16); : (int16_t)insn_get(env, s, MO_16));
gen_bnd_jmp(s);
gen_jmp_rel(s, dflag, diff, 0);
} }
tval += s->pc - s->cs_base;
if (dflag == MO_16) {
tval &= 0xffff;
} else if (!CODE64(s)) {
tval &= 0xffffffff;
}
gen_bnd_jmp(s);
gen_jmp(s, tval);
break; break;
case 0xea: /* ljmp im */ case 0xea: /* ljmp im */
{ {
@ -6922,12 +6924,10 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
} }
goto do_ljmp; goto do_ljmp;
case 0xeb: /* jmp Jb */ case 0xeb: /* jmp Jb */
tval = (int8_t)insn_get(env, s, MO_8); {
tval += s->pc - s->cs_base; int diff = (int8_t)insn_get(env, s, MO_8);
if (dflag == MO_16) { gen_jmp_rel(s, dflag, diff, 0);
tval &= 0xffff;
} }
gen_jmp(s, tval);
break; break;
case 0x70 ... 0x7f: /* jcc Jb */ case 0x70 ... 0x7f: /* jcc Jb */
tval = (int8_t)insn_get(env, s, MO_8); tval = (int8_t)insn_get(env, s, MO_8);