Refactor ModRM decoding

This commit is contained in:
Alexis Engelke
2019-02-24 09:25:19 +01:00
parent 1670a52047
commit 89d6b5a5a7

View File

@@ -241,15 +241,12 @@ decode_modrm(const uint8_t* buffer, int len, DecodeMode mode, FdInstr* instr,
// SIB byte // SIB byte
uint8_t scale = 0; uint8_t scale = 0;
uint8_t idx = 0; uint8_t idx = 4;
uint8_t base = 0; uint8_t base = rm;
if (rm == 4) if (rm == 4)
{ {
if (UNLIKELY(off >= len)) if (UNLIKELY(off >= len))
{
return -1; return -1;
}
uint8_t sib = buffer[off++]; uint8_t sib = buffer[off++];
scale = (sib & 0xc0) >> 6; scale = (sib & 0xc0) >> 6;
idx = (sib & 0x38) >> 3; idx = (sib & 0x38) >> 3;
@@ -259,23 +256,29 @@ decode_modrm(const uint8_t* buffer, int len, DecodeMode mode, FdInstr* instr,
base = sib & 0x07; 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 (mod == 1)
{ {
if (UNLIKELY(off + 1 > len)) if (UNLIKELY(off + 1 > len))
{
return -1; return -1;
}
instr->disp = (int8_t) LOAD_LE_1(&buffer[off]); instr->disp = (int8_t) LOAD_LE_1(&buffer[off]);
off += 1; 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)) if (UNLIKELY(off + 4 > len))
{
return -1; return -1;
}
instr->disp = (int32_t) LOAD_LE_4(&buffer[off]); instr->disp = (int32_t) LOAD_LE_4(&buffer[off]);
off += 4; off += 4;
} }
@@ -284,54 +287,6 @@ decode_modrm(const uint8_t* buffer, int len, DecodeMode mode, FdInstr* instr,
instr->disp = 0; 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; return off;
} }