aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPekka Enberg <penberg@kernel.org>2013-06-13 14:26:23 +0300
committerPekka Enberg <penberg@kernel.org>2013-06-18 14:48:35 +0300
commit5f9ee0e790706699a0f49ece2359cf1e0c2214c3 (patch)
treec6c1a5612ec0af4141a57c4c90a2fae5ee07322b
parentd494ba1ecd6286f7fa2102b0e99a308de839a84f (diff)
downloadjato-5f9ee0e790706699a0f49ece2359cf1e0c2214c3.tar.gz
x86-64: Fix INSN_JMP_MEMINDEX encoding
Table 2-5 ("Special Cases of REX Encodings") of Intel manual states that: EBP without a displacement must be done using mod = 01 with displacement of 0. The problem is visible on x86-64 where INSN_JMP_MEMINDEX is encoded wrong. This fixes issue #34. Signed-off-by: Pekka Enberg <penberg@kernel.org>
-rw-r--r--arch/x86/encode.c19
-rw-r--r--test/unit/arch-x86/encode-test.c24
2 files changed, 40 insertions, 3 deletions
diff --git a/arch/x86/encode.c b/arch/x86/encode.c
index f345beb4..1a3fa401 100644
--- a/arch/x86/encode.c
+++ b/arch/x86/encode.c
@@ -505,7 +505,14 @@ static uint8_t insn_encode_mod_rm(struct insn *self, uint64_t flags, uint8_t opc
need_sib = insn_need_sib(self, flags);
if (flags & INDEX) {
- mod = 0x00;
+#ifdef CONFIG_X86_64
+ if (insn_uses_reg(self, MACH_REG_R13) || insn_uses_reg(self, MACH_REG_RBP))
+ mod = 0x01;
+ else
+ mod = 0x00;
+#else
+ mod = 0x00;
+#endif
} else {
if (flags & DIR_REVERSED)
mod = mod_dest_encode(flags);
@@ -650,7 +657,10 @@ static void insn_disp(struct insn *self, struct x86_insn *insn)
if (insn->flags & DST_REG)
return;
- insn->disp = self->dest.disp;
+ if (insn->flags & INDEX)
+ insn->disp = 0;
+ else
+ insn->disp = self->dest.disp;
if (insn->disp == 0 && !insn_need_disp(self))
insn->flags |= DST_MEM;
@@ -662,7 +672,10 @@ static void insn_disp(struct insn *self, struct x86_insn *insn)
if (insn->flags & SRC_REG)
return;
- insn->disp = self->src.disp;
+ if (insn->flags & INDEX)
+ insn->disp = 0;
+ else
+ insn->disp = self->src.disp;
if (insn->disp == 0 && !insn_need_disp(self))
insn->flags |= SRC_MEM;
diff --git a/test/unit/arch-x86/encode-test.c b/test/unit/arch-x86/encode-test.c
index e663d6ca..1167e0a6 100644
--- a/test/unit/arch-x86/encode-test.c
+++ b/test/unit/arch-x86/encode-test.c
@@ -431,6 +431,30 @@ void test_encoding_jmp_memindex(void)
teardown();
}
+void test_encoding_jmp_memindex_high_2(void)
+{
+#ifdef CONFIG_X86_64
+ uint8_t encoding[] = { 0x43, 0xff, 0x64, 0xf5, 0x00 };
+ struct insn insn = { };
+
+ setup();
+
+ /* jmpq *0x0(%r13,%r14,8) */
+ insn.type = INSN_JMP_MEMINDEX;
+ insn.dest.type = OPERAND_MEMINDEX;
+ insn.dest.base_reg.interval = &reg_r13;
+ insn.dest.index_reg.interval = &reg_r14;
+ insn.dest.shift = 3;
+
+ insn_encode(&insn, buffer, NULL);
+
+ assert_int_equals(ARRAY_SIZE(encoding), buffer_offset(buffer));
+ assert_mem_equals(encoding, buffer_ptr(buffer), ARRAY_SIZE(encoding));
+
+ teardown();
+#endif
+}
+
void test_encoding_jmp_memindex_high(void)
{
#ifdef CONFIG_X86_64