[Qemu-devel] [PATCH] i386: fix 0x66 prefix in disassembler and translator

Jürgen Buchmüller posted 1 patch 6 years, 7 months ago
Failed in applying to current master (apply log)
2 files changed, 54 insertions(+), 33 deletions(-)
[Qemu-devel] [PATCH] i386: fix 0x66 prefix in disassembler and translator
Posted by Jürgen Buchmüller 6 years, 7 months ago
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 <pullmoll@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