namespace X86Disassembler.X86.Handlers.String; using Operands; /// /// 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 for 32-bit mode (default) private static readonly Dictionary CreateOperands)> StringInstructions32 = new() { // MOVS instructions { 0xA4, (InstructionType.MovsB, () => [ 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 // 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.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.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.CreateRegisterOperand8(RegisterIndex8.AL), OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Di, "es") ]) }, // SCASB { 0xAF, (InstructionType.ScasD, () => [ OperandFactory.CreateRegisterOperand(RegisterIndex.A, 32), OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 32, "es") ]) } // SCASD }; // 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() { // 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 }; /// /// Initializes a new instance of the StringInstructionHandler class /// /// The instruction decoder that owns this handler public StringInstructionHandler(InstructionDecoder decoder) : base(decoder) { } /// /// Checks if this handler can handle the given opcode /// /// The opcode to check /// True if this handler can handle the opcode public override bool CanHandle(byte opcode) { // Check if the opcode is a string instruction in either 16-bit or 32-bit mode return StringInstructions32.ContainsKey(opcode); } /// /// Decodes a string instruction /// /// The opcode to decode /// The instruction to populate /// True if the instruction was successfully decoded public override bool Decode(byte opcode, Instruction instruction) { // Select the appropriate dictionary based on operand size prefix var instructionsDict = Decoder.HasOperandSizePrefix() ? StringInstructions16 : StringInstructions32; // Get the instruction type and operands for the string instruction if (instructionsDict.TryGetValue(opcode, out var instructionInfo)) { // Set the instruction type instruction.Type = instructionInfo.Type; // Create and set the structured operands instruction.StructuredOperands = instructionInfo.CreateOperands().ToList(); return true; } // This shouldn't happen if CanHandle is called first return false; } }