The opcodes 0xe8 (call) and 0xe9 (jump), when prefixed by 0x66, do not use a 16 bit offset, but still 32 bits, just like conditional relative jumps. To distinguish between conditional jumps and the unconditional call/jump add a new call_jump_mode and a call_jump_flag. This prerevents data size changes for both, call_jump_mode and cond_jump_mode when using the Intel syntax.
In the translator respect data size changes only, if the CPU is not and Intel type. Otherwise the size of the call/jmp is always 32 bits. See https://github.com/xoreaxeaxeax/sandsifter/blob/master/references/d omas_breaking_the_x86_isa_wp.pdf for the details and reasoning. Signed-off-by: Jürgen Buchmüller <pullm...@t-online.de> --- disas/i386.c | 31 ++++++++++++++------------- target/i386/translate.c | 56 ++++++++++++++++++++++++++++++++--------- -------- 2 files changed, 54 insertions(+), 33 deletions(-) diff --git a/disas/i386.c b/disas/i386.c index f1e376ca4a..2b18285fb8 100644 --- a/disas/i386.c +++ b/disas/i386.c @@ -464,6 +464,7 @@ fetch_data(struct disassemble_info *info, bfd_byte *addr) #define ALr { REP_Fixup, al_reg } #define eAXr { REP_Fixup, eAX_reg } +#define call_jump_flag { NULL, call_jump_mode } #define cond_jump_flag { NULL, cond_jump_mode } #define loop_jcxz_flag { NULL, loop_jcxz_mode } @@ -480,17 +481,18 @@ fetch_data(struct disassemble_info *info, bfd_byte *addr) #define t_mode 6 /* ten-byte operand */ #define x_mode 7 /* 16-byte XMM operand */ #define m_mode 8 /* d_mode in 32bit, q_mode in 64bit mode. */ -#define cond_jump_mode 9 -#define loop_jcxz_mode 10 -#define dq_mode 11 /* operand size depends on REX prefixes. */ -#define dqw_mode 12 /* registers like dq_mode, memory like w_mode. */ -#define f_mode 13 /* 4- or 6-byte pointer operand */ -#define const_1_mode 14 -#define stack_v_mode 15 /* v_mode for stack-related opcodes. */ -#define z_mode 16 /* non-quad operand size depends on prefixes */ -#define o_mode 17 /* 16-byte operand */ -#define dqb_mode 18 /* registers like dq_mode, memory like b_mode. */ -#define dqd_mode 19 /* registers like dq_mode, memory like d_mode. */ +#define call_jump_mode 9 +#define cond_jump_mode 10 +#define loop_jcxz_mode 11 +#define dq_mode 12 /* operand size depends on REX prefixes. */ +#define dqw_mode 13 /* registers like dq_mode, memory like w_mode. */ +#define f_mode 14 /* 4- or 6-byte pointer operand */ +#define const_1_mode 15 +#define stack_v_mode 16 /* v_mode for stack-related opcodes. */ +#define z_mode 17 /* non-quad operand size depends on prefixes */ +#define o_mode 18 /* 16-byte operand */ +#define dqb_mode 19 /* registers like dq_mode, memory like b_mode. */ +#define dqd_mode 20 /* registers like dq_mode, memory like d_mode. */ #define es_reg 100 #define cs_reg 101 @@ -1007,8 +1009,8 @@ static const struct dis386 dis386[] = { { "outB", { Ib, AL } }, { "outG", { Ib, zAX } }, /* e8 */ - { "callT", { Jv } }, - { "jmpT", { Jv } }, + { "callT", { Jv, XX, call_jump_flag } }, + { "jmpT", { Jv, XX, call_jump_flag } }, { "Jjmp{T|}", { Ap } }, { "jmp", { Jb } }, { "inB", { AL, indirDX } }, @@ -3968,7 +3970,8 @@ print_insn (bfd_vma pc, disassemble_info *info) if (!uses_DATA_prefix && (prefixes & PREFIX_DATA)) { sizeflag ^= DFLAG; - if (dp->op[2].bytemode == cond_jump_mode + if ((dp->op[2].bytemode == call_jump_mode + || dp->op[2].bytemode == cond_jump_mode) && dp->op[0].bytemode == v_mode && !intel_syntax) { diff --git a/target/i386/translate.c b/target/i386/translate.c index 5fdadf98cf..a97cc9496f 100644 --- a/target/i386/translate.c +++ b/target/i386/translate.c @@ -6480,17 +6480,26 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, break; case 0xe8: /* call im */ { - if (dflag != MO_16) { - tval = (int32_t)insn_get(env, s, MO_32); + if (env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1) { + if (dflag != MO_16) { + tval = (int32_t)insn_get(env, s, MO_32); + } else { + tval = (int16_t)insn_get(env, s, MO_16); + } + next_eip = s->pc - s->cs_base; + tval += next_eip; + if (dflag == MO_16) { + tval &= 0xffff; + } else if (!CODE64(s)) { + tval &= 0xffffffff; + } } else { - tval = (int16_t)insn_get(env, s, MO_16); - } - next_eip = s->pc - s->cs_base; - tval += next_eip; - if (dflag == MO_16) { - tval &= 0xffff; - } else if (!CODE64(s)) { - tval &= 0xffffffff; + tval = (int32_t)insn_get(env, s, MO_32); + next_eip = s->pc - s->cs_base; + tval += next_eip; + if (!CODE64(s)) { + tval &= 0xffffffff; + } } tcg_gen_movi_tl(cpu_T0, next_eip); gen_push_v(s, cpu_T0); @@ -6513,16 +6522,25 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, } goto do_lcall; case 0xe9: /* jmp im */ - if (dflag != MO_16) { - tval = (int32_t)insn_get(env, s, MO_32); + if (env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1) { + if (dflag != MO_16) { + tval = (int32_t)insn_get(env, s, MO_32); + } else { + tval = (int16_t)insn_get(env, s, MO_16); + } + next_eip = s->pc - s->cs_base; + tval += next_eip; + if (dflag == MO_16) { + tval &= 0xffff; + } else if (!CODE64(s)) { + tval &= 0xffffffff; + } } else { - 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; + tval = (int32_t)insn_get(env, s, MO_32); + tval += s->pc - s->cs_base; + if (!CODE64(s)) { + tval &= 0xffffffff; + } } gen_bnd_jmp(s); gen_jmp(s, tval); -- 2.14.1