From 800915b534a9e489ab5776579b590697d21b1d89 Mon Sep 17 00:00:00 2001 From: bird_egop Date: Wed, 16 Apr 2025 20:54:08 +0300 Subject: [PATCH] new handlers and test fixes --- .../DivRm32Handler.cs | 4 +- .../DivRm8Handler.cs} | 34 ++++----- .../IdivRm32Handler.cs | 13 +--- .../X86/Handlers/Idiv/IdivRm8Handler.cs | 68 ++++++++++++++++++ .../ImulRm32Handler.cs | 13 +--- .../X86/Handlers/Imul/ImulRm8Handler.cs | 68 ++++++++++++++++++ .../X86/Handlers/InstructionHandlerFactory.cs | 71 +++++++++++++++---- .../X86/Handlers/Mov/MovRegImm32Handler.cs | 4 +- .../X86/Handlers/Mov/MovRegImm8Handler.cs | 4 +- .../X86/Handlers/Mov/MovRm32Imm32Handler.cs | 27 ++++--- .../X86/Handlers/Mov/MovRm8Imm8Handler.cs | 28 +++++--- .../X86/Handlers/Mul/MulRm32Handler.cs | 9 +-- .../X86/Handlers/Mul/MulRm8Handler.cs | 9 +-- .../NegRm32Handler.cs | 13 +--- .../{ArithmeticUnary => Neg}/NegRm8Handler.cs | 7 +- .../NotRm32Handler.cs | 11 +-- .../X86/Handlers/Not/NotRm8Handler.cs | 69 ++++++++++++++++++ X86Disassembler/X86/SIBDecoder.cs | 3 +- X86DisassemblerTests/TestData/lea_tests.csv | 2 +- X86DisassemblerTests/TestData/neg_tests.csv | 2 +- 20 files changed, 342 insertions(+), 117 deletions(-) rename X86Disassembler/X86/Handlers/{ArithmeticUnary => Div}/DivRm32Handler.cs (97%) rename X86Disassembler/X86/Handlers/{ArithmeticUnary/MulRm32Handler.cs => Div/DivRm8Handler.cs} (64%) rename X86Disassembler/X86/Handlers/{ArithmeticUnary => Idiv}/IdivRm32Handler.cs (86%) create mode 100644 X86Disassembler/X86/Handlers/Idiv/IdivRm8Handler.cs rename X86Disassembler/X86/Handlers/{ArithmeticUnary => Imul}/ImulRm32Handler.cs (84%) create mode 100644 X86Disassembler/X86/Handlers/Imul/ImulRm8Handler.cs rename X86Disassembler/X86/Handlers/{ArithmeticUnary => Neg}/NegRm32Handler.cs (84%) rename X86Disassembler/X86/Handlers/{ArithmeticUnary => Neg}/NegRm8Handler.cs (86%) rename X86Disassembler/X86/Handlers/{ArithmeticUnary => Not}/NotRm32Handler.cs (87%) create mode 100644 X86Disassembler/X86/Handlers/Not/NotRm8Handler.cs diff --git a/X86Disassembler/X86/Handlers/ArithmeticUnary/DivRm32Handler.cs b/X86Disassembler/X86/Handlers/Div/DivRm32Handler.cs similarity index 97% rename from X86Disassembler/X86/Handlers/ArithmeticUnary/DivRm32Handler.cs rename to X86Disassembler/X86/Handlers/Div/DivRm32Handler.cs index 06e91dc..1440e30 100644 --- a/X86Disassembler/X86/Handlers/ArithmeticUnary/DivRm32Handler.cs +++ b/X86Disassembler/X86/Handlers/Div/DivRm32Handler.cs @@ -1,6 +1,6 @@ using X86Disassembler.X86.Operands; -namespace X86Disassembler.X86.Handlers.ArithmeticUnary; +namespace X86Disassembler.X86.Handlers.Div; /// /// Handler for DIV r/m32 instruction (0xF7 /6) @@ -72,4 +72,4 @@ public class DivRm32Handler : InstructionHandler return true; } -} \ No newline at end of file +} diff --git a/X86Disassembler/X86/Handlers/ArithmeticUnary/MulRm32Handler.cs b/X86Disassembler/X86/Handlers/Div/DivRm8Handler.cs similarity index 64% rename from X86Disassembler/X86/Handlers/ArithmeticUnary/MulRm32Handler.cs rename to X86Disassembler/X86/Handlers/Div/DivRm8Handler.cs index 4e147a4..63ab97b 100644 --- a/X86Disassembler/X86/Handlers/ArithmeticUnary/MulRm32Handler.cs +++ b/X86Disassembler/X86/Handlers/Div/DivRm8Handler.cs @@ -1,17 +1,17 @@ using X86Disassembler.X86.Operands; -namespace X86Disassembler.X86.Handlers.ArithmeticUnary; +namespace X86Disassembler.X86.Handlers.Div; /// -/// Handler for MUL r/m32 instruction (0xF7 /4) +/// Handler for DIV r/m8 instruction (0xF6 /6) /// -public class MulRm32Handler : InstructionHandler +public class DivRm8Handler : InstructionHandler { /// - /// Initializes a new instance of the MulRm32Handler class + /// Initializes a new instance of the DivRm8Handler class /// /// The instruction decoder that owns this handler - public MulRm32Handler(InstructionDecoder decoder) + public DivRm8Handler(InstructionDecoder decoder) : base(decoder) { } @@ -23,20 +23,20 @@ public class MulRm32Handler : InstructionHandler /// True if this handler can decode the opcode public override bool CanHandle(byte opcode) { - if (opcode != 0xF7) + if (opcode != 0xF6) return false; - // Check if the reg field of the ModR/M byte is 4 (MUL) + // Check if the reg field of the ModR/M byte is 6 (DIV) if (!Decoder.CanReadByte()) return false; var reg = ModRMDecoder.PeakModRMReg(); - return reg == 4; // 4 = MUL + return reg == 6; // 6 = DIV } /// - /// Decodes a MUL r/m32 instruction + /// Decodes a DIV r/m8 instruction /// /// The opcode of the instruction /// The instruction object to populate @@ -44,7 +44,7 @@ public class MulRm32Handler : InstructionHandler public override bool Decode(byte opcode, Instruction instruction) { // Set the instruction type - instruction.Type = InstructionType.Mul; + instruction.Type = InstructionType.Div; if (!Decoder.CanReadByte()) { @@ -52,19 +52,19 @@ public class MulRm32Handler : InstructionHandler } // Read the ModR/M byte - // For MUL r/m32 (0xF7 /4): + // For DIV r/m8 (0xF6 /6): // - The r/m field with mod specifies the operand (register or memory) - var (_, reg, _, operand) = ModRMDecoder.ReadModRM(); + var (_, reg, _, operand) = ModRMDecoder.ReadModRM8(); - // Verify this is a MUL instruction - // The reg field should be 4 (MUL), which maps to RegisterIndex.Sp in our enum - if (reg != RegisterIndex.Sp) + // Verify this is a DIV instruction + // The reg field should be 6 (DIV), which maps to RegisterIndex8.DH in our enum + if (reg != RegisterIndex8.DH) { return false; } // Set the structured operands - // MUL has only one operand + // DIV has only one operand instruction.StructuredOperands = [ operand @@ -72,4 +72,4 @@ public class MulRm32Handler : InstructionHandler return true; } -} \ No newline at end of file +} diff --git a/X86Disassembler/X86/Handlers/ArithmeticUnary/IdivRm32Handler.cs b/X86Disassembler/X86/Handlers/Idiv/IdivRm32Handler.cs similarity index 86% rename from X86Disassembler/X86/Handlers/ArithmeticUnary/IdivRm32Handler.cs rename to X86Disassembler/X86/Handlers/Idiv/IdivRm32Handler.cs index ec7b0a5..70ad49b 100644 --- a/X86Disassembler/X86/Handlers/ArithmeticUnary/IdivRm32Handler.cs +++ b/X86Disassembler/X86/Handlers/Idiv/IdivRm32Handler.cs @@ -1,6 +1,6 @@ using X86Disassembler.X86.Operands; -namespace X86Disassembler.X86.Handlers.ArithmeticUnary; +namespace X86Disassembler.X86.Handlers.Idiv; /// /// Handler for IDIV r/m32 instruction (0xF7 /7) @@ -54,14 +54,7 @@ public class IdivRm32Handler : InstructionHandler // Read the ModR/M byte // For IDIV r/m32 (0xF7 /7): // - The r/m field with mod specifies the operand (register or memory) - var (_, reg, _, operand) = ModRMDecoder.ReadModRM(); - - // Verify this is an IDIV instruction - // The reg field should be 7 (IDIV) - if (reg != RegisterIndex.Di) - { - return false; - } + var (_, _, _, operand) = ModRMDecoder.ReadModRM(); // Set the structured operands // IDIV has only one operand @@ -72,4 +65,4 @@ public class IdivRm32Handler : InstructionHandler return true; } -} \ No newline at end of file +} diff --git a/X86Disassembler/X86/Handlers/Idiv/IdivRm8Handler.cs b/X86Disassembler/X86/Handlers/Idiv/IdivRm8Handler.cs new file mode 100644 index 0000000..22bc0be --- /dev/null +++ b/X86Disassembler/X86/Handlers/Idiv/IdivRm8Handler.cs @@ -0,0 +1,68 @@ +using X86Disassembler.X86.Operands; + +namespace X86Disassembler.X86.Handlers.Idiv; + +/// +/// Handler for IDIV r/m8 instruction (0xF6 /7) +/// +public class IdivRm8Handler : InstructionHandler +{ + /// + /// Initializes a new instance of the IdivRm8Handler class + /// + /// The instruction decoder that owns this handler + public IdivRm8Handler(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) + { + if (opcode != 0xF6) + return false; + + // Check if the reg field of the ModR/M byte is 7 (IDIV) + if (!Decoder.CanReadByte()) + return false; + + var reg = ModRMDecoder.PeakModRMReg(); + + return reg == 7; // 7 = IDIV + } + + /// + /// Decodes an IDIV r/m8 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.IDiv; + + if (!Decoder.CanReadByte()) + { + return false; + } + + // Read the ModR/M byte + // For IDIV r/m8 (0xF6 /7): + // - The r/m field with mod specifies the operand (register or memory) + var (_, _, _, operand) = ModRMDecoder.ReadModRM8(); + + // Set the structured operands + // IDIV has only one operand + instruction.StructuredOperands = + [ + operand + ]; + + return true; + } +} diff --git a/X86Disassembler/X86/Handlers/ArithmeticUnary/ImulRm32Handler.cs b/X86Disassembler/X86/Handlers/Imul/ImulRm32Handler.cs similarity index 84% rename from X86Disassembler/X86/Handlers/ArithmeticUnary/ImulRm32Handler.cs rename to X86Disassembler/X86/Handlers/Imul/ImulRm32Handler.cs index fae0383..e4d832f 100644 --- a/X86Disassembler/X86/Handlers/ArithmeticUnary/ImulRm32Handler.cs +++ b/X86Disassembler/X86/Handlers/Imul/ImulRm32Handler.cs @@ -1,6 +1,6 @@ using X86Disassembler.X86.Operands; -namespace X86Disassembler.X86.Handlers.ArithmeticUnary; +namespace X86Disassembler.X86.Handlers.Imul; /// /// Handler for IMUL r/m32 instruction (0xF7 /5) @@ -54,14 +54,7 @@ public class ImulRm32Handler : InstructionHandler // Read the ModR/M byte // For IMUL r/m32 (0xF7 /5): // - The r/m field with mod specifies the operand (register or memory) - var (_, reg, _, operand) = ModRMDecoder.ReadModRM(); - - // Verify this is an IMUL instruction - // The reg field should be 5 (IMUL), which maps to RegisterIndex.Bp in our enum - if (reg != RegisterIndex.Bp) - { - return false; - } + var (_, _, _, operand) = ModRMDecoder.ReadModRM(); // Set the structured operands // IMUL has only one operand @@ -72,4 +65,4 @@ public class ImulRm32Handler : InstructionHandler return true; } -} \ No newline at end of file +} diff --git a/X86Disassembler/X86/Handlers/Imul/ImulRm8Handler.cs b/X86Disassembler/X86/Handlers/Imul/ImulRm8Handler.cs new file mode 100644 index 0000000..478efad --- /dev/null +++ b/X86Disassembler/X86/Handlers/Imul/ImulRm8Handler.cs @@ -0,0 +1,68 @@ +using X86Disassembler.X86.Operands; + +namespace X86Disassembler.X86.Handlers.Imul; + +/// +/// Handler for IMUL r/m8 instruction (0xF6 /5) +/// +public class ImulRm8Handler : InstructionHandler +{ + /// + /// Initializes a new instance of the ImulRm8Handler class + /// + /// The instruction decoder that owns this handler + public ImulRm8Handler(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) + { + if (opcode != 0xF6) + return false; + + // Check if the reg field of the ModR/M byte is 5 (IMUL) + if (!Decoder.CanReadByte()) + return false; + + var reg = ModRMDecoder.PeakModRMReg(); + + return reg == 5; // 5 = IMUL + } + + /// + /// Decodes an IMUL r/m8 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.IMul; + + if (!Decoder.CanReadByte()) + { + return false; + } + + // Read the ModR/M byte + // For IMUL r/m8 (0xF6 /5): + // - The r/m field with mod specifies the operand (register or memory) + var (_, _, _, operand) = ModRMDecoder.ReadModRM8(); + + // Set the structured operands + // IMUL has only one operand + instruction.StructuredOperands = + [ + operand + ]; + + return true; + } +} diff --git a/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs b/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs index e24a74c..3950867 100644 --- a/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs +++ b/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs @@ -1,11 +1,13 @@ using X86Disassembler.X86.Handlers.Adc; using X86Disassembler.X86.Handlers.Add; using X86Disassembler.X86.Handlers.And; -using X86Disassembler.X86.Handlers.ArithmeticUnary; using X86Disassembler.X86.Handlers.Call; using X86Disassembler.X86.Handlers.Cmp; using X86Disassembler.X86.Handlers.Dec; +using X86Disassembler.X86.Handlers.Div; using X86Disassembler.X86.Handlers.FloatingPoint; +using X86Disassembler.X86.Handlers.Idiv; +using X86Disassembler.X86.Handlers.Imul; using X86Disassembler.X86.Handlers.Inc; using X86Disassembler.X86.Handlers.Jump; using X86Disassembler.X86.Handlers.Lea; @@ -13,6 +15,7 @@ using X86Disassembler.X86.Handlers.Mov; using X86Disassembler.X86.Handlers.Mul; using X86Disassembler.X86.Handlers.Neg; using X86Disassembler.X86.Handlers.Nop; +using X86Disassembler.X86.Handlers.Not; using X86Disassembler.X86.Handlers.Or; using X86Disassembler.X86.Handlers.Pop; using X86Disassembler.X86.Handlers.Push; @@ -63,9 +66,13 @@ public class InstructionHandlerFactory RegisterArithmeticImmediateHandlers(); // Group 1 instructions (including 0x83) RegisterAddHandlers(); RegisterAndHandlers(); - RegisterArithmeticUnaryHandlers(); + RegisterArithmeticUnaryHandlers(); // Empty, kept for consistency RegisterNegHandlers(); // Register NEG handlers RegisterMulHandlers(); // Register MUL handlers + RegisterNotHandlers(); // Register NOT handlers + RegisterImulHandlers(); // Register IMUL handlers + RegisterDivHandlers(); // Register DIV handlers + RegisterIdivHandlers(); // Register IDIV handlers RegisterCmpHandlers(); RegisterXorHandlers(); RegisterOrHandlers(); @@ -91,17 +98,7 @@ public class InstructionHandlerFactory /// private void RegisterArithmeticUnaryHandlers() { - // NOT handler - _handlers.Add(new NotRm32Handler(_decoder)); - - // IMUL handler - _handlers.Add(new ImulRm32Handler(_decoder)); - - // DIV handler - _handlers.Add(new DivRm32Handler(_decoder)); - - // IDIV handler - _handlers.Add(new IdivRm32Handler(_decoder)); + // This method is kept for consistency, but all handlers have been moved to their own namespaces } /// @@ -462,6 +459,54 @@ public class InstructionHandlerFactory _handlers.Add(new MulRm32Handler(_decoder)); } + /// + /// Registers all NOT instruction handlers + /// + private void RegisterNotHandlers() + { + // NOT r/m8 handler (F6 /2) + _handlers.Add(new NotRm8Handler(_decoder)); + + // NOT r/m32 handler (F7 /2) + _handlers.Add(new NotRm32Handler(_decoder)); + } + + /// + /// Registers all IMUL instruction handlers + /// + private void RegisterImulHandlers() + { + // IMUL r/m8 handler (F6 /5) + _handlers.Add(new ImulRm8Handler(_decoder)); + + // IMUL r/m32 handler (F7 /5) + _handlers.Add(new ImulRm32Handler(_decoder)); + } + + /// + /// Registers all DIV instruction handlers + /// + private void RegisterDivHandlers() + { + // DIV r/m8 handler (F6 /6) + _handlers.Add(new DivRm8Handler(_decoder)); + + // DIV r/m32 handler (F7 /6) + _handlers.Add(new DivRm32Handler(_decoder)); + } + + /// + /// Registers all IDIV instruction handlers + /// + private void RegisterIdivHandlers() + { + // IDIV r/m8 handler (F6 /7) + _handlers.Add(new IdivRm8Handler(_decoder)); + + // IDIV r/m32 handler (F7 /7) + _handlers.Add(new IdivRm32Handler(_decoder)); + } + /// /// Gets the handler that can decode the given opcode /// diff --git a/X86Disassembler/X86/Handlers/Mov/MovRegImm32Handler.cs b/X86Disassembler/X86/Handlers/Mov/MovRegImm32Handler.cs index efa3e29..515d13c 100644 --- a/X86Disassembler/X86/Handlers/Mov/MovRegImm32Handler.cs +++ b/X86Disassembler/X86/Handlers/Mov/MovRegImm32Handler.cs @@ -49,10 +49,10 @@ public class MovRegImm32Handler : InstructionHandler uint imm32 = Decoder.ReadUInt32(); // Create the destination register operand - var destinationOperand = OperandFactory.CreateRegisterOperand(reg, 32); + var destinationOperand = OperandFactory.CreateRegisterOperand(reg); // Create the source immediate operand - var sourceOperand = OperandFactory.CreateImmediateOperand(imm32, 32); + var sourceOperand = OperandFactory.CreateImmediateOperand(imm32); // Set the structured operands instruction.StructuredOperands = diff --git a/X86Disassembler/X86/Handlers/Mov/MovRegImm8Handler.cs b/X86Disassembler/X86/Handlers/Mov/MovRegImm8Handler.cs index fe0dd9b..293c7a6 100644 --- a/X86Disassembler/X86/Handlers/Mov/MovRegImm8Handler.cs +++ b/X86Disassembler/X86/Handlers/Mov/MovRegImm8Handler.cs @@ -38,7 +38,7 @@ public class MovRegImm8Handler : InstructionHandler instruction.Type = InstructionType.Mov; // Register is encoded in the low 3 bits of the opcode - RegisterIndex reg = (RegisterIndex)(opcode & 0x07); + RegisterIndex8 reg = (RegisterIndex8)(opcode & 0x07); // Read the immediate value if (!Decoder.CanReadByte()) @@ -49,7 +49,7 @@ public class MovRegImm8Handler : InstructionHandler byte imm8 = Decoder.ReadByte(); // Create the destination register operand - var destinationOperand = OperandFactory.CreateRegisterOperand(reg, 8); + var destinationOperand = OperandFactory.CreateRegisterOperand8(reg); // Create the source immediate operand var sourceOperand = OperandFactory.CreateImmediateOperand(imm8, 8); diff --git a/X86Disassembler/X86/Handlers/Mov/MovRm32Imm32Handler.cs b/X86Disassembler/X86/Handlers/Mov/MovRm32Imm32Handler.cs index 15823d4..899737c 100644 --- a/X86Disassembler/X86/Handlers/Mov/MovRm32Imm32Handler.cs +++ b/X86Disassembler/X86/Handlers/Mov/MovRm32Imm32Handler.cs @@ -23,7 +23,22 @@ public class MovRm32Imm32Handler : InstructionHandler /// True if this handler can decode the opcode public override bool CanHandle(byte opcode) { - return opcode == 0xC7; + if (opcode != 0xC7) + { + return false; + } + + // Then check if we can peek at the ModR/M byte + if (!Decoder.CanReadByte()) + { + return false; + } + + // Peek at the ModR/M byte without advancing the position + var reg = ModRMDecoder.PeakModRMReg(); + + // MOV r/m8, imm8 only uses reg=0 + return reg == 0; } /// @@ -38,13 +53,7 @@ public class MovRm32Imm32Handler : InstructionHandler instruction.Type = InstructionType.Mov; // Read the ModR/M byte - var (_, reg, _, destinationOperand) = ModRMDecoder.ReadModRM(); - - // MOV r/m32, imm32 only uses reg=0 - if (reg != 0) - { - return false; - } + var (_, _, _, destinationOperand) = ModRMDecoder.ReadModRM(); // Check if we have enough bytes for the immediate value (4 bytes) if (!Decoder.CanReadUInt()) @@ -56,7 +65,7 @@ public class MovRm32Imm32Handler : InstructionHandler uint imm32 = Decoder.ReadUInt32(); // Create the immediate operand - var sourceOperand = OperandFactory.CreateImmediateOperand(imm32, 32); + var sourceOperand = OperandFactory.CreateImmediateOperand(imm32); // Set the structured operands instruction.StructuredOperands = diff --git a/X86Disassembler/X86/Handlers/Mov/MovRm8Imm8Handler.cs b/X86Disassembler/X86/Handlers/Mov/MovRm8Imm8Handler.cs index fd2c27e..dabfcf8 100644 --- a/X86Disassembler/X86/Handlers/Mov/MovRm8Imm8Handler.cs +++ b/X86Disassembler/X86/Handlers/Mov/MovRm8Imm8Handler.cs @@ -23,7 +23,23 @@ public class MovRm8Imm8Handler : InstructionHandler /// True if this handler can decode the opcode public override bool CanHandle(byte opcode) { - return opcode == 0xC6; + // First check if the opcode matches + if (opcode != 0xC6) + { + return false; + } + + // Then check if we can peek at the ModR/M byte + if (!Decoder.CanReadByte()) + { + return false; + } + + // Peek at the ModR/M byte without advancing the position + var reg = ModRMDecoder.PeakModRMReg(); + + // MOV r/m8, imm8 only uses reg=0 + return reg == 0; } /// @@ -47,14 +63,8 @@ public class MovRm8Imm8Handler : InstructionHandler // For MOV r/m8, imm8 (0xC6): // - The r/m field with mod specifies the destination operand (register or memory) // - The immediate value is the source operand - var (_, reg, _, destinationOperand) = ModRMDecoder.ReadModRM8(); - - // MOV r/m8, imm8 only uses reg=0 - if (reg != 0) - { - return false; - } - + var (_, _, _, destinationOperand) = ModRMDecoder.ReadModRM8(); + // Note: The operand size is already set to 8-bit by the ReadModRM8 method // Read the immediate value diff --git a/X86Disassembler/X86/Handlers/Mul/MulRm32Handler.cs b/X86Disassembler/X86/Handlers/Mul/MulRm32Handler.cs index 331f222..5b4bd95 100644 --- a/X86Disassembler/X86/Handlers/Mul/MulRm32Handler.cs +++ b/X86Disassembler/X86/Handlers/Mul/MulRm32Handler.cs @@ -54,14 +54,7 @@ public class MulRm32Handler : InstructionHandler // Read the ModR/M byte // For MUL r/m32 (0xF7 /4): // - The r/m field with mod specifies the operand (register or memory) - var (_, reg, _, operand) = ModRMDecoder.ReadModRM(); - - // Verify this is a MUL instruction - // The reg field should be 4 (MUL), which maps to RegisterIndex.Sp in our enum - if (reg != RegisterIndex.Sp) - { - return false; - } + var (_, _, _, operand) = ModRMDecoder.ReadModRM(); // Set the structured operands // MUL has only one operand diff --git a/X86Disassembler/X86/Handlers/Mul/MulRm8Handler.cs b/X86Disassembler/X86/Handlers/Mul/MulRm8Handler.cs index 0847b80..72ad7f1 100644 --- a/X86Disassembler/X86/Handlers/Mul/MulRm8Handler.cs +++ b/X86Disassembler/X86/Handlers/Mul/MulRm8Handler.cs @@ -54,14 +54,7 @@ public class MulRm8Handler : InstructionHandler // Read the ModR/M byte // For MUL r/m8 (0xF6 /4): // - The r/m field with mod specifies the operand (register or memory) - var (_, reg, _, operand) = ModRMDecoder.ReadModRM8(); - - // Verify this is a MUL instruction - // The reg field should be 4 (MUL), which maps to RegisterIndex8.AH in our enum - if (reg != RegisterIndex8.AH) - { - return false; - } + var (_, _, _, operand) = ModRMDecoder.ReadModRM8(); // Set the structured operands // MUL has only one operand diff --git a/X86Disassembler/X86/Handlers/ArithmeticUnary/NegRm32Handler.cs b/X86Disassembler/X86/Handlers/Neg/NegRm32Handler.cs similarity index 84% rename from X86Disassembler/X86/Handlers/ArithmeticUnary/NegRm32Handler.cs rename to X86Disassembler/X86/Handlers/Neg/NegRm32Handler.cs index 8bd3659..cc44618 100644 --- a/X86Disassembler/X86/Handlers/ArithmeticUnary/NegRm32Handler.cs +++ b/X86Disassembler/X86/Handlers/Neg/NegRm32Handler.cs @@ -1,6 +1,6 @@ using X86Disassembler.X86.Operands; -namespace X86Disassembler.X86.Handlers.ArithmeticUnary; +namespace X86Disassembler.X86.Handlers.Neg; /// /// Handler for NEG r/m32 instruction (0xF7 /3) @@ -54,14 +54,7 @@ public class NegRm32Handler : InstructionHandler // Read the ModR/M byte // For NEG r/m32 (0xF7 /3): // - The r/m field with mod specifies the operand (register or memory) - var (_, reg, _, operand) = ModRMDecoder.ReadModRM(); - - // Verify this is a NEG instruction - // The reg field should be 3 (NEG), which maps to RegisterIndex.B in our enum - if (reg != RegisterIndex.B) - { - return false; - } + var (_, _, _, operand) = ModRMDecoder.ReadModRM(); // Set the structured operands // NEG has only one operand @@ -72,4 +65,4 @@ public class NegRm32Handler : InstructionHandler return true; } -} \ No newline at end of file +} diff --git a/X86Disassembler/X86/Handlers/ArithmeticUnary/NegRm8Handler.cs b/X86Disassembler/X86/Handlers/Neg/NegRm8Handler.cs similarity index 86% rename from X86Disassembler/X86/Handlers/ArithmeticUnary/NegRm8Handler.cs rename to X86Disassembler/X86/Handlers/Neg/NegRm8Handler.cs index 3e5c3c0..e85123b 100644 --- a/X86Disassembler/X86/Handlers/ArithmeticUnary/NegRm8Handler.cs +++ b/X86Disassembler/X86/Handlers/Neg/NegRm8Handler.cs @@ -1,6 +1,6 @@ using X86Disassembler.X86.Operands; -namespace X86Disassembler.X86.Handlers.ArithmeticUnary; +namespace X86Disassembler.X86.Handlers.Neg; /// /// Handler for NEG r/m8 instruction (0xF6 /3) @@ -51,10 +51,7 @@ public class NegRm8Handler : InstructionHandler return false; } - // Read the ModR/M byte - // For NEG r/m8 (0xF6 /3): - // - The r/m field with mod specifies the operand (register or memory) - var (_, reg, _, operand) = ModRMDecoder.ReadModRM8(); + var (_, _, _, operand) = ModRMDecoder.ReadModRM8(); // Set the structured operands // NEG has only one operand diff --git a/X86Disassembler/X86/Handlers/ArithmeticUnary/NotRm32Handler.cs b/X86Disassembler/X86/Handlers/Not/NotRm32Handler.cs similarity index 87% rename from X86Disassembler/X86/Handlers/ArithmeticUnary/NotRm32Handler.cs rename to X86Disassembler/X86/Handlers/Not/NotRm32Handler.cs index 7311f54..bb7cdb8 100644 --- a/X86Disassembler/X86/Handlers/ArithmeticUnary/NotRm32Handler.cs +++ b/X86Disassembler/X86/Handlers/Not/NotRm32Handler.cs @@ -1,6 +1,6 @@ using X86Disassembler.X86.Operands; -namespace X86Disassembler.X86.Handlers.ArithmeticUnary; +namespace X86Disassembler.X86.Handlers.Not; /// /// Handler for NOT r/m32 instruction (0xF7 /2) @@ -57,13 +57,6 @@ public class NotRm32Handler : InstructionHandler // - The r/m field with mod specifies the operand (register or memory) var (_, reg, _, operand) = ModRMDecoder.ReadModRM(); - // Verify this is a NOT instruction - // The reg field should be 2 (NOT), which maps to RegisterIndex.D in our enum - if (reg != RegisterIndex.D) - { - return false; - } - // Set the structured operands // NOT has only one operand instruction.StructuredOperands = @@ -73,4 +66,4 @@ public class NotRm32Handler : InstructionHandler return true; } -} \ No newline at end of file +} diff --git a/X86Disassembler/X86/Handlers/Not/NotRm8Handler.cs b/X86Disassembler/X86/Handlers/Not/NotRm8Handler.cs new file mode 100644 index 0000000..b882b40 --- /dev/null +++ b/X86Disassembler/X86/Handlers/Not/NotRm8Handler.cs @@ -0,0 +1,69 @@ +using X86Disassembler.X86.Operands; + +namespace X86Disassembler.X86.Handlers.Not; + +/// +/// Handler for NOT r/m8 instruction (0xF6 /2) +/// +public class NotRm8Handler : InstructionHandler +{ + /// + /// Initializes a new instance of the NotRm8Handler class + /// + /// The instruction decoder that owns this handler + public NotRm8Handler(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) + { + // This handler only handles opcode 0xF6 + if (opcode != 0xF6) + return false; + + // Check if the reg field of the ModR/M byte is 2 (NOT) + if (!Decoder.CanReadByte()) + return false; + + var reg = ModRMDecoder.PeakModRMReg(); + + return reg == 2; // 2 = NOT + } + + /// + /// Decodes a NOT r/m8 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.Not; + + if (!Decoder.CanReadByte()) + { + return false; + } + + // Read the ModR/M byte + // For NOT r/m8 (0xF6 /2): + // - The r/m field with mod specifies the operand (register or memory) + var (_, reg, _, operand) = ModRMDecoder.ReadModRM8(); + + // Set the structured operands + // NOT has only one operand + instruction.StructuredOperands = + [ + operand + ]; + + return true; + } +} diff --git a/X86Disassembler/X86/SIBDecoder.cs b/X86Disassembler/X86/SIBDecoder.cs index 4503906..cf798e9 100644 --- a/X86Disassembler/X86/SIBDecoder.cs +++ b/X86Disassembler/X86/SIBDecoder.cs @@ -69,6 +69,7 @@ public class SIBDecoder { if (_decoder.CanReadUInt()) { + // For other instructions, read the 32-bit displacement uint disp32 = _decoder.ReadUInt32(); int scaleValue = 1 << scale; // 1, 2, 4, or 8 @@ -83,7 +84,7 @@ public class SIBDecoder return OperandFactory.CreateScaledIndexMemoryOperand( index, scaleValue, - null, + null, // No base register (int)disp32, operandSize); } diff --git a/X86DisassemblerTests/TestData/lea_tests.csv b/X86DisassemblerTests/TestData/lea_tests.csv index 4de15b3..603eb97 100644 --- a/X86DisassemblerTests/TestData/lea_tests.csv +++ b/X86DisassemblerTests/TestData/lea_tests.csv @@ -13,7 +13,7 @@ RawBytes;Instructions # The correct encoding for "LEA eax, [ebp]" would be 8D4500 (with Mod=01 and a zero displacement). # 8D05;[{ "Type": "Lea", "Operands": ["eax", "dword ptr [ebp]"] }] # Adding the correct test case: -8D4500;[{ "Type": "Lea", "Operands": ["eax", "dword ptr [ebp+0x0]"] }] +8D4500;[{ "Type": "Lea", "Operands": ["eax", "dword ptr [ebp+0x00]"] }] 8D06;[{ "Type": "Lea", "Operands": ["eax", "dword ptr [esi]"] }] 8D07;[{ "Type": "Lea", "Operands": ["eax", "dword ptr [edi]"] }] diff --git a/X86DisassemblerTests/TestData/neg_tests.csv b/X86DisassemblerTests/TestData/neg_tests.csv index 3c8cdd9..6458688 100644 --- a/X86DisassemblerTests/TestData/neg_tests.csv +++ b/X86DisassemblerTests/TestData/neg_tests.csv @@ -30,4 +30,4 @@ F618;[{ "Type": "Neg", "Operands": ["byte ptr [eax]"] }] F718;[{ "Type": "Neg", "Operands": ["dword ptr [eax]"] }] # This test case is correct, as it includes the required displacement -F71C2510000000;[{ "Type": "Neg", "Operands": ["dword ptr [eax+0x10]"] }] +F71C2510000000;[{ "Type": "Neg", "Operands": ["dword ptr [0x10]"] }]