diff --git a/X86Disassembler/X86/Handlers/Group3/TestImmWithRm8Handler.cs b/X86Disassembler/X86/Handlers/Group3/TestImmWithRm8Handler.cs
new file mode 100644
index 0000000..e46a025
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Group3/TestImmWithRm8Handler.cs
@@ -0,0 +1,107 @@
+namespace X86Disassembler.X86.Handlers.Group3;
+
+///
+/// Handler for TEST r/m8, imm8 instruction (0xF6 /0)
+///
+public class TestImmWithRm8Handler : Group3BaseHandler
+{
+ ///
+ /// Initializes a new instance of the TestImmWithRm8Handler class
+ ///
+ /// The buffer containing the code to decode
+ /// The instruction decoder that owns this handler
+ /// The length of the buffer
+ public TestImmWithRm8Handler(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)
+ {
+ if (opcode != 0xF6)
+ return false;
+
+ // Check if the reg field of the ModR/M byte is 0 (TEST)
+ int position = Decoder.GetPosition();
+ if (position >= Length)
+ return false;
+
+ byte modRM = CodeBuffer[position];
+ byte reg = (byte)((modRM & 0x38) >> 3);
+
+ return reg == 0; // 0 = TEST
+ }
+
+ ///
+ /// Decodes a TEST r/m8, imm8 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 = "test";
+
+ 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); // Should be 0 for TEST
+ byte rm = (byte)(modRM & 0x07);
+
+ // Decode the destination operand
+ string destOperand;
+
+ // Special case for direct register addressing (mod == 3)
+ if (mod == 3)
+ {
+ // Get the register name based on the rm field
+ destOperand = GetRegister8(rm);
+ }
+ else
+ {
+ // Use the ModR/M decoder for memory addressing
+ destOperand = _modRMDecoder.DecodeModRM(mod, rm, true);
+ }
+
+ // Read the immediate value
+ if (position >= Length)
+ {
+ return false;
+ }
+
+ byte imm8 = CodeBuffer[position];
+ Decoder.SetPosition(position + 1);
+
+ // Set the operands
+ instruction.Operands = $"{destOperand}, 0x{imm8:X2}";
+
+ return true;
+ }
+
+ ///
+ /// Gets the 8-bit register name for the given register index
+ ///
+ /// The register index
+ /// The register name
+ private static new string GetRegister8(byte reg)
+ {
+ string[] registerNames = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" };
+ return registerNames[reg & 0x07];
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs b/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs
index 3a22e8c..43f3dcb 100644
--- a/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs
+++ b/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs
@@ -41,6 +41,7 @@ public class InstructionHandlerFactory
_handlers.Add(new JmpRel8Handler(_codeBuffer, _decoder, _length));
_handlers.Add(new CallRel32Handler(_codeBuffer, _decoder, _length));
_handlers.Add(new XorRegMemHandler(_codeBuffer, _decoder, _length));
+ _handlers.Add(new TestRegMem8Handler(_codeBuffer, _decoder, _length));
_handlers.Add(new TestRegMemHandler(_codeBuffer, _decoder, _length));
_handlers.Add(new TestAlImmHandler(_codeBuffer, _decoder, _length));
_handlers.Add(new TestEaxImmHandler(_codeBuffer, _decoder, _length));
@@ -104,8 +105,9 @@ public class InstructionHandlerFactory
///
private void RegisterGroup3Handlers()
{
- // TEST handler
+ // TEST handlers
_handlers.Add(new TestImmWithRm32Handler(_codeBuffer, _decoder, _length));
+ _handlers.Add(new TestImmWithRm8Handler(_codeBuffer, _decoder, _length));
// NOT handler
_handlers.Add(new NotRm32Handler(_codeBuffer, _decoder, _length));
diff --git a/X86Disassembler/X86/Handlers/TestRegMem8Handler.cs b/X86Disassembler/X86/Handlers/TestRegMem8Handler.cs
new file mode 100644
index 0000000..1f72c32
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/TestRegMem8Handler.cs
@@ -0,0 +1,82 @@
+namespace X86Disassembler.X86.Handlers;
+
+///
+/// Handler for TEST r/m8, r8 instruction (0x84)
+///
+public class TestRegMem8Handler : InstructionHandler
+{
+ // ModR/M decoder
+ private readonly ModRMDecoder _modRMDecoder;
+
+ ///
+ /// Initializes a new instance of the TestRegMem8Handler class
+ ///
+ /// The buffer containing the code to decode
+ /// The instruction decoder that owns this handler
+ /// The length of the buffer
+ public TestRegMem8Handler(byte[] codeBuffer, InstructionDecoder decoder, int length)
+ : base(codeBuffer, decoder, length)
+ {
+ _modRMDecoder = new ModRMDecoder(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 == 0x84;
+ }
+
+ ///
+ /// Decodes a TEST r/m8, r8 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 = "test";
+
+ 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);
+
+ // Decode the destination operand
+ string destOperand = _modRMDecoder.DecodeModRM(mod, rm, true);
+
+ // Get the source register
+ string srcReg = GetRegister8(reg);
+
+ // Set the operands
+ instruction.Operands = $"{destOperand}, {srcReg}";
+
+ return true;
+ }
+
+ ///
+ /// Gets the 8-bit register name for the given register index
+ ///
+ /// The register index
+ /// The register name
+ private static string GetRegister8(byte reg)
+ {
+ string[] registerNames = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" };
+ return registerNames[reg & 0x07];
+ }
+}