diff options
author | Pekka Enberg <penberg@kernel.org> | 2013-06-13 14:26:23 +0300 |
---|---|---|
committer | Pekka Enberg <penberg@kernel.org> | 2013-06-18 14:48:35 +0300 |
commit | 5f9ee0e790706699a0f49ece2359cf1e0c2214c3 (patch) | |
tree | c6c1a5612ec0af4141a57c4c90a2fae5ee07322b | |
parent | d494ba1ecd6286f7fa2102b0e99a308de839a84f (diff) | |
download | jato-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.c | 19 | ||||
-rw-r--r-- | test/unit/arch-x86/encode-test.c | 24 |
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 = ®_r13; + insn.dest.index_reg.interval = ®_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 |