diff --git a/X86Disassembler/X86/Handlers/Cmp/CmpRm32R32Handler.cs b/X86Disassembler/X86/Handlers/Cmp/CmpRm32R32Handler.cs
new file mode 100644
index 0000000..c07c61c
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Cmp/CmpRm32R32Handler.cs
@@ -0,0 +1,179 @@
+namespace X86Disassembler.X86.Handlers.Cmp;
+
+///
+/// Handler for CMP r/m32, r32 instruction (0x39)
+///
+public class CmpRm32R32Handler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the CmpRm32R32Handler class
+ ///
+ /// The buffer containing the code to decode
+ /// The instruction decoder that owns this handler
+ /// The length of the buffer
+ public CmpRm32R32Handler(byte[] codeBuffer, InstructionDecoder decoder, int length)
+ : base(codeBuffer, decoder, length)
+ {
+ }
+
+ ///
+ /// Checks if this handler can decode the given opcode
+ ///
+ /// The opcode to check
+ /// True if this handler can decode the opcode
+ public override bool CanHandle(byte opcode)
+ {
+ return opcode == 0x39;
+ }
+
+ ///
+ /// Decodes a CMP r/m32, r32 instruction
+ ///
+ /// The opcode of the instruction
+ /// The instruction object to populate
+ /// True if the instruction was successfully decoded
+ public override bool Decode(byte opcode, Instruction instruction)
+ {
+ // Set the mnemonic
+ instruction.Mnemonic = "cmp";
+
+ 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); // Top 2 bits
+ byte reg = (byte)((modRM & 0x38) >> 3); // Middle 3 bits
+ byte rm = (byte)(modRM & 0x07); // Bottom 3 bits
+
+ // Get the register name for the reg field
+ string regName = GetRegisterName(reg);
+
+ // Handle the different addressing modes
+ string rmOperand;
+
+ if (mod == 3) // Direct register addressing
+ {
+ // Get the register name for the r/m field
+ rmOperand = GetRegisterName(rm);
+ }
+ else // Memory addressing
+ {
+ // Handle SIB byte if needed
+ if (mod != 3 && rm == 4) // SIB byte present
+ {
+ if (position >= Length)
+ {
+ return false;
+ }
+
+ byte sib = CodeBuffer[position++];
+
+ // Extract the fields from the SIB byte
+ byte scale = (byte)((sib & 0xC0) >> 6);
+ byte index = (byte)((sib & 0x38) >> 3);
+ byte base_ = (byte)(sib & 0x07);
+
+ // TODO: Handle SIB byte properly
+ rmOperand = $"[complex addressing]";
+ }
+ else if (mod == 0 && rm == 5) // Displacement only addressing
+ {
+ if (position + 3 >= Length)
+ {
+ return false;
+ }
+
+ // Read the 32-bit displacement
+ uint disp = (uint)(CodeBuffer[position] |
+ (CodeBuffer[position + 1] << 8) |
+ (CodeBuffer[position + 2] << 16) |
+ (CodeBuffer[position + 3] << 24));
+ position += 4;
+
+ rmOperand = $"[0x{disp:X8}]";
+ }
+ else // Simple addressing modes
+ {
+ string baseReg = GetRegisterName(rm);
+
+ if (mod == 0) // No displacement
+ {
+ rmOperand = $"[{baseReg}]";
+ }
+ else // Displacement
+ {
+ uint disp;
+
+ if (mod == 1) // 8-bit displacement
+ {
+ if (position >= Length)
+ {
+ return false;
+ }
+
+ // Sign-extend the 8-bit displacement
+ sbyte dispByte = (sbyte)CodeBuffer[position++];
+ disp = (uint)(int)dispByte;
+
+ // Format the displacement
+ string dispStr = dispByte < 0 ? $"-0x{-dispByte:X2}" : $"0x{dispByte:X2}";
+ rmOperand = $"[{baseReg}+{dispStr}]";
+ }
+ else // 32-bit displacement
+ {
+ if (position + 3 >= Length)
+ {
+ return false;
+ }
+
+ // Read the 32-bit displacement
+ disp = (uint)(CodeBuffer[position] |
+ (CodeBuffer[position + 1] << 8) |
+ (CodeBuffer[position + 2] << 16) |
+ (CodeBuffer[position + 3] << 24));
+ position += 4;
+
+ rmOperand = $"[{baseReg}+0x{disp:X8}]";
+ }
+ }
+ }
+ }
+
+ // Update the decoder position
+ Decoder.SetPosition(position);
+
+ // Set the operands
+ instruction.Operands = $"{rmOperand}, {regName}";
+
+ return true;
+ }
+
+ ///
+ /// Gets the register name for a register number
+ ///
+ /// The register number
+ /// The register name
+ private string GetRegisterName(byte regNum)
+ {
+ // 32-bit registers
+ switch (regNum)
+ {
+ case 0: return "eax";
+ case 1: return "ecx";
+ case 2: return "edx";
+ case 3: return "ebx";
+ case 4: return "esp";
+ case 5: return "ebp";
+ case 6: return "esi";
+ case 7: return "edi";
+ default: return "??";
+ }
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs b/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs
index 6f00136..24f9245 100644
--- a/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs
+++ b/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs
@@ -209,6 +209,7 @@ public class InstructionHandlerFactory
{
// Add Cmp handlers
_handlers.Add(new CmpR32Rm32Handler(_codeBuffer, _decoder, _length));
+ _handlers.Add(new CmpRm32R32Handler(_codeBuffer, _decoder, _length));
_handlers.Add(new CmpImmWithRm8Handler(_codeBuffer, _decoder, _length));
_handlers.Add(new CmpAlImmHandler(_codeBuffer, _decoder, _length));
diff --git a/X86DisassemblerTests/CmpInstructionHandlerTests.cs b/X86DisassemblerTests/CmpInstructionHandlerTests.cs
index f95e660..a4ecb84 100644
--- a/X86DisassemblerTests/CmpInstructionHandlerTests.cs
+++ b/X86DisassemblerTests/CmpInstructionHandlerTests.cs
@@ -51,4 +51,46 @@ public class CmpInstructionHandlerTests
Assert.Equal("cmp", instruction.Mnemonic);
Assert.Equal("al, 0xFF", instruction.Operands);
}
+
+ ///
+ /// Tests the CmpRm32R32Handler for decoding CMP r/m32, r32 instructions with register operands
+ ///
+ [Fact]
+ public void CmpRm32R32Handler_DecodesCmpRm32R32_WithRegisterOperands()
+ {
+ // Arrange
+ // CMP ECX, EAX (39 C1) - ModR/M byte C1 = 11 000 001 (mod=3, reg=0, rm=1)
+ // mod=3 means direct register addressing, reg=0 is EAX, rm=1 is ECX
+ byte[] codeBuffer = new byte[] { 0x39, 0xC1 };
+ var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length);
+
+ // Act
+ var instruction = decoder.DecodeInstruction();
+
+ // Assert
+ Assert.NotNull(instruction);
+ Assert.Equal("cmp", instruction.Mnemonic);
+ Assert.Equal("ecx, eax", instruction.Operands);
+ }
+
+ ///
+ /// Tests the CmpRm32R32Handler for decoding CMP r/m32, r32 instructions with memory operands
+ ///
+ [Fact]
+ public void CmpRm32R32Handler_DecodesCmpRm32R32_WithMemoryOperands()
+ {
+ // Arrange
+ // CMP [EBX+0x10], EDX (39 53 10) - ModR/M byte 53 = 01 010 011 (mod=1, reg=2, rm=3)
+ // mod=1 means memory addressing with 8-bit displacement, reg=2 is EDX, rm=3 is EBX
+ byte[] codeBuffer = new byte[] { 0x39, 0x53, 0x10 };
+ var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length);
+
+ // Act
+ var instruction = decoder.DecodeInstruction();
+
+ // Assert
+ Assert.NotNull(instruction);
+ Assert.Equal("cmp", instruction.Mnemonic);
+ Assert.Equal("[ebx+0x10], edx", instruction.Operands);
+ }
}