extract decoding of modrm into dedicated function in decoder

This commit is contained in:
Stanislav Shwartsman 2016-07-03 19:51:33 +00:00
parent 586031ca9f
commit 98da36a63f
2 changed files with 247 additions and 211 deletions

View File

@ -1273,6 +1273,151 @@ static const BxOpcodeInfo_t BxOpcodeInfo32[512*2] = {
/* 0F FF /d */ { 0, BX_IA_ERROR }
};
const Bit8u *decodeModrm32(const Bit8u *iptr, unsigned &remain, bxInstruction_c *i, unsigned mod, unsigned nnn, unsigned rm)
{
unsigned seg = BX_SEG_REG_DS;
i->setSibBase(rm); // initialize with rm to use BxResolve32Base
i->setSibIndex(4); // no Index encoding by default
// initialize displ32 with zero to include cases with no diplacement
i->modRMForm.displ32u = 0;
// note that mod==11b handled outside
if (i->as32L()) {
if (rm != 4) { // no s-i-b byte
if (mod == 0x00) { // mod == 00b
if (rm == 5) {
i->setSibBase(BX_NIL_REGISTER);
if (remain > 3) {
i->modRMForm.displ32u = FetchDWORD(iptr);
iptr += 4;
remain -= 4;
}
else return NULL;
}
// mod==00b, rm!=4, rm!=5
goto modrm_done;
}
seg = sreg_mod1or2_base32[rm];
}
else { // mod!=11b, rm==4, s-i-b byte follows
unsigned sib, base, index, scale;
if (remain != 0) {
sib = *iptr++;
remain--;
}
else {
return NULL;
}
base = sib & 0x7; sib >>= 3;
index = sib & 0x7; sib >>= 3;
scale = sib;
i->setSibScale(scale);
i->setSibBase(base);
// this part is a little tricky - assign index value always,
// it will be really used if the instruction is Gather. Others
// assume that resolve function will do the right thing.
i->setSibIndex(index);
if (mod == 0x00) { // mod==00b, rm==4
seg = sreg_mod0_base32[base];
if (base == 5) {
i->setSibBase(BX_NIL_REGISTER);
if (remain > 3) {
i->modRMForm.displ32u = FetchDWORD(iptr);
iptr += 4;
remain -= 4;
}
else {
return NULL;
}
}
// mod==00b, rm==4, base!=5
goto modrm_done;
}
else {
seg = sreg_mod1or2_base32[base];
}
}
if (mod == 0x40) { // mod==01b
if (remain != 0) {
// 8 sign extended to 32
i->modRMForm.displ32u = (Bit8s) *iptr++;
remain--;
}
else {
return NULL;
}
}
else {
// (mod == 0x80), mod==10b
if (remain > 3) {
i->modRMForm.displ32u = FetchDWORD(iptr);
iptr += 4;
remain -= 4;
}
else {
return NULL;
}
}
}
else {
// 16-bit addressing modes, mod==11b handled above
i->setSibBase(Resolve16BaseReg[rm]);
i->setSibIndex(Resolve16IndexReg[rm]);
i->setSibScale(0);
if (mod == 0x00) { // mod == 00b
seg = sreg_mod00_rm16[rm];
if (rm == 6) {
i->setSibBase(BX_NIL_REGISTER);
if (remain > 1) {
i->modRMForm.displ32u = (Bit32s) (Bit16s) FetchWORD(iptr);
iptr += 2;
remain -= 2;
}
else {
return NULL;
}
}
goto modrm_done;
}
else {
seg = sreg_mod01or10_rm16[rm];
}
if (mod == 0x40) { // mod == 01b
if (remain != 0) {
// 8 sign extended to 16
i->modRMForm.displ32u = (Bit32s) (Bit8s) *iptr++;
remain--;
}
else {
return NULL;
}
}
else {
// (mod == 0x80) mod == 10b
if (remain > 1) {
i->modRMForm.displ32u = (Bit32s) (Bit16s) FetchWORD(iptr);
iptr += 2;
remain -= 2;
}
else {
return NULL;
}
}
}
modrm_done:
i->setSeg(seg);
return iptr;
}
int fetchDecode32(const Bit8u *iptr, Bit32u fetchModeMask, bx_bool handle_lock_cr0, bxInstruction_c *i, unsigned remainingInPage)
{
if (remainingInPage > 15) remainingInPage = 15;
@ -1550,142 +1695,19 @@ fetch_b1:
if (mod == 0xc0) { // mod == 11b
i->assertModC0();
goto modrm_done;
}
mod_mem = 1;
i->setSibBase(rm); // initialize with rm to use BxResolve32Base
i->setSibIndex(4); // no Index encoding
// initialize displ32 with zero to include cases with no diplacement
i->modRMForm.displ32u = 0;
if (i->as32L()) {
// 32-bit addressing modes; note that mod==11b handled above
if (rm != 4) { // no s-i-b byte
if (mod == 0x00) { // mod == 00b
if (rm == 5) {
i->setSibBase(BX_NIL_REGISTER);
if (remain > 3) {
i->modRMForm.displ32u = FetchDWORD(iptr);
iptr += 4;
remain -= 4;
}
else return(-1);
}
// mod==00b, rm!=4, rm!=5
goto modrm_done;
}
seg = sreg_mod1or2_base32[rm];
}
else { // mod!=11b, rm==4, s-i-b byte follows
unsigned sib, base, index, scale;
if (remain != 0) {
sib = *iptr++;
remain--;
}
else {
return(-1);
}
base = sib & 0x7; sib >>= 3;
index = sib & 0x7; sib >>= 3;
scale = sib;
i->setSibScale(scale);
i->setSibBase(base);
// this part is a little tricky - assign index value always,
// it will be really used if the instruction is Gather. Others
// assume that resolve function will do the right thing.
i->setSibIndex(index);
if (mod == 0x00) { // mod==00b, rm==4
seg = sreg_mod0_base32[base];
if (base == 5) {
i->setSibBase(BX_NIL_REGISTER);
if (remain > 3) {
i->modRMForm.displ32u = FetchDWORD(iptr);
iptr += 4;
remain -= 4;
}
else {
return(-1);
}
}
// mod==00b, rm==4, base!=5
goto modrm_done;
}
seg = sreg_mod1or2_base32[base];
}
if (mod == 0x40) { // mod==01b
if (remain != 0) {
// 8 sign extended to 32
i->modRMForm.displ32u = (Bit8s) *iptr++;
#if BX_SUPPORT_EVEX
displ8 = 1;
#endif
remain--;
goto modrm_done;
}
else {
return(-1);
}
}
// (mod == 0x80), mod==10b
if (remain > 3) {
i->modRMForm.displ32u = FetchDWORD(iptr);
iptr += 4;
remain -= 4;
}
else {
return(-1);
}
}
else {
// 16-bit addressing modes, mod==11b handled above
i->setSibBase(Resolve16BaseReg[rm]);
i->setSibIndex(Resolve16IndexReg[rm]);
i->setSibScale(0);
if (mod == 0x00) { // mod == 00b
seg = sreg_mod00_rm16[rm];
if (rm == 6) {
i->setSibBase(BX_NIL_REGISTER);
if (remain > 1) {
i->modRMForm.displ32u = (Bit32s) (Bit16s) FetchWORD(iptr);
iptr += 2;
remain -= 2;
goto modrm_done;
}
else return(-1);
}
goto modrm_done;
}
seg = sreg_mod01or10_rm16[rm];
if (mod == 0x40) { // mod == 01b
if (remain != 0) {
// 8 sign extended to 16
i->modRMForm.displ32u = (Bit32s) (Bit8s) *iptr++;
#if BX_SUPPORT_EVEX
displ8 = 1;
#endif
remain--;
goto modrm_done;
}
else {
return(-1);
}
}
// (mod == 0x80) mod == 10b
if (remain > 1) {
i->modRMForm.displ32u = (Bit32s) (Bit16s) FetchWORD(iptr);
iptr += 2;
remain -= 2;
}
else {
mod_mem = 1;
iptr = decodeModrm32(iptr, remain, i, mod, nnn, rm);
if (! iptr)
return(-1);
#if BX_SUPPORT_EVEX
if (mod == 0x40) { // mod==01b
displ8 = 1;
}
#endif
}
modrm_done:
#if BX_SUPPORT_EVEX
// EVEX.b in reg form implies 512-bit vector length
if (i->modC0() && i->getEvexb()) {
@ -1710,6 +1732,7 @@ modrm_done:
rm = b1 & 0x7;
nnn = (b1 >> 3) & 0x7;
i->assertModC0();
i->setSeg(seg);
}
if (lock) { // lock prefix invalid opcode
@ -1933,8 +1956,7 @@ modrm_done:
// assign memory segment override
if (! BX_NULL_SEG_REG(seg_override))
seg = seg_override;
i->setSeg(seg);
i->setSeg(seg_override);
#if BX_SUPPORT_AVX
if (had_vex_xop) {

View File

@ -1690,6 +1690,92 @@ static const BxOpcodeInfo_t BxOpcodeInfo64[512*3] = {
/* 0F FF /q */ { 0, BX_IA_ERROR }
};
const Bit8u *decodeModrm64(const Bit8u *iptr, unsigned &remain, bxInstruction_c *i, unsigned mod, unsigned nnn, unsigned rm, unsigned rex_r, unsigned rex_x, unsigned rex_b)
{
unsigned seg = BX_SEG_REG_DS;
i->setSibBase(rm & 0xf); // initialize with rm to use BxResolve64Base
i->setSibIndex(4);
// initialize displ32 with zero to include cases with no diplacement
i->modRMForm.displ32u = 0;
// note that mod==11b handled outside
if ((rm & 0x7) != 4) { // no s-i-b byte
if (mod == 0x00) { // mod == 00b
if ((rm & 0x7) == 5) {
i->setSibBase(BX_64BIT_REG_RIP);
goto get_32bit_displ;
}
// mod==00b, rm!=4, rm!=5
goto modrm_done;
}
// (mod == 0x40), mod==01b or (mod == 0x80), mod==10b
seg = sreg_mod1or2_base32[rm & 0xf];
}
else { // mod!=11b, rm==4, s-i-b byte follows
unsigned sib, base, index, scale;
if (remain != 0) {
sib = *iptr++;
remain--;
}
else {
return NULL;
}
base = (sib & 0x7) | rex_b; sib >>= 3;
index = (sib & 0x7) | rex_x; sib >>= 3;
scale = sib;
i->setSibScale(scale);
i->setSibBase(base & 0xf);
// this part is a little tricky - assign index value always,
// it will be really used if the instruction is Gather. Others
// assume that resolve function will do the right thing.
i->setSibIndex(index & 0xf);
if (mod == 0x00) { // mod==00b, rm==4
seg = sreg_mod0_base32[base & 0xf];
if ((base & 0x7) == 5) {
i->setSibBase(BX_NIL_REGISTER);
goto get_32bit_displ;
}
// mod==00b, rm==4, base!=5
goto modrm_done;
}
// (mod == 0x40), mod==01b or (mod == 0x80), mod==10b
seg = sreg_mod1or2_base32[base & 0xf];
}
// (mod == 0x40), mod==01b
if (mod == 0x40) {
if (remain != 0) {
// 8 sign extended to 32
i->modRMForm.displ32u = (Bit8s) *iptr++;
remain--;
}
else {
return NULL;
}
}
else {
get_32bit_displ:
// (mod == 0x80), mod==10b
if (remain > 3) {
i->modRMForm.displ32u = FetchDWORD(iptr);
iptr += 4;
remain -= 4;
}
else {
return NULL;
}
}
modrm_done:
i->setSeg(seg);
return iptr;
}
int fetchDecode64(const Bit8u *iptr, Bit32u fetchModeMask, bx_bool handle_lock_cr0, bxInstruction_c *i, unsigned remainingInPage)
{
if (remainingInPage > 15) remainingInPage = 15;
@ -2041,91 +2127,19 @@ fetch_b1:
if (mod == 0xc0) { // mod == 11b
i->assertModC0();
goto modrm_done;
}
mod_mem = 1;
i->setSibBase(rm & 0xf); // initialize with rm to use BxResolve64Base
i->setSibIndex(4);
// initialize displ32 with zero to include cases with no diplacement
i->modRMForm.displ32u = 0;
// note that mod==11b handled above
if ((rm & 0x7) != 4) { // no s-i-b byte
if (mod == 0x00) { // mod == 00b
if ((rm & 0x7) == 5) {
i->setSibBase(BX_64BIT_REG_RIP);
goto get_32bit_displ;
}
// mod==00b, rm!=4, rm!=5
goto modrm_done;
}
// (mod == 0x40), mod==01b or (mod == 0x80), mod==10b
seg = sreg_mod1or2_base32[rm & 0xf];
}
else { // mod!=11b, rm==4, s-i-b byte follows
unsigned sib, base, index, scale;
if (remain != 0) {
sib = *iptr++;
remain--;
}
else {
return(-1);
}
base = (sib & 0x7) | rex_b; sib >>= 3;
index = (sib & 0x7) | rex_x; sib >>= 3;
scale = sib;
i->setSibScale(scale);
i->setSibBase(base & 0xf);
// this part is a little tricky - assign index value always,
// it will be really used if the instruction is Gather. Others
// assume that resolve function will do the right thing.
i->setSibIndex(index & 0xf);
if (mod == 0x00) { // mod==00b, rm==4
seg = sreg_mod0_base32[base & 0xf];
if ((base & 0x7) == 5) {
i->setSibBase(BX_NIL_REGISTER);
goto get_32bit_displ;
}
// mod==00b, rm==4, base!=5
goto modrm_done;
}
// (mod == 0x40), mod==01b or (mod == 0x80), mod==10b
seg = sreg_mod1or2_base32[base & 0xf];
}
// (mod == 0x40), mod==01b
if (mod == 0x40) {
if (remain != 0) {
// 8 sign extended to 32
i->modRMForm.displ32u = (Bit8s) *iptr++;
#if BX_SUPPORT_EVEX
displ8 = 1;
#endif
remain--;
}
else {
return(-1);
}
}
else {
get_32bit_displ:
// (mod == 0x80), mod==10b
if (remain > 3) {
i->modRMForm.displ32u = FetchDWORD(iptr);
iptr += 4;
remain -= 4;
}
else {
mod_mem = 1;
iptr = decodeModrm64(iptr, remain, i, mod, nnn, rm, rex_r, rex_x, rex_b);
if (! iptr)
return(-1);
#if BX_SUPPORT_EVEX
if (mod == 0x40) { // mod==01b
displ8 = 1;
}
#endif
}
modrm_done:
#if BX_SUPPORT_EVEX
// EVEX.b in reg form implies 512-bit vector length
if (i->modC0() && i->getEvexb()) {