2013-04-18 03:09:55 +00:00
|
|
|
// Copyright 2013 Dolphin Emulator Project
|
|
|
|
// Licensed under GPLv2
|
|
|
|
// Refer to the license.txt file included.
|
2009-03-28 08:57:34 +00:00
|
|
|
|
2014-02-17 10:18:15 +00:00
|
|
|
#include "Common/x64Analyzer.h"
|
2008-12-08 05:30:24 +00:00
|
|
|
|
2013-09-02 20:37:04 +00:00
|
|
|
bool DisassembleMov(const unsigned char *codePtr, InstructionInfo *info)
|
2008-12-08 05:30:24 +00:00
|
|
|
{
|
|
|
|
unsigned const char *startCodePtr = codePtr;
|
|
|
|
u8 rex = 0;
|
|
|
|
u8 codeByte = 0;
|
|
|
|
u8 codeByte2 = 0;
|
2013-10-29 05:23:17 +00:00
|
|
|
|
2008-12-08 05:30:24 +00:00
|
|
|
//Check for regular prefix
|
2013-09-02 20:37:04 +00:00
|
|
|
info->operandSize = 4;
|
|
|
|
info->zeroExtend = false;
|
|
|
|
info->signExtend = false;
|
|
|
|
info->hasImmediate = false;
|
|
|
|
info->isMemoryWrite = false;
|
2008-12-08 05:30:24 +00:00
|
|
|
|
|
|
|
u8 modRMbyte = 0;
|
|
|
|
u8 sibByte = 0;
|
2013-04-15 20:28:55 +00:00
|
|
|
bool hasModRM = false;
|
2008-12-08 05:30:24 +00:00
|
|
|
|
|
|
|
int displacementSize = 0;
|
|
|
|
|
|
|
|
if (*codePtr == 0x66)
|
|
|
|
{
|
2013-09-02 20:37:04 +00:00
|
|
|
info->operandSize = 2;
|
2008-12-08 05:30:24 +00:00
|
|
|
codePtr++;
|
2013-10-29 05:23:17 +00:00
|
|
|
}
|
2008-12-08 05:30:24 +00:00
|
|
|
else if (*codePtr == 0x67)
|
|
|
|
{
|
|
|
|
codePtr++;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Check for REX prefix
|
|
|
|
if ((*codePtr & 0xF0) == 0x40)
|
|
|
|
{
|
|
|
|
rex = *codePtr;
|
|
|
|
if (rex & 8) //REX.W
|
|
|
|
{
|
2013-09-02 20:37:04 +00:00
|
|
|
info->operandSize = 8;
|
2008-12-08 05:30:24 +00:00
|
|
|
}
|
|
|
|
codePtr++;
|
|
|
|
}
|
|
|
|
|
|
|
|
codeByte = *codePtr++;
|
|
|
|
|
2013-10-29 05:23:17 +00:00
|
|
|
// Skip two-byte opcode byte
|
|
|
|
bool twoByte = false;
|
|
|
|
if(codeByte == 0x0F)
|
2013-04-15 20:28:55 +00:00
|
|
|
{
|
2013-10-29 05:23:17 +00:00
|
|
|
twoByte = true;
|
2008-12-08 05:30:24 +00:00
|
|
|
codeByte2 = *codePtr++;
|
2013-04-15 20:28:55 +00:00
|
|
|
}
|
2008-12-08 05:30:24 +00:00
|
|
|
|
|
|
|
if (!twoByte)
|
|
|
|
{
|
2013-10-29 05:23:17 +00:00
|
|
|
if ((codeByte & 0xF0) == 0x80 ||
|
2013-03-20 01:51:12 +00:00
|
|
|
((codeByte & 0xF8) == 0xC0 && (codeByte & 0x0E) != 0x02))
|
2008-12-08 05:30:24 +00:00
|
|
|
{
|
|
|
|
modRMbyte = *codePtr++;
|
|
|
|
hasModRM = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-10-29 05:23:17 +00:00
|
|
|
if (((codeByte2 & 0xF0) == 0x00 && (codeByte2 & 0x0F) >= 0x04 && (codeByte2 & 0x0D) != 0x0D) ||
|
|
|
|
(codeByte2 & 0xF0) == 0x30 ||
|
|
|
|
codeByte2 == 0x77 ||
|
|
|
|
(codeByte2 & 0xF0) == 0x80 ||
|
|
|
|
((codeByte2 & 0xF0) == 0xA0 && (codeByte2 & 0x07) <= 0x02) ||
|
|
|
|
(codeByte2 & 0xF8) == 0xC8)
|
2013-09-02 20:37:04 +00:00
|
|
|
{
|
2013-10-29 05:23:17 +00:00
|
|
|
// No mod R/M byte
|
2013-09-02 20:37:04 +00:00
|
|
|
}
|
2013-10-29 05:23:17 +00:00
|
|
|
else
|
2013-09-02 20:37:04 +00:00
|
|
|
{
|
2008-12-08 05:30:24 +00:00
|
|
|
modRMbyte = *codePtr++;
|
|
|
|
hasModRM = true;
|
2013-10-29 05:23:17 +00:00
|
|
|
}
|
2008-12-08 05:30:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (hasModRM)
|
|
|
|
{
|
|
|
|
ModRM mrm(modRMbyte, rex);
|
2013-09-02 20:37:04 +00:00
|
|
|
info->regOperandReg = mrm.reg;
|
2008-12-08 05:30:24 +00:00
|
|
|
if (mrm.mod < 3)
|
|
|
|
{
|
|
|
|
if (mrm.rm == 4)
|
|
|
|
{
|
|
|
|
//SIB byte
|
|
|
|
sibByte = *codePtr++;
|
2013-09-02 20:37:04 +00:00
|
|
|
info->scaledReg = (sibByte >> 3) & 7;
|
|
|
|
info->otherReg = (sibByte & 7);
|
|
|
|
if (rex & 2) info->scaledReg += 8;
|
|
|
|
if (rex & 1) info->otherReg += 8;
|
2008-12-08 05:30:24 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-10-29 05:23:17 +00:00
|
|
|
//info->scaledReg =
|
2008-12-08 05:30:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (mrm.mod == 1 || mrm.mod == 2)
|
|
|
|
{
|
|
|
|
if (mrm.mod == 1)
|
|
|
|
displacementSize = 1;
|
|
|
|
else
|
|
|
|
displacementSize = 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (displacementSize == 1)
|
2013-09-02 20:37:04 +00:00
|
|
|
info->displacement = (s32)(s8)*codePtr;
|
2008-12-08 05:30:24 +00:00
|
|
|
else
|
2013-09-02 20:37:04 +00:00
|
|
|
info->displacement = *((s32 *)codePtr);
|
2008-12-08 05:30:24 +00:00
|
|
|
codePtr += displacementSize;
|
|
|
|
|
2013-03-20 01:51:12 +00:00
|
|
|
|
2013-09-02 20:37:04 +00:00
|
|
|
switch (codeByte)
|
2008-12-08 05:30:24 +00:00
|
|
|
{
|
2013-09-02 20:37:04 +00:00
|
|
|
// writes
|
|
|
|
case 0xC6: // mem <- imm8
|
2008-12-08 05:30:24 +00:00
|
|
|
{
|
2013-09-02 20:37:04 +00:00
|
|
|
info->isMemoryWrite = true;
|
|
|
|
info->hasImmediate = true;
|
|
|
|
info->immediate = *codePtr;
|
|
|
|
codePtr++; //move past immediate
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xC7: // mem <- imm16/32
|
|
|
|
{
|
|
|
|
info->isMemoryWrite = true;
|
|
|
|
if (info->operandSize == 2)
|
2008-12-08 05:30:24 +00:00
|
|
|
{
|
2013-09-02 20:37:04 +00:00
|
|
|
info->hasImmediate = true;
|
|
|
|
info->immediate = *(u16*)codePtr;
|
|
|
|
codePtr += 2;
|
2008-12-08 05:30:24 +00:00
|
|
|
}
|
2013-09-02 20:37:04 +00:00
|
|
|
else if (info->operandSize == 4)
|
2008-12-08 05:30:24 +00:00
|
|
|
{
|
2013-09-02 20:37:04 +00:00
|
|
|
info->hasImmediate = true;
|
|
|
|
info->immediate = *(u32*)codePtr;
|
|
|
|
codePtr += 4;
|
2008-12-08 05:30:24 +00:00
|
|
|
}
|
2013-09-02 20:37:04 +00:00
|
|
|
else if (info->operandSize == 8)
|
|
|
|
{
|
|
|
|
info->zeroExtend = true;
|
|
|
|
info->immediate = *(u32*)codePtr;
|
|
|
|
codePtr += 4;
|
|
|
|
}
|
|
|
|
}
|
2008-12-08 05:30:24 +00:00
|
|
|
|
2013-09-25 02:47:01 +00:00
|
|
|
case 0x88: // mem <- r8
|
|
|
|
{
|
|
|
|
info->isMemoryWrite = true;
|
|
|
|
if (info->operandSize == 4)
|
|
|
|
{
|
|
|
|
info->operandSize = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-09-02 20:37:04 +00:00
|
|
|
case 0x89: // mem <- r16/32/64
|
|
|
|
{
|
|
|
|
info->isMemoryWrite = true;
|
|
|
|
break;
|
2008-12-08 05:30:24 +00:00
|
|
|
}
|
|
|
|
|
2013-09-02 20:37:04 +00:00
|
|
|
case 0x0F: // two-byte escape
|
2008-12-08 05:30:24 +00:00
|
|
|
{
|
2013-09-02 20:37:04 +00:00
|
|
|
info->isMemoryWrite = false;
|
2008-12-08 05:30:24 +00:00
|
|
|
switch (codeByte2)
|
|
|
|
{
|
2013-09-02 20:37:04 +00:00
|
|
|
case 0xB6: // movzx on byte
|
|
|
|
info->zeroExtend = true;
|
|
|
|
info->operandSize = 1;
|
2008-12-08 05:30:24 +00:00
|
|
|
break;
|
2013-09-02 20:37:04 +00:00
|
|
|
case 0xB7: // movzx on short
|
|
|
|
info->zeroExtend = true;
|
|
|
|
info->operandSize = 2;
|
2008-12-08 05:30:24 +00:00
|
|
|
break;
|
2013-09-02 20:37:04 +00:00
|
|
|
case 0xBE: // movsx on byte
|
|
|
|
info->signExtend = true;
|
|
|
|
info->operandSize = 1;
|
2008-12-08 05:30:24 +00:00
|
|
|
break;
|
2013-09-02 20:37:04 +00:00
|
|
|
case 0xBF: // movsx on short
|
|
|
|
info->signExtend = true;
|
|
|
|
info->operandSize = 2;
|
2008-12-08 05:30:24 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
break;
|
2013-09-02 20:37:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
case 0x8A: // r8 <- mem
|
|
|
|
{
|
|
|
|
info->isMemoryWrite = false;
|
|
|
|
if (info->operandSize == 4)
|
2008-12-08 05:30:24 +00:00
|
|
|
{
|
2013-09-02 20:37:04 +00:00
|
|
|
info->operandSize = 1;
|
2008-12-08 05:30:24 +00:00
|
|
|
break;
|
|
|
|
}
|
2013-09-02 20:37:04 +00:00
|
|
|
else
|
2008-12-08 05:30:24 +00:00
|
|
|
return false;
|
|
|
|
}
|
2013-09-02 20:37:04 +00:00
|
|
|
|
|
|
|
case 0x8B: // r16/32/64 <- mem
|
|
|
|
{
|
|
|
|
info->isMemoryWrite = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return false;
|
2008-12-08 05:30:24 +00:00
|
|
|
}
|
2013-09-02 20:37:04 +00:00
|
|
|
info->instructionSize = (int)(codePtr - startCodePtr);
|
2008-12-08 05:30:24 +00:00
|
|
|
return true;
|
|
|
|
}
|