From 618ee641a8e37ea195d923a07e011e7775dcefcf Mon Sep 17 00:00:00 2001 From: bird_egop Date: Sun, 13 Apr 2025 02:35:48 +0300 Subject: [PATCH] Added OrRm8R8Handler for decoding OR r/m8, r8 instruction (opcode 0x08) --- .../X86/Handlers/InstructionHandlerFactory.cs | 1 + .../X86/Handlers/Or/OrRm8R8Handler.cs | 85 +++++++++++++++++++ X86DisassemblerTests/OrRm8R8HandlerTests.cs | 72 ++++++++++++++++ 3 files changed, 158 insertions(+) create mode 100644 X86Disassembler/X86/Handlers/Or/OrRm8R8Handler.cs create mode 100644 X86DisassemblerTests/OrRm8R8HandlerTests.cs diff --git a/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs b/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs index 0424ca2..6f59e44 100644 --- a/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs +++ b/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs @@ -193,6 +193,7 @@ public class InstructionHandlerFactory _handlers.Add(new OrImmToRm32SignExtendedHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new OrR8Rm8Handler(_codeBuffer, _decoder, _length)); + _handlers.Add(new OrRm8R8Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new OrR32Rm32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new OrAlImmHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new OrEaxImmHandler(_codeBuffer, _decoder, _length)); diff --git a/X86Disassembler/X86/Handlers/Or/OrRm8R8Handler.cs b/X86Disassembler/X86/Handlers/Or/OrRm8R8Handler.cs new file mode 100644 index 0000000..a123045 --- /dev/null +++ b/X86Disassembler/X86/Handlers/Or/OrRm8R8Handler.cs @@ -0,0 +1,85 @@ +namespace X86Disassembler.X86.Handlers.Or; + +/// +/// Handler for OR r/m8, r8 instruction (0x08) +/// +public class OrRm8R8Handler : InstructionHandler +{ + // 8-bit register names + private static readonly string[] RegisterNames8 = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" }; + + /// + /// Initializes a new instance of the OrRm8R8Handler class + /// + /// The buffer containing the code to decode + /// The instruction decoder that owns this handler + /// The length of the buffer + public OrRm8R8Handler(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 == 0x08; + } + + /// + /// Decodes an OR 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 = "or"; + + // Read the ModR/M byte + int position = Decoder.GetPosition(); + if (position >= Length) + { + instruction.Operands = "??"; + return true; + } + + byte modRM = CodeBuffer[position++]; + Decoder.SetPosition(position); + + // Extract fields from 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 + + // The register operand is in the reg field (8-bit register) + string regOperand = RegisterNames8[reg]; + + // Handle the r/m operand based on mod field + string rmOperand; + + if (mod == 3) // Register-to-register + { + // Direct register addressing + rmOperand = RegisterNames8[rm]; + } + else // Memory addressing + { + // Use ModRMDecoder for memory addressing, but we need to adjust for 8-bit operands + var modRMDecoder = new ModRMDecoder(CodeBuffer, Decoder, Length); + string memOperand = modRMDecoder.DecodeModRM(mod, rm, false); // false = not 64-bit + + // Replace "dword ptr" with "byte ptr" for 8-bit operands + rmOperand = memOperand.Replace("dword ptr", "byte ptr"); + } + + // Set the operands (r/m8, r8 format) + instruction.Operands = $"{rmOperand}, {regOperand}"; + + return true; + } +} diff --git a/X86DisassemblerTests/OrRm8R8HandlerTests.cs b/X86DisassemblerTests/OrRm8R8HandlerTests.cs new file mode 100644 index 0000000..297d996 --- /dev/null +++ b/X86DisassemblerTests/OrRm8R8HandlerTests.cs @@ -0,0 +1,72 @@ +namespace X86DisassemblerTests; + +using System; +using Xunit; +using X86Disassembler.X86; +using X86Disassembler.X86.Handlers.Or; + +/// +/// Tests for OR r/m8, r8 instruction handler +/// +public class OrRm8R8HandlerTests +{ + /// + /// Tests the OrRm8R8Handler for decoding OR [mem], reg8 instruction + /// + [Fact] + public void OrRm8R8Handler_DecodesOrMemReg8_Correctly() + { + // Arrange + // OR [ebx+ecx*4+0x41], al (08 44 8B 41) + byte[] codeBuffer = new byte[] { 0x08, 0x44, 0x8B, 0x41 }; + var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length); + + // Act + var instruction = decoder.DecodeInstruction(); + + // Assert + Assert.NotNull(instruction); + Assert.Equal("or", instruction.Mnemonic); + Assert.Equal("byte ptr [ebx+ecx*4+0x41], al", instruction.Operands); + } + + /// + /// Tests the OrRm8R8Handler for decoding OR reg8, reg8 instruction + /// + [Fact] + public void OrRm8R8Handler_DecodesOrRegReg8_Correctly() + { + // Arrange + // OR bl, ch (08 EB) + byte[] codeBuffer = new byte[] { 0x08, 0xEB }; + var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length); + + // Act + var instruction = decoder.DecodeInstruction(); + + // Assert + Assert.NotNull(instruction); + Assert.Equal("or", instruction.Mnemonic); + Assert.Equal("bl, ch", instruction.Operands); + } + + /// + /// Tests the OrRm8R8Handler for handling insufficient bytes + /// + [Fact] + public void OrRm8R8Handler_HandlesInsufficientBytes_Gracefully() + { + // Arrange + // OR ?? (08) - missing ModR/M byte + byte[] codeBuffer = new byte[] { 0x08 }; + var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length); + + // Act + var instruction = decoder.DecodeInstruction(); + + // Assert + Assert.NotNull(instruction); + Assert.Equal("or", instruction.Mnemonic); + Assert.Equal("??", instruction.Operands); + } +}