From 89d6b5a5a7dd0e6500729ab83da92226753b3106 Mon Sep 17 00:00:00 2001 From: Alexis Engelke Date: Sun, 24 Feb 2019 09:25:19 +0100 Subject: [PATCH] Refactor ModRM decoding --- decode.c | 75 ++++++++++++-------------------------------------------- 1 file changed, 15 insertions(+), 60 deletions(-) diff --git a/decode.c b/decode.c index a3f7909..4c421cd 100644 --- a/decode.c +++ b/decode.c @@ -241,15 +241,12 @@ decode_modrm(const uint8_t* buffer, int len, DecodeMode mode, FdInstr* instr, // SIB byte uint8_t scale = 0; - uint8_t idx = 0; - uint8_t base = 0; + uint8_t idx = 4; + uint8_t base = rm; if (rm == 4) { if (UNLIKELY(off >= len)) - { return -1; - } - uint8_t sib = buffer[off++]; scale = (sib & 0xc0) >> 6; idx = (sib & 0x38) >> 3; @@ -259,23 +256,29 @@ decode_modrm(const uint8_t* buffer, int len, DecodeMode mode, FdInstr* instr, base = sib & 0x07; } + out_o1->type = FD_OT_MEM; + instr->idx_scale = scale; + instr->idx_reg = idx == 4 ? FD_REG_NONE : idx; + + // RIP-relative addressing only if SIB-byte is absent + if (mod == 0 && rm == 5 && mode == DECODE_64) + out_o1->reg = FD_REG_IP; + else if (mod == 0 && base == 5) + out_o1->reg = FD_REG_NONE; + else + out_o1->reg = base + (prefixes & PREFIX_REXB ? 8 : 0); + if (mod == 1) { if (UNLIKELY(off + 1 > len)) - { return -1; - } - instr->disp = (int8_t) LOAD_LE_1(&buffer[off]); off += 1; } - else if (mod == 2 || (mod == 0 && (rm == 5 || base == 5))) + else if (mod == 2 || (mod == 0 && base == 5)) { if (UNLIKELY(off + 4 > len)) - { return -1; - } - instr->disp = (int32_t) LOAD_LE_4(&buffer[off]); off += 4; } @@ -284,54 +287,6 @@ decode_modrm(const uint8_t* buffer, int len, DecodeMode mode, FdInstr* instr, instr->disp = 0; } - out_o1->type = FD_OT_MEM; - instr->idx_scale = scale; - - // If there was no SIB byte. - if (rm != 4) - { - instr->idx_reg = FD_REG_NONE; - if (mod == 0 && rm == 5) - { -#if defined(ARCH_X86_64) - if (mode == DECODE_64) - out_o1->reg = FD_REG_IP; - else -#endif - out_o1->reg = FD_REG_NONE; - return off; - } - - uint8_t reg_idx = rm; -#if defined(ARCH_X86_64) - reg_idx += prefixes & PREFIX_REXB ? 8 : 0; -#endif - out_o1->reg = reg_idx; - return off; - } - - if (idx == 4) - { - instr->idx_reg = FD_REG_NONE; - } - else - { - instr->idx_reg = idx; - } - - if (base == 5 && mod == 0) - { - out_o1->reg = FD_REG_NONE; - } - else - { - uint8_t reg_idx = base; -#if defined(ARCH_X86_64) - reg_idx += prefixes & PREFIX_REXB ? 8 : 0; -#endif - out_o1->reg = reg_idx; - } - return off; }