From 7c0e6d7f3aa55c0f918c998a74ff190181d1cd9b Mon Sep 17 00:00:00 2001 From: bird_egop Date: Thu, 17 Apr 2025 18:39:34 +0300 Subject: [PATCH] Added 16-bit register-to-register ADD handlers for r16, r/m16 and r/m16, r16 instructions --- .../X86/Handlers/Add/AddR16Rm16Handler.cs | 72 +++++++++++++++++++ .../X86/Handlers/Add/AddRm16R16Handler.cs | 72 +++++++++++++++++++ .../X86/Handlers/InstructionHandlerFactory.cs | 4 ++ X86DisassemblerTests/TestData/add_tests.csv | 6 +- 4 files changed, 151 insertions(+), 3 deletions(-) create mode 100644 X86Disassembler/X86/Handlers/Add/AddR16Rm16Handler.cs create mode 100644 X86Disassembler/X86/Handlers/Add/AddRm16R16Handler.cs diff --git a/X86Disassembler/X86/Handlers/Add/AddR16Rm16Handler.cs b/X86Disassembler/X86/Handlers/Add/AddR16Rm16Handler.cs new file mode 100644 index 0000000..a96cafc --- /dev/null +++ b/X86Disassembler/X86/Handlers/Add/AddR16Rm16Handler.cs @@ -0,0 +1,72 @@ +using X86Disassembler.X86.Operands; + +namespace X86Disassembler.X86.Handlers.Add; + +/// +/// Handler for ADD r16, r/m16 instruction (opcode 03 with 0x66 prefix) +/// +public class AddR16Rm16Handler : InstructionHandler +{ + /// + /// Initializes a new instance of the AddR16Rm16Handler class + /// + /// The instruction decoder that owns this handler + public AddR16Rm16Handler(InstructionDecoder decoder) + : base(decoder) + { + } + + /// + /// 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) + { + // ADD r16, r/m16 is encoded as 0x03 with 0x66 prefix + if (opcode != 0x03) + { + return false; + } + + // Only handle when the operand size prefix is present + return Decoder.HasOperandSizePrefix(); + } + + /// + /// Decodes an ADD r16, r/m16 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 instruction type + instruction.Type = InstructionType.Add; + + // Check if we can read the ModR/M byte + if (!Decoder.CanReadByte()) + { + return false; + } + + // For ADD r16, r/m16 (0x03 with 0x66 prefix): + // - The reg field of the ModR/M byte specifies the destination register + // - The r/m field with mod specifies the source operand (register or memory) + var (_, reg, _, sourceOperand) = ModRMDecoder.ReadModRM16(); + + // Note: The operand size is already set to 16-bit by the ReadModRM16 method + + // Create the destination register operand with 16-bit size + var destinationOperand = OperandFactory.CreateRegisterOperand(reg, 16); + + // Set the structured operands + instruction.StructuredOperands = + [ + destinationOperand, + sourceOperand + ]; + + return true; + } +} diff --git a/X86Disassembler/X86/Handlers/Add/AddRm16R16Handler.cs b/X86Disassembler/X86/Handlers/Add/AddRm16R16Handler.cs new file mode 100644 index 0000000..670f9b4 --- /dev/null +++ b/X86Disassembler/X86/Handlers/Add/AddRm16R16Handler.cs @@ -0,0 +1,72 @@ +using X86Disassembler.X86.Operands; + +namespace X86Disassembler.X86.Handlers.Add; + +/// +/// Handler for ADD r/m16, r16 instruction (opcode 01 with 0x66 prefix) +/// +public class AddRm16R16Handler : InstructionHandler +{ + /// + /// Initializes a new instance of the AddRm16R16Handler class + /// + /// The instruction decoder that owns this handler + public AddRm16R16Handler(InstructionDecoder decoder) + : base(decoder) + { + } + + /// + /// 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) + { + // ADD r/m16, r16 is encoded as 0x01 with 0x66 prefix + if (opcode != 0x01) + { + return false; + } + + // Only handle when the operand size prefix is present + return Decoder.HasOperandSizePrefix(); + } + + /// + /// Decodes an ADD r/m16, r16 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 instruction type + instruction.Type = InstructionType.Add; + + // Check if we can read the ModR/M byte + if (!Decoder.CanReadByte()) + { + return false; + } + + // For ADD r/m16, r16 (0x01 with 0x66 prefix): + // - The reg field of the ModR/M byte specifies the source register + // - The r/m field with mod specifies the destination operand (register or memory) + var (_, reg, _, destinationOperand) = ModRMDecoder.ReadModRM16(); + + // Note: The operand size is already set to 16-bit by the ReadModRM16 method + + // Create the source register operand with 16-bit size + var sourceOperand = OperandFactory.CreateRegisterOperand(reg, 16); + + // Set the structured operands + instruction.StructuredOperands = + [ + destinationOperand, + sourceOperand + ]; + + return true; + } +} diff --git a/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs b/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs index d749d48..0c42183 100644 --- a/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs +++ b/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs @@ -297,6 +297,10 @@ public class InstructionHandlerFactory _handlers.Add(new AddRm32R32Handler(_decoder)); // ADD r/m32, r32 (opcode 01) _handlers.Add(new AddEaxImmHandler(_decoder)); // ADD EAX, imm32 (opcode 05) + // Add ADD register-to-register handlers (16-bit) + _handlers.Add(new AddR16Rm16Handler(_decoder)); // ADD r16, r/m16 (opcode 03 with 0x66 prefix) + _handlers.Add(new AddRm16R16Handler(_decoder)); // ADD r/m16, r16 (opcode 01 with 0x66 prefix) + // Add ADD register-to-register handlers (8-bit) _handlers.Add(new AddRm8R8Handler(_decoder)); // ADD r/m8, r8 (opcode 00) _handlers.Add(new AddR8Rm8Handler(_decoder)); // ADD r8, r/m8 (opcode 02) diff --git a/X86DisassemblerTests/TestData/add_tests.csv b/X86DisassemblerTests/TestData/add_tests.csv index 0e505b8..c5a21bc 100644 --- a/X86DisassemblerTests/TestData/add_tests.csv +++ b/X86DisassemblerTests/TestData/add_tests.csv @@ -31,6 +31,6 @@ RawBytes;Instructions 810488AA000000;[{ "Type": "Add", "Operands": ["dword ptr [eax+ecx*4]", "0xAA"] }] # Mixed addressing modes -00A314285600;[{ "Type": "Add", "Operands": ["byte ptr [ebx+0x562814]", "ah"] }] -6601B310203040;[{ "Type": "Add", "Operands": ["si", "word ptr [ebx+0x40302010]"] }] -030C8D10203040;[{ "Type": "Add", "Operands": ["ecx", "dword ptr [ebp*4+0x40302010]"] }] \ No newline at end of file +00A314285600;[{ "Type": "Add", "Operands": ["byte ptr [ebx+0x00562814]", "ah"] }] +6601B310203040;[{ "Type": "Add", "Operands": ["word ptr [ebx+0x40302010]", "si"] }] +030C8D10203040;[{ "Type": "Add", "Operands": ["ecx", "dword ptr [ecx*4+0x40302010]"] }] \ No newline at end of file