forked from dolphin-emu/dolphin
		
	
		
			
				
	
	
		
			242 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			242 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright 2008 Dolphin Emulator Project
 | |
| // Licensed under GPLv2+
 | |
| // Refer to the license.txt file included.
 | |
| 
 | |
| #include "Common/x64Analyzer.h"
 | |
| 
 | |
| bool DisassembleMov(const unsigned char *codePtr, InstructionInfo *info)
 | |
| {
 | |
| 	unsigned const char *startCodePtr = codePtr;
 | |
| 	u8 rex = 0;
 | |
| 	u32 opcode;
 | |
| 	int opcode_length;
 | |
| 
 | |
| 	//Check for regular prefix
 | |
| 	info->operandSize = 4;
 | |
| 	info->zeroExtend = false;
 | |
| 	info->signExtend = false;
 | |
| 	info->hasImmediate = false;
 | |
| 	info->isMemoryWrite = false;
 | |
| 	info->byteSwap = false;
 | |
| 
 | |
| 	u8 modRMbyte = 0;
 | |
| 	u8 sibByte = 0;
 | |
| 	bool hasModRM = false;
 | |
| 
 | |
| 	int displacementSize = 0;
 | |
| 
 | |
| 	if (*codePtr == 0x66)
 | |
| 	{
 | |
| 		info->operandSize = 2;
 | |
| 		codePtr++;
 | |
| 	}
 | |
| 	else if (*codePtr == 0x67)
 | |
| 	{
 | |
| 		codePtr++;
 | |
| 	}
 | |
| 
 | |
| 	//Check for REX prefix
 | |
| 	if ((*codePtr & 0xF0) == 0x40)
 | |
| 	{
 | |
| 		rex = *codePtr;
 | |
| 		if (rex & 8) //REX.W
 | |
| 		{
 | |
| 			info->operandSize = 8;
 | |
| 		}
 | |
| 		codePtr++;
 | |
| 	}
 | |
| 
 | |
| 	opcode = *codePtr++;
 | |
| 	opcode_length = 1;
 | |
| 	if (opcode == 0x0F)
 | |
| 	{
 | |
| 		opcode = (opcode << 8) | *codePtr++;
 | |
| 		opcode_length = 2;
 | |
| 		if ((opcode & 0xFB) == 0x38)
 | |
| 		{
 | |
| 			opcode = (opcode << 8) | *codePtr++;
 | |
| 			opcode_length = 3;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	switch (opcode_length)
 | |
| 	{
 | |
| 		case 1:
 | |
| 			if ((opcode & 0xF0) == 0x80 ||
 | |
| 			    ((opcode & 0xF8) == 0xC0 && (opcode & 0x0E) != 0x02))
 | |
| 			{
 | |
| 				modRMbyte = *codePtr++;
 | |
| 				hasModRM = true;
 | |
| 			}
 | |
| 			break;
 | |
| 		case 2:
 | |
| 			if (((opcode & 0xF0) == 0x00 && (opcode & 0x0F) >= 0x04 && (opcode & 0x0D) != 0x0D) ||
 | |
| 			    ((opcode & 0xF0) == 0xA0 && (opcode & 0x07) <= 0x02) ||
 | |
| 			    (opcode & 0xF0) == 0x30 ||
 | |
| 			    (opcode & 0xFF) == 0x77 ||
 | |
| 			    (opcode & 0xF0) == 0x80 ||
 | |
| 			    (opcode & 0xF8) == 0xC8)
 | |
| 			{
 | |
| 				// No mod R/M byte
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				modRMbyte = *codePtr++;
 | |
| 				hasModRM = true;
 | |
| 			}
 | |
| 			break;
 | |
| 		case 3:
 | |
| 			// TODO: support more 3-byte opcode instructions
 | |
| 			if ((opcode & 0xFE) == 0xF0)
 | |
| 			{
 | |
| 				modRMbyte = *codePtr++;
 | |
| 				hasModRM = true;
 | |
| 			}
 | |
| 			break;
 | |
| 	}
 | |
| 
 | |
| 	if (hasModRM)
 | |
| 	{
 | |
| 		ModRM mrm(modRMbyte, rex);
 | |
| 		info->regOperandReg = mrm.reg;
 | |
| 		if (mrm.mod < 3)
 | |
| 		{
 | |
| 			if (mrm.rm == 4)
 | |
| 			{
 | |
| 				//SIB byte
 | |
| 				sibByte = *codePtr++;
 | |
| 				info->scaledReg = (sibByte >> 3) & 7;
 | |
| 				info->otherReg = (sibByte & 7);
 | |
| 				if (rex & 2) info->scaledReg += 8;
 | |
| 				if (rex & 1) info->otherReg += 8;
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				//info->scaledReg =
 | |
| 			}
 | |
| 		}
 | |
| 		if (mrm.mod == 1 || mrm.mod == 2)
 | |
| 		{
 | |
| 			if (mrm.mod == 1)
 | |
| 				displacementSize = 1;
 | |
| 			else
 | |
| 				displacementSize = 4;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (displacementSize == 1)
 | |
| 		info->displacement = (s32)(s8)*codePtr;
 | |
| 	else
 | |
| 		info->displacement = *((s32*)codePtr);
 | |
| 	codePtr += displacementSize;
 | |
| 
 | |
| 	switch (opcode)
 | |
| 	{
 | |
| 	case 0xC6: // mem <- imm8
 | |
| 		info->isMemoryWrite = true;
 | |
| 		info->hasImmediate = true;
 | |
| 		info->immediate = *codePtr;
 | |
| 		info->operandSize = 1;
 | |
| 		codePtr++;
 | |
| 		break;
 | |
| 
 | |
| 	case 0xC7: // mem <- imm16/32
 | |
| 		info->isMemoryWrite = true;
 | |
| 		switch (info->operandSize)
 | |
| 		{
 | |
| 		case 2:
 | |
| 			info->hasImmediate = true;
 | |
| 			info->immediate = *(u16*)codePtr;
 | |
| 			codePtr += 2;
 | |
| 			break;
 | |
| 
 | |
| 		case 4:
 | |
| 			info->hasImmediate = true;
 | |
| 			info->immediate = *(u32*)codePtr;
 | |
| 			codePtr += 4;
 | |
| 			break;
 | |
| 
 | |
| 		case 8:
 | |
| 			info->zeroExtend = true;
 | |
| 			info->immediate = *(u32*)codePtr;
 | |
| 			codePtr += 4;
 | |
| 			break;
 | |
| 		}
 | |
| 		break;
 | |
| 
 | |
| 	case 0x88: // mem <- r8
 | |
| 		info->isMemoryWrite = true;
 | |
| 		if (info->operandSize != 4)
 | |
| 		{
 | |
| 			return false;
 | |
| 		}
 | |
| 		info->operandSize = 1;
 | |
| 		break;
 | |
| 
 | |
| 	case 0x89: // mem <- r16/32/64
 | |
| 		info->isMemoryWrite = true;
 | |
| 		break;
 | |
| 
 | |
| 	case 0x8A: // r8 <- mem
 | |
| 		if (info->operandSize != 4)
 | |
| 		{
 | |
| 			return false;
 | |
| 		}
 | |
| 		info->operandSize = 1;
 | |
| 		break;
 | |
| 
 | |
| 	case 0x8B: // r16/32/64 <- mem
 | |
| 		break;
 | |
| 
 | |
| 	case 0x0FB6: // movzx on byte
 | |
| 		info->zeroExtend = true;
 | |
| 		info->operandSize = 1;
 | |
| 		break;
 | |
| 
 | |
| 	case 0x0FB7: // movzx on short
 | |
| 		info->zeroExtend = true;
 | |
| 		info->operandSize = 2;
 | |
| 		break;
 | |
| 
 | |
| 	case 0x0FBE: // movsx on byte
 | |
| 		info->signExtend = true;
 | |
| 		info->operandSize = 1;
 | |
| 		break;
 | |
| 
 | |
| 	case 0x0FBF: // movsx on short
 | |
| 		info->signExtend = true;
 | |
| 		info->operandSize = 2;
 | |
| 		break;
 | |
| 
 | |
| 	case 0x0F38F0: // movbe read
 | |
| 		info->byteSwap = true;
 | |
| 		break;
 | |
| 
 | |
| 	case 0x0F38F1: // movbe write
 | |
| 		info->byteSwap = true;
 | |
| 		info->isMemoryWrite = true;
 | |
| 		break;
 | |
| 
 | |
| 	default:
 | |
| 		return false;
 | |
| 	}
 | |
| 	info->instructionSize = (int)(codePtr - startCodePtr);
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| bool InstructionInfo::operator==(const InstructionInfo &other) const
 | |
| {
 | |
| 	return operandSize     == other.operandSize     &&
 | |
| 	       instructionSize == other.instructionSize &&
 | |
| 	       regOperandReg   == other.regOperandReg   &&
 | |
| 	       otherReg        == other.otherReg        &&
 | |
| 	       scaledReg       == other.scaledReg       &&
 | |
| 	       zeroExtend      == other.zeroExtend      &&
 | |
| 	       signExtend      == other.signExtend      &&
 | |
| 	       hasImmediate    == other.hasImmediate    &&
 | |
| 	       isMemoryWrite   == other.isMemoryWrite   &&
 | |
| 	       byteSwap        == other.byteSwap        &&
 | |
| 	       immediate       == other.immediate       &&
 | |
| 	       displacement    == other.displacement;
 | |
| }
 |