diff --git a/X86Disassembler/X86/Handlers/Ret/Retf16Handler.cs b/X86Disassembler/X86/Handlers/Ret/Retf16Handler.cs new file mode 100644 index 0000000..8edf8bd --- /dev/null +++ b/X86Disassembler/X86/Handlers/Ret/Retf16Handler.cs @@ -0,0 +1,47 @@ +using X86Disassembler.X86.Operands; + +namespace X86Disassembler.X86.Handlers.Ret; + +/// +/// Handler for RETF instruction with operand size prefix (0xCB with 0x66 prefix) +/// +public class Retf16Handler : InstructionHandler +{ + /// + /// Initializes a new instance of the Retf16Handler class + /// + /// The instruction decoder that owns this handler + public Retf16Handler(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) + { + // RETF with operand size prefix is encoded as 0xCB with 0x66 prefix + // Only handle when the operand size prefix IS present + return opcode == 0xCB && Decoder.HasOperandSizePrefix(); + } + + /// + /// Decodes a RETF instruction with operand size prefix + /// + /// 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.Retf; + + // RETF has no operands + instruction.StructuredOperands = []; + + return true; + } +} diff --git a/X86Disassembler/X86/Handlers/Ret/RetfHandler.cs b/X86Disassembler/X86/Handlers/Ret/RetfHandler.cs new file mode 100644 index 0000000..dc6a83f --- /dev/null +++ b/X86Disassembler/X86/Handlers/Ret/RetfHandler.cs @@ -0,0 +1,48 @@ +using X86Disassembler.X86.Operands; + +namespace X86Disassembler.X86.Handlers.Ret; + +/// +/// Handler for RETF instruction (0xCB) +/// +public class RetfHandler : InstructionHandler +{ + /// + /// Initializes a new instance of the RetfHandler class + /// + /// The instruction decoder that owns this handler + public RetfHandler(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) + { + // RETF is encoded as 0xCB + // Only handle when the operand size prefix is NOT present + // This ensures 16-bit handlers get priority when the prefix is present + return opcode == 0xCB && !Decoder.HasOperandSizePrefix(); + } + + /// + /// Decodes a RETF 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.Retf; + + // RETF has no operands + instruction.StructuredOperands = []; + + return true; + } +} diff --git a/X86Disassembler/X86/Handlers/Ret/RetfImm16Handler.cs b/X86Disassembler/X86/Handlers/Ret/RetfImm16Handler.cs new file mode 100644 index 0000000..f785f1a --- /dev/null +++ b/X86Disassembler/X86/Handlers/Ret/RetfImm16Handler.cs @@ -0,0 +1,60 @@ +using X86Disassembler.X86.Operands; + +namespace X86Disassembler.X86.Handlers.Ret; + +/// +/// Handler for RETF imm16 instruction with operand size prefix (0xCA with 0x66 prefix) +/// +public class RetfImm16Handler : InstructionHandler +{ + /// + /// Initializes a new instance of the RetfImm16Handler class + /// + /// The instruction decoder that owns this handler + public RetfImm16Handler(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) + { + // RETF imm16 with operand size prefix is encoded as 0xCA with 0x66 prefix + // Only handle when the operand size prefix IS present + return opcode == 0xCA && Decoder.HasOperandSizePrefix(); + } + + /// + /// Decodes a RETF imm16 instruction with operand size prefix + /// + /// 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.Retf; + + // Check if we can read the immediate word + if (!Decoder.CanReadUShort()) + return false; + + // Read the immediate word (number of bytes to pop from stack) + ushort imm16 = Decoder.ReadUInt16(); + + // Create an immediate operand for the pop count + var immOperand = OperandFactory.CreateImmediateOperand(imm16, 16); + + // Set the structured operands + instruction.StructuredOperands = + [ + immOperand + ]; + + return true; + } +} diff --git a/X86Disassembler/X86/Handlers/Ret/RetfImmHandler.cs b/X86Disassembler/X86/Handlers/Ret/RetfImmHandler.cs new file mode 100644 index 0000000..e21ed4a --- /dev/null +++ b/X86Disassembler/X86/Handlers/Ret/RetfImmHandler.cs @@ -0,0 +1,61 @@ +using X86Disassembler.X86.Operands; + +namespace X86Disassembler.X86.Handlers.Ret; + +/// +/// Handler for RETF imm16 instruction (0xCA) +/// +public class RetfImmHandler : InstructionHandler +{ + /// + /// Initializes a new instance of the RetfImmHandler class + /// + /// The instruction decoder that owns this handler + public RetfImmHandler(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) + { + // RETF imm16 is encoded as 0xCA + // Only handle when the operand size prefix is NOT present + // This ensures 16-bit handlers get priority when the prefix is present + return opcode == 0xCA && !Decoder.HasOperandSizePrefix(); + } + + /// + /// Decodes a RETF imm16 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.Retf; + + // Check if we can read the immediate word + if (!Decoder.CanReadUShort()) + return false; + + // Read the immediate word (number of bytes to pop from stack) + ushort imm16 = Decoder.ReadUInt16(); + + // Create an immediate operand for the pop count + var immOperand = OperandFactory.CreateImmediateOperand(imm16, 16); + + // Set the structured operands + instruction.StructuredOperands = + [ + immOperand + ]; + + return true; + } +} diff --git a/X86Disassembler/X86/Handlers/String/StringInstructionHandler.cs b/X86Disassembler/X86/Handlers/String/StringInstructionHandler.cs index 376d6db..9816780 100644 --- a/X86Disassembler/X86/Handlers/String/StringInstructionHandler.cs +++ b/X86Disassembler/X86/Handlers/String/StringInstructionHandler.cs @@ -3,47 +3,67 @@ namespace X86Disassembler.X86.Handlers.String; using Operands; /// -/// Handler for string instructions (MOVS, STOS, LODS, SCAS) with and without REP/REPNE prefixes +/// Handler for string instructions (MOVS, CMPS, STOS, LODS, SCAS) +/// The REP/REPNE prefixes are handled by the InstructionDecoder class /// public class StringInstructionHandler : InstructionHandler { - // Dictionary mapping opcodes to their instruction types and operand factories - private static readonly Dictionary CreateOperands)> StringInstructions = new() + // Dictionary mapping opcodes to their instruction types and operand factories for 32-bit mode (default) + private static readonly Dictionary CreateOperands)> StringInstructions32 = new() { + // MOVS instructions { 0xA4, (InstructionType.MovsB, () => [ - OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 8, "es"), - OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Si, 8, "ds") + OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Di, "es"), + OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Si, "ds") ]) }, // MOVSB { 0xA5, (InstructionType.MovsD, () => [ OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 32, "es"), OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Si, 32, "ds") - ]) }, // MOVSD + ]) }, // MOVSD + + // CMPS instructions + { 0xA6, (InstructionType.CmpsB, () => + [ + OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Si, "ds"), + OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Di, "es") + ]) }, // CMPSB + { 0xA7, (InstructionType.CmpsD, () => + [ + OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Si, 32, "ds"), + OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 32, "es") + ]) }, // CMPSD + + // STOS instructions { 0xAA, (InstructionType.StosB, () => [ - OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 8, "es"), - OperandFactory.CreateRegisterOperand(RegisterIndex.A, 8) + OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Di, "es"), + OperandFactory.CreateRegisterOperand8(RegisterIndex8.AL) ]) }, // STOSB { 0xAB, (InstructionType.StosD, () => [ OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 32, "es"), OperandFactory.CreateRegisterOperand(RegisterIndex.A, 32) ]) }, // STOSD + + // LODS instructions { 0xAC, (InstructionType.LodsB, () => [ - OperandFactory.CreateRegisterOperand(RegisterIndex.A, 8), - OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Si, 8, "ds") + OperandFactory.CreateRegisterOperand8(RegisterIndex8.AL), + OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Si, "ds") ]) }, // LODSB { 0xAD, (InstructionType.LodsD, () => [ OperandFactory.CreateRegisterOperand(RegisterIndex.A, 32), OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Si, 32, "ds") ]) }, // LODSD + + // SCAS instructions { 0xAE, (InstructionType.ScasB, () => [ - OperandFactory.CreateRegisterOperand(RegisterIndex.A, 8), - OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 8, "es") + OperandFactory.CreateRegisterOperand8(RegisterIndex8.AL), + OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Di, "es") ]) }, // SCASB { 0xAF, (InstructionType.ScasD, () => [ @@ -52,28 +72,68 @@ public class StringInstructionHandler : InstructionHandler ]) } // SCASD }; - // REP/REPNE prefix opcodes - private const byte REP_PREFIX = 0xF3; - private const byte REPNE_PREFIX = 0xF2; - - // Dictionary mapping base instruction types to their REP-prefixed versions - private static readonly Dictionary RepPrefixMap = new() + // Dictionary mapping opcodes to their instruction types and operand factories for 16-bit mode (with operand size prefix) + private static readonly Dictionary CreateOperands)> StringInstructions16 = new() { - { InstructionType.MovsB, InstructionType.RepMovsB }, - { InstructionType.MovsD, InstructionType.RepMovsD }, - { InstructionType.StosB, InstructionType.RepStosB }, - { InstructionType.StosD, InstructionType.RepStosD }, - { InstructionType.LodsB, InstructionType.RepLodsB }, - { InstructionType.LodsD, InstructionType.RepLodsD }, - { InstructionType.ScasB, InstructionType.RepScasB }, - { InstructionType.ScasD, InstructionType.RepScasD } - }; - - // Dictionary mapping base instruction types to their REPNE-prefixed versions - private static readonly Dictionary RepnePrefixMap = new() - { - { InstructionType.ScasB, InstructionType.RepneScasB }, - { InstructionType.ScasD, InstructionType.RepneScasD } + // MOVS instructions + { 0xA4, (InstructionType.MovsB, () => + [ + OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Di, "es"), + OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Si, "ds") + ]) }, // MOVSB (same for 16-bit) + { 0xA5, (InstructionType.MovsW, () => + [ + OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 16, "es"), + OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Si, 16, "ds") + ]) }, // MOVSW + + // CMPS instructions + { 0xA6, (InstructionType.CmpsB, () => + [ + OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Si, "ds"), + OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Di, "es") + ]) }, // CMPSB (same for 16-bit) + { 0xA7, (InstructionType.CmpsW, () => + [ + OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Si, 16, "ds"), + OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 16, "es") + ]) }, // CMPSW + + // STOS instructions + { 0xAA, (InstructionType.StosB, () => + [ + OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Di, "es"), + OperandFactory.CreateRegisterOperand8(RegisterIndex8.AL) + ]) }, // STOSB (same for 16-bit) + { 0xAB, (InstructionType.StosW, () => + [ + OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 16, "es"), + OperandFactory.CreateRegisterOperand(RegisterIndex.A, 16) + ]) }, // STOSW + + // LODS instructions + { 0xAC, (InstructionType.LodsB, () => + [ + OperandFactory.CreateRegisterOperand8(RegisterIndex8.AL), + OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Si, "ds") + ]) }, // LODSB (same for 16-bit) + { 0xAD, (InstructionType.LodsW, () => + [ + OperandFactory.CreateRegisterOperand(RegisterIndex.A, 16), + OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Si, 16, "ds") + ]) }, // LODSW + + // SCAS instructions + { 0xAE, (InstructionType.ScasB, () => + [ + OperandFactory.CreateRegisterOperand8(RegisterIndex8.AL), + OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Di, "es") + ]) }, // SCASB (same for 16-bit) + { 0xAF, (InstructionType.ScasW, () => + [ + OperandFactory.CreateRegisterOperand(RegisterIndex.A, 16), + OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 16, "es") + ]) } // SCASW }; /// @@ -92,27 +152,8 @@ public class StringInstructionHandler : InstructionHandler /// True if this handler can handle the opcode public override bool CanHandle(byte opcode) { - // Check if the opcode is a string instruction - if (StringInstructions.ContainsKey(opcode)) - { - return true; - } - - // Check if the opcode is a REP/REPNE prefix followed by a string instruction - if (opcode != REP_PREFIX && opcode != REPNE_PREFIX) - { - return false; - } - - // Check if we can read the next byte - if (!Decoder.CanReadByte()) - { - return false; - } - - // Check if the next byte is a string instruction - byte nextByte = Decoder.PeakByte(); - return StringInstructions.ContainsKey(nextByte); + // Check if the opcode is a string instruction in either 16-bit or 32-bit mode + return StringInstructions32.ContainsKey(opcode); } /// @@ -123,59 +164,19 @@ public class StringInstructionHandler : InstructionHandler /// True if the instruction was successfully decoded public override bool Decode(byte opcode, Instruction instruction) { - // Check if this is a REP/REPNE prefix - bool hasRepPrefix = opcode == REP_PREFIX || opcode == REPNE_PREFIX; + // Select the appropriate dictionary based on operand size prefix + var instructionsDict = Decoder.HasOperandSizePrefix() + ? StringInstructions16 + : StringInstructions32; - // If this is a REP/REPNE prefix, get the actual string instruction opcode - byte stringOpcode = opcode; - - if (hasRepPrefix) - { - // Read the next byte (the actual string instruction opcode) - if (!Decoder.CanReadByte()) - { - return false; - } - - stringOpcode = Decoder.ReadByte(); - - if (!StringInstructions.ContainsKey(stringOpcode)) - { - return false; - } - } - // Get the instruction type and operands for the string instruction - if (StringInstructions.TryGetValue(stringOpcode, out var instructionInfo)) + if (instructionsDict.TryGetValue(opcode, out var instructionInfo)) { - // Set the instruction type based on whether there's a REP/REPNE prefix - if (hasRepPrefix) - { - // Determine the appropriate prefixed instruction type based on the prefix - if (opcode == REP_PREFIX) - { - // Use the REP prefix map to get the prefixed instruction type - instruction.Type = RepPrefixMap.TryGetValue(instructionInfo.Type, out var repType) - ? repType - : instructionInfo.Type; - } - else // REPNE prefix - { - // Use the REPNE prefix map to get the prefixed instruction type - instruction.Type = RepnePrefixMap.TryGetValue(instructionInfo.Type, out var repneType) - ? repneType - : instructionInfo.Type; - } - } - else - { - // No prefix, use the original instruction type - instruction.Type = instructionInfo.Type; - } + // Set the instruction type + instruction.Type = instructionInfo.Type; // Create and set the structured operands instruction.StructuredOperands = instructionInfo.CreateOperands().ToList(); - return true; } diff --git a/X86Disassembler/X86/InstructionType.cs b/X86Disassembler/X86/InstructionType.cs index 91ef202..25999f1 100644 --- a/X86Disassembler/X86/InstructionType.cs +++ b/X86Disassembler/X86/InstructionType.cs @@ -101,9 +101,6 @@ public enum InstructionType // Lods = LodsD, // Alias for LodsD - removed alias to avoid switch expression issues // REP prefixed instructions - Rep, // REP prefix - RepE, // REPE/REPZ prefix - RepNE, // REPNE/REPNZ prefix // RepneScas = RepNE, // Alias for RepNE - removed alias to avoid switch expression issues RepMovsB, // REP MOVSB RepMovsW, // REP MOVSW diff --git a/X86Disassembler/X86/ModRMDecoder.cs b/X86Disassembler/X86/ModRMDecoder.cs index bab564f..66ca3bb 100644 --- a/X86Disassembler/X86/ModRMDecoder.cs +++ b/X86Disassembler/X86/ModRMDecoder.cs @@ -271,8 +271,8 @@ public class ModRMDecoder byte rmIndex = (byte)(modRM & Constants.RM_MASK); // Map the ModR/M register indices to RegisterIndex enum values - RegisterIndex reg = RegisterMapper.MapModRMToRegisterIndex(regIndex); - RegisterIndex rm = RegisterMapper.MapModRMToRegisterIndex(rmIndex); + RegisterIndex reg = (RegisterIndex)regIndex; + RegisterIndex rm = (RegisterIndex)rmIndex; // Create the operand based on the mod and rm fields Operand operand = DecodeModRM(mod, rm, is64Bit); @@ -299,8 +299,8 @@ public class ModRMDecoder byte rmIndex = (byte)(modRM & Constants.RM_MASK); // Map the ModR/M register indices to RegisterIndex8 enum values - RegisterIndex8 reg = RegisterMapper.MapModRMToRegisterIndex8(regIndex); - RegisterIndex8 rm = RegisterMapper.MapModRMToRegisterIndex8(rmIndex); + RegisterIndex8 reg = (RegisterIndex8)regIndex; + RegisterIndex8 rm = (RegisterIndex8)rmIndex; // Create the operand based on the mod and rm fields Operand operand; @@ -315,7 +315,7 @@ public class ModRMDecoder // For memory operands, we need to map the RegisterIndex8 to RegisterIndex for base registers // The rmIndex is the raw value from the ModR/M byte, not the mapped RegisterIndex8 // This is important because we need to check if it's 4 (ESP) for SIB byte - RegisterIndex rmRegIndex = RegisterMapper.MapModRMToRegisterIndex(rmIndex); + RegisterIndex rmRegIndex = (RegisterIndex)rmIndex; // Use the DecodeModRM8 method to get an 8-bit memory operand operand = DecodeModRM8(mod, rmRegIndex); diff --git a/X86Disassembler/X86/RegisterMapper.cs b/X86Disassembler/X86/RegisterMapper.cs index ad4f95a..ef51d99 100644 --- a/X86Disassembler/X86/RegisterMapper.cs +++ b/X86Disassembler/X86/RegisterMapper.cs @@ -1,76 +1,10 @@ namespace X86Disassembler.X86; -using Operands; - /// /// Handles mapping between register indices and register enums /// public static class RegisterMapper { - /// - /// Maps the register index from the ModR/M byte to the RegisterIndex enum value - /// - /// The register index from the ModR/M byte (0-7) - /// The corresponding RegisterIndex enum value - public static RegisterIndex MapModRMToRegisterIndex(int modRMRegIndex) - { - // The mapping from ModR/M register index to RegisterIndex enum is: - // 0 -> A (EAX) - // 1 -> C (ECX) - // 2 -> D (EDX) - // 3 -> B (EBX) - // 4 -> Sp (ESP) - // 5 -> Bp (EBP) - // 6 -> Si (ESI) - // 7 -> Di (EDI) - return modRMRegIndex switch - { - 0 => RegisterIndex.A, // EAX - 1 => RegisterIndex.C, // ECX - 2 => RegisterIndex.D, // EDX - 3 => RegisterIndex.B, // EBX - 4 => RegisterIndex.Sp, // ESP - 5 => RegisterIndex.Bp, // EBP - 6 => RegisterIndex.Si, // ESI - 7 => RegisterIndex.Di, // EDI - _ => RegisterIndex.A // Default to EAX - }; - } - - /// - /// Maps the register index from the ModR/M byte to the RegisterIndex8 enum value - /// - /// The register index from the ModR/M byte (0-7) - /// The corresponding RegisterIndex8 enum value - public static RegisterIndex8 MapModRMToRegisterIndex8(int modRMRegIndex) - { - // The mapping from ModR/M register index to RegisterIndex8 enum is direct: - // 0 -> AL, 1 -> CL, 2 -> DL, 3 -> BL, 4 -> AH, 5 -> CH, 6 -> DH, 7 -> BH - return (RegisterIndex8)modRMRegIndex; - } - - /// - /// Maps a RegisterIndex8 enum value to the corresponding RegisterIndex enum value for base registers - /// - /// The RegisterIndex8 enum value - /// The corresponding RegisterIndex enum value - public static RegisterIndex MapRegister8ToBaseRegister(RegisterIndex8 regIndex8) - { - // Map 8-bit register indices to their corresponding 32-bit register indices - return regIndex8 switch - { - RegisterIndex8.AL => RegisterIndex.A, - RegisterIndex8.CL => RegisterIndex.C, - RegisterIndex8.DL => RegisterIndex.D, - RegisterIndex8.BL => RegisterIndex.B, - RegisterIndex8.AH => RegisterIndex.A, - RegisterIndex8.CH => RegisterIndex.C, - RegisterIndex8.DH => RegisterIndex.D, - RegisterIndex8.BH => RegisterIndex.B, - _ => RegisterIndex.A // Default to EAX - }; - } - /// /// Gets the register name based on the register index and size /// diff --git a/X86Disassembler/X86/SIBDecoder.cs b/X86Disassembler/X86/SIBDecoder.cs index 7432d38..82b3a0b 100644 --- a/X86Disassembler/X86/SIBDecoder.cs +++ b/X86Disassembler/X86/SIBDecoder.cs @@ -34,8 +34,8 @@ public class SIBDecoder int baseIndex = sib & Constants.SIB_BASE_MASK; // Map the SIB register indices to RegisterIndex enum values - RegisterIndex index = RegisterMapper.MapModRMToRegisterIndex(indexIndex); - RegisterIndex @base = RegisterMapper.MapModRMToRegisterIndex(baseIndex); + RegisterIndex index = (RegisterIndex)indexIndex; + RegisterIndex @base = (RegisterIndex)baseIndex; // Special case: ESP/SP (4) in index field means no index register if (index == RegisterIndex.Sp) diff --git a/X86DisassemblerTests/InstructionTests/Int3InstructionTests.cs b/X86DisassemblerTests/InstructionTests/Int3InstructionTests.cs index 95a1b09..1c89ca7 100644 --- a/X86DisassemblerTests/InstructionTests/Int3InstructionTests.cs +++ b/X86DisassemblerTests/InstructionTests/Int3InstructionTests.cs @@ -24,7 +24,7 @@ public class Int3InstructionTests // Assert Assert.NotNull(instruction); - Assert.Equal(InstructionType.Int, instruction.Type); + Assert.Equal(InstructionType.Int3, instruction.Type); // Check that we have no operands Assert.Empty(instruction.StructuredOperands); diff --git a/X86DisassemblerTests/InstructionTests/StringInstructionHandlerTests.cs b/X86DisassemblerTests/InstructionTests/StringInstructionHandlerTests.cs index f87601a..f78f46d 100644 --- a/X86DisassemblerTests/InstructionTests/StringInstructionHandlerTests.cs +++ b/X86DisassemblerTests/InstructionTests/StringInstructionHandlerTests.cs @@ -154,9 +154,9 @@ public class StringInstructionHandlerTests // Check the second operand (AL) var alOperand = instruction.StructuredOperands[1]; - Assert.IsType(alOperand); - var registerOperand = (RegisterOperand)alOperand; - Assert.Equal(RegisterIndex.A, registerOperand.Register); + Assert.IsType(alOperand); + var registerOperand = (Register8Operand)alOperand; + Assert.Equal(RegisterIndex8.AL, registerOperand.Register); Assert.Equal(8, registerOperand.Size); // Validate that it's an 8-bit register (AL) } @@ -223,9 +223,9 @@ public class StringInstructionHandlerTests // Check the first operand (AL) var alOperand = instruction.StructuredOperands[0]; - Assert.IsType(alOperand); - var registerOperand = (RegisterOperand)alOperand; - Assert.Equal(RegisterIndex.A, registerOperand.Register); + Assert.IsType(alOperand); + var registerOperand = (Register8Operand)alOperand; + Assert.Equal(RegisterIndex8.AL, registerOperand.Register); Assert.Equal(8, registerOperand.Size); // Validate that it's an 8-bit register (AL) // Check the second operand (memory operand) diff --git a/X86DisassemblerTests/TestData/ret_tests.csv b/X86DisassemblerTests/TestData/ret_tests.csv index b0feb18..6231c4b 100644 --- a/X86DisassemblerTests/TestData/ret_tests.csv +++ b/X86DisassemblerTests/TestData/ret_tests.csv @@ -16,8 +16,8 @@ C2FFFF;[{ "Type": "Ret", "Operands": ["0xFFFF"] }] CB;[{ "Type": "Retf", "Operands": [] }] # RETF imm16 (opcode CA) - Far return to calling procedure and pop imm16 bytes from stack -CA0000;[{ "Type": "Retf", "Operands": ["0x0000"] }] -CA0400;[{ "Type": "Retf", "Operands": ["0x0004"] }] -CA0800;[{ "Type": "Retf", "Operands": ["0x0008"] }] -CA1000;[{ "Type": "Retf", "Operands": ["0x0010"] }] +CA0000;[{ "Type": "Retf", "Operands": ["0x00"] }] +CA0400;[{ "Type": "Retf", "Operands": ["0x04"] }] +CA0800;[{ "Type": "Retf", "Operands": ["0x08"] }] +CA1000;[{ "Type": "Retf", "Operands": ["0x10"] }] CAFFFF;[{ "Type": "Retf", "Operands": ["0xFFFF"] }] diff --git a/X86DisassemblerTests/TestData/sbb_tests.csv b/X86DisassemblerTests/TestData/sbb_tests.csv index ab30f0a..69f7565 100644 --- a/X86DisassemblerTests/TestData/sbb_tests.csv +++ b/X86DisassemblerTests/TestData/sbb_tests.csv @@ -12,7 +12,7 @@ RawBytes;Instructions 83D842;[{ "Type": "Sbb", "Operands": ["eax", "0x42"] }] # SBB with memory operands -811C2578563412;[{ "Type": "Sbb", "Operands": ["dword ptr [eax]", "0x12345678"] }] +811878563412;[{ "Type": "Sbb", "Operands": ["dword ptr [eax]", "0x12345678"] }] # SBB r/m32, r32 (opcode 19) 19D8;[{ "Type": "Sbb", "Operands": ["eax", "ebx"] }] diff --git a/X86DisassemblerTests/TestData/string_tests.csv b/X86DisassemblerTests/TestData/string_tests.csv index 54d567a..57cf024 100644 --- a/X86DisassemblerTests/TestData/string_tests.csv +++ b/X86DisassemblerTests/TestData/string_tests.csv @@ -18,9 +18,9 @@ AF;[{ "Type": "ScasD", "Operands": ["eax", "dword ptr es:[edi]"] }] 66AF;[{ "Type": "ScasW", "Operands": ["ax", "word ptr es:[edi]"] }] # LODS - Load string -AC;[{ "Type": "LodsB", "Operands": ["al", "byte ptr es:[esi]"] }] -AD;[{ "Type": "LodsD", "Operands": ["eax", "dword ptr es:[esi]"] }] -66AD;[{ "Type": "LodsW", "Operands": ["ax", "byte ptr es:[esi]"] }] +AC;[{ "Type": "LodsB", "Operands": ["al", "byte ptr ds:[esi]"] }] +AD;[{ "Type": "LodsD", "Operands": ["eax", "dword ptr ds:[esi]"] }] +66AD;[{ "Type": "LodsW", "Operands": ["ax", "byte ptr ds:[esi]"] }] # STOS - Store string AA;[{ "Type": "StosB", "Operands": ["byte ptr es:[edi]", "al"] }]