0
mirror of https://github.com/sampletext32/ParkanPlayground.git synced 2025-05-19 11:51:17 +03:00

Added support for MOV r/m8, imm8 (0xC6) and ADD r/m32, r32 (0x01) instructions with tests

This commit is contained in:
bird_egop 2025-04-13 00:50:23 +03:00
parent 266fdfeee5
commit 7d23af32fa
5 changed files with 298 additions and 0 deletions

View File

@ -0,0 +1,73 @@
namespace X86Disassembler.X86.Handlers.Add;
/// <summary>
/// Handler for ADD r/m32, r32 instruction (0x01)
/// </summary>
public class AddRm32R32Handler : InstructionHandler
{
/// <summary>
/// Initializes a new instance of the AddRm32R32Handler class
/// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param>
public AddRm32R32Handler(byte[] codeBuffer, InstructionDecoder decoder, int length)
: base(codeBuffer, decoder, length)
{
}
/// <summary>
/// Checks if this handler can decode the given opcode
/// </summary>
/// <param name="opcode">The opcode to check</param>
/// <returns>True if this handler can decode the opcode</returns>
public override bool CanHandle(byte opcode)
{
return opcode == 0x01;
}
/// <summary>
/// Decodes an ADD r/m32, r32 instruction
/// </summary>
/// <param name="opcode">The opcode of the instruction</param>
/// <param name="instruction">The instruction object to populate</param>
/// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction)
{
int position = Decoder.GetPosition();
if (position >= Length)
{
return false;
}
// Read the ModR/M byte
byte modRM = CodeBuffer[position++];
Decoder.SetPosition(position);
// Extract the fields from the ModR/M byte
byte mod = (byte)((modRM & 0xC0) >> 6);
byte reg = (byte)((modRM & 0x38) >> 3);
byte rm = (byte)(modRM & 0x07);
// Set the mnemonic
instruction.Mnemonic = "add";
// Get the register name
string regName = GetRegister32(reg);
// For memory operands, set the operand
if (mod != 3) // Memory operand
{
string operand = ModRMDecoder.DecodeModRM(mod, rm, false);
instruction.Operands = $"{operand}, {regName}";
}
else // Register operand
{
string rmName = GetRegister32(rm);
instruction.Operands = $"{rmName}, {regName}";
}
return true;
}
}

View File

@ -266,6 +266,7 @@ public class InstructionHandlerFactory
{ {
// Add Add handlers // Add Add handlers
_handlers.Add(new AddR32Rm32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new AddR32Rm32Handler(_codeBuffer, _decoder, _length));
_handlers.Add(new AddRm32R32Handler(_codeBuffer, _decoder, _length));
} }
/// <summary> /// <summary>
@ -290,6 +291,7 @@ public class InstructionHandlerFactory
_handlers.Add(new MovEaxMoffsHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new MovEaxMoffsHandler(_codeBuffer, _decoder, _length));
_handlers.Add(new MovMoffsEaxHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new MovMoffsEaxHandler(_codeBuffer, _decoder, _length));
_handlers.Add(new MovRm32Imm32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new MovRm32Imm32Handler(_codeBuffer, _decoder, _length));
_handlers.Add(new MovRm8Imm8Handler(_codeBuffer, _decoder, _length));
// Add PUSH handlers // Add PUSH handlers
_handlers.Add(new PushRegHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new PushRegHandler(_codeBuffer, _decoder, _length));

View File

@ -0,0 +1,125 @@
namespace X86Disassembler.X86.Handlers.Mov;
/// <summary>
/// Handler for MOV r/m8, imm8 instruction (0xC6)
/// </summary>
public class MovRm8Imm8Handler : InstructionHandler
{
/// <summary>
/// Initializes a new instance of the MovRm8Imm8Handler class
/// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param>
public MovRm8Imm8Handler(byte[] codeBuffer, InstructionDecoder decoder, int length)
: base(codeBuffer, decoder, length)
{
}
/// <summary>
/// Checks if this handler can decode the given opcode
/// </summary>
/// <param name="opcode">The opcode to check</param>
/// <returns>True if this handler can decode the opcode</returns>
public override bool CanHandle(byte opcode)
{
return opcode == 0xC6;
}
/// <summary>
/// Decodes a MOV r/m8, imm8 instruction
/// </summary>
/// <param name="opcode">The opcode of the instruction</param>
/// <param name="instruction">The instruction object to populate</param>
/// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction)
{
int position = Decoder.GetPosition();
if (position >= Length)
{
return false;
}
// Read the ModR/M byte
byte modRM = CodeBuffer[position++];
// Extract the fields from the ModR/M byte
byte mod = (byte)((modRM & 0xC0) >> 6);
byte reg = (byte)((modRM & 0x38) >> 3);
byte rm = (byte)(modRM & 0x07);
// MOV r/m8, imm8 only uses reg=0
if (reg != 0)
{
return false;
}
// Process SIB and displacement bytes if needed
if (mod != 3 && rm == 4) // SIB byte present
{
if (position >= Length)
{
return false;
}
position++; // Skip SIB byte
}
// Handle displacement
if ((mod == 1 && position >= Length) || (mod == 2 && position + 3 >= Length))
{
return false;
}
if (mod == 1) // 8-bit displacement
{
position++;
}
else if (mod == 2) // 32-bit displacement
{
position += 4;
}
// Read the immediate byte
if (position >= Length)
{
return false;
}
byte imm8 = CodeBuffer[position++];
Decoder.SetPosition(position);
// Set the mnemonic
instruction.Mnemonic = "mov";
// Get the operand string
string operand;
if (mod != 3) // Memory operand
{
string memOperand = ModRMDecoder.DecodeModRM(mod, rm, true);
// Replace the size prefix with "byte ptr"
if (memOperand.StartsWith("qword ptr "))
{
operand = memOperand.Replace("qword ptr ", "byte ptr ");
}
else if (memOperand.StartsWith("dword ptr "))
{
operand = memOperand.Replace("dword ptr ", "byte ptr ");
}
else
{
operand = $"byte ptr {memOperand}";
}
}
else // Register operand
{
operand = GetRegister8(rm);
}
// Set the operands
instruction.Operands = $"{operand}, 0x{imm8:X2}";
return true;
}
}

View File

@ -0,0 +1,49 @@
namespace X86DisassemblerTests;
using System;
using Xunit;
using X86Disassembler.X86;
/// <summary>
/// Tests for ADD r/m32, r32 instruction (0x01)
/// </summary>
public class AddRm32R32Tests
{
/// <summary>
/// Tests the ADD r32, r32 instruction (0x01) with register operand
/// </summary>
[Fact]
public void TestAddR32R32()
{
// Arrange
byte[] code = { 0x01, 0xC1 }; // ADD ECX, EAX
// Act
Disassembler disassembler = new Disassembler(code, 0x1000);
var instructions = disassembler.Disassemble();
// Assert
Assert.Single(instructions);
Assert.Equal("add", instructions[0].Mnemonic);
Assert.Equal("ecx, eax", instructions[0].Operands);
}
/// <summary>
/// Tests the ADD m32, r32 instruction (0x01) with memory operand
/// </summary>
[Fact]
public void TestAddM32R32()
{
// Arrange
byte[] code = { 0x01, 0x01 }; // ADD DWORD PTR [ECX], EAX
// Act
Disassembler disassembler = new Disassembler(code, 0x1000);
var instructions = disassembler.Disassemble();
// Assert
Assert.Single(instructions);
Assert.Equal("add", instructions[0].Mnemonic);
Assert.Equal("dword ptr [ecx], eax", instructions[0].Operands);
}
}

View File

@ -0,0 +1,49 @@
namespace X86DisassemblerTests;
using System;
using Xunit;
using X86Disassembler.X86;
/// <summary>
/// Tests for MOV r/m8, imm8 instruction (0xC6)
/// </summary>
public class MovRm8Imm8Tests
{
/// <summary>
/// Tests the MOV r8, imm8 instruction (0xC6) with register operand
/// </summary>
[Fact]
public void TestMovR8Imm8()
{
// Arrange
byte[] code = { 0xC6, 0xC0, 0x42 }; // MOV AL, 0x42
// Act
Disassembler disassembler = new Disassembler(code, 0x1000);
var instructions = disassembler.Disassemble();
// Assert
Assert.Single(instructions);
Assert.Equal("mov", instructions[0].Mnemonic);
Assert.Equal("al, 0x42", instructions[0].Operands);
}
/// <summary>
/// Tests the MOV m8, imm8 instruction (0xC6) with memory operand
/// </summary>
[Fact]
public void TestMovM8Imm8()
{
// Arrange
byte[] code = { 0xC6, 0x01, 0x01 }; // MOV BYTE PTR [ECX], 0x01
// Act
Disassembler disassembler = new Disassembler(code, 0x1000);
var instructions = disassembler.Disassemble();
// Assert
Assert.Single(instructions);
Assert.Equal("mov", instructions[0].Mnemonic);
Assert.Equal("byte ptr [ecx], 0x01", instructions[0].Operands);
}
}