using X86Disassembler.X86.Operands; namespace X86Disassembler.X86.Handlers.FloatingPoint; /// /// Handler for floating-point load/store int32 and miscellaneous operations (DB opcode) /// public class LoadStoreInt32Handler : InstructionHandler { // Memory operand instruction types for DB opcode - load/store int32, misc private static readonly InstructionType[] MemoryInstructionTypes = [ InstructionType.Fild, // fild dword ptr [r/m] InstructionType.Unknown, // fisttp dword ptr [r/m] (not implemented) InstructionType.Fist, // fist dword ptr [r/m] InstructionType.Fistp, // fistp dword ptr [r/m] InstructionType.Unknown, // (reserved) InstructionType.Fld, // fld extended-precision [r/m] InstructionType.Unknown, // (reserved) InstructionType.Fstp // fstp extended-precision [r/m] ]; // Register-register operations mapping (mod=3) private static readonly Dictionary<(RegisterIndex Reg, RegisterIndex Rm), (InstructionType Type, FpuRegisterIndex DestIndex, FpuRegisterIndex? SrcIndex)> RegisterOperations = new() { // FCMOVNB ST(0), ST(i) { (RegisterIndex.A, RegisterIndex.A), (InstructionType.Fcmovnb, FpuRegisterIndex.ST0, FpuRegisterIndex.ST0) }, { (RegisterIndex.A, RegisterIndex.C), (InstructionType.Fcmovnb, FpuRegisterIndex.ST0, FpuRegisterIndex.ST1) }, { (RegisterIndex.A, RegisterIndex.D), (InstructionType.Fcmovnb, FpuRegisterIndex.ST0, FpuRegisterIndex.ST2) }, { (RegisterIndex.A, RegisterIndex.B), (InstructionType.Fcmovnb, FpuRegisterIndex.ST0, FpuRegisterIndex.ST3) }, { (RegisterIndex.A, RegisterIndex.Sp), (InstructionType.Fcmovnb, FpuRegisterIndex.ST0, FpuRegisterIndex.ST4) }, { (RegisterIndex.A, RegisterIndex.Bp), (InstructionType.Fcmovnb, FpuRegisterIndex.ST0, FpuRegisterIndex.ST5) }, { (RegisterIndex.A, RegisterIndex.Si), (InstructionType.Fcmovnb, FpuRegisterIndex.ST0, FpuRegisterIndex.ST6) }, { (RegisterIndex.A, RegisterIndex.Di), (InstructionType.Fcmovnb, FpuRegisterIndex.ST0, FpuRegisterIndex.ST7) }, // FCMOVNE ST(0), ST(i) { (RegisterIndex.B, RegisterIndex.A), (InstructionType.Fcmovne, FpuRegisterIndex.ST0, FpuRegisterIndex.ST0) }, { (RegisterIndex.B, RegisterIndex.C), (InstructionType.Fcmovne, FpuRegisterIndex.ST0, FpuRegisterIndex.ST1) }, { (RegisterIndex.B, RegisterIndex.D), (InstructionType.Fcmovne, FpuRegisterIndex.ST0, FpuRegisterIndex.ST2) }, { (RegisterIndex.B, RegisterIndex.B), (InstructionType.Fcmovne, FpuRegisterIndex.ST0, FpuRegisterIndex.ST3) }, { (RegisterIndex.B, RegisterIndex.Sp), (InstructionType.Fcmovne, FpuRegisterIndex.ST0, FpuRegisterIndex.ST4) }, { (RegisterIndex.B, RegisterIndex.Bp), (InstructionType.Fcmovne, FpuRegisterIndex.ST0, FpuRegisterIndex.ST5) }, { (RegisterIndex.B, RegisterIndex.Si), (InstructionType.Fcmovne, FpuRegisterIndex.ST0, FpuRegisterIndex.ST6) }, { (RegisterIndex.B, RegisterIndex.Di), (InstructionType.Fcmovne, FpuRegisterIndex.ST0, FpuRegisterIndex.ST7) }, // FCMOVNBE ST(0), ST(i) { (RegisterIndex.C, RegisterIndex.A), (InstructionType.Fcmovnbe, FpuRegisterIndex.ST0, FpuRegisterIndex.ST0) }, { (RegisterIndex.C, RegisterIndex.C), (InstructionType.Fcmovnbe, FpuRegisterIndex.ST0, FpuRegisterIndex.ST1) }, { (RegisterIndex.C, RegisterIndex.D), (InstructionType.Fcmovnbe, FpuRegisterIndex.ST0, FpuRegisterIndex.ST2) }, { (RegisterIndex.C, RegisterIndex.B), (InstructionType.Fcmovnbe, FpuRegisterIndex.ST0, FpuRegisterIndex.ST3) }, { (RegisterIndex.C, RegisterIndex.Sp), (InstructionType.Fcmovnbe, FpuRegisterIndex.ST0, FpuRegisterIndex.ST4) }, { (RegisterIndex.C, RegisterIndex.Bp), (InstructionType.Fcmovnbe, FpuRegisterIndex.ST0, FpuRegisterIndex.ST5) }, { (RegisterIndex.C, RegisterIndex.Si), (InstructionType.Fcmovnbe, FpuRegisterIndex.ST0, FpuRegisterIndex.ST6) }, { (RegisterIndex.C, RegisterIndex.Di), (InstructionType.Fcmovnbe, FpuRegisterIndex.ST0, FpuRegisterIndex.ST7) }, // FCMOVNU ST(0), ST(i) { (RegisterIndex.D, RegisterIndex.A), (InstructionType.Fcmovnu, FpuRegisterIndex.ST0, FpuRegisterIndex.ST0) }, { (RegisterIndex.D, RegisterIndex.C), (InstructionType.Fcmovnu, FpuRegisterIndex.ST0, FpuRegisterIndex.ST1) }, { (RegisterIndex.D, RegisterIndex.D), (InstructionType.Fcmovnu, FpuRegisterIndex.ST0, FpuRegisterIndex.ST2) }, { (RegisterIndex.D, RegisterIndex.B), (InstructionType.Fcmovnu, FpuRegisterIndex.ST0, FpuRegisterIndex.ST3) }, { (RegisterIndex.D, RegisterIndex.Sp), (InstructionType.Fcmovnu, FpuRegisterIndex.ST0, FpuRegisterIndex.ST4) }, { (RegisterIndex.D, RegisterIndex.Bp), (InstructionType.Fcmovnu, FpuRegisterIndex.ST0, FpuRegisterIndex.ST5) }, { (RegisterIndex.D, RegisterIndex.Si), (InstructionType.Fcmovnu, FpuRegisterIndex.ST0, FpuRegisterIndex.ST6) }, { (RegisterIndex.D, RegisterIndex.Di), (InstructionType.Fcmovnu, FpuRegisterIndex.ST0, FpuRegisterIndex.ST7) }, // Special cases { (RegisterIndex.Si, RegisterIndex.C), (InstructionType.Fclex, FpuRegisterIndex.ST0, null) }, // fclex { (RegisterIndex.Si, RegisterIndex.D), (InstructionType.Finit, FpuRegisterIndex.ST0, null) }, // finit // FUCOMI ST(0), ST(i) { (RegisterIndex.Di, RegisterIndex.A), (InstructionType.Fucomi, FpuRegisterIndex.ST0, FpuRegisterIndex.ST0) }, { (RegisterIndex.Di, RegisterIndex.C), (InstructionType.Fucomi, FpuRegisterIndex.ST0, FpuRegisterIndex.ST1) }, { (RegisterIndex.Di, RegisterIndex.D), (InstructionType.Fucomi, FpuRegisterIndex.ST0, FpuRegisterIndex.ST2) }, { (RegisterIndex.Di, RegisterIndex.B), (InstructionType.Fucomi, FpuRegisterIndex.ST0, FpuRegisterIndex.ST3) }, { (RegisterIndex.Di, RegisterIndex.Sp), (InstructionType.Fucomi, FpuRegisterIndex.ST0, FpuRegisterIndex.ST4) }, { (RegisterIndex.Di, RegisterIndex.Bp), (InstructionType.Fucomi, FpuRegisterIndex.ST0, FpuRegisterIndex.ST5) }, { (RegisterIndex.Di, RegisterIndex.Si), (InstructionType.Fucomi, FpuRegisterIndex.ST0, FpuRegisterIndex.ST6) }, { (RegisterIndex.Di, RegisterIndex.Di), (InstructionType.Fucomi, FpuRegisterIndex.ST0, FpuRegisterIndex.ST7) }, // FCOMI ST(0), ST(i) { (RegisterIndex.Sp, RegisterIndex.A), (InstructionType.Fcomi, FpuRegisterIndex.ST0, FpuRegisterIndex.ST0) }, { (RegisterIndex.Sp, RegisterIndex.C), (InstructionType.Fcomi, FpuRegisterIndex.ST0, FpuRegisterIndex.ST1) }, { (RegisterIndex.Sp, RegisterIndex.D), (InstructionType.Fcomi, FpuRegisterIndex.ST0, FpuRegisterIndex.ST2) }, { (RegisterIndex.Sp, RegisterIndex.B), (InstructionType.Fcomi, FpuRegisterIndex.ST0, FpuRegisterIndex.ST3) }, { (RegisterIndex.Sp, RegisterIndex.Sp), (InstructionType.Fcomi, FpuRegisterIndex.ST0, FpuRegisterIndex.ST4) }, { (RegisterIndex.Sp, RegisterIndex.Bp), (InstructionType.Fcomi, FpuRegisterIndex.ST0, FpuRegisterIndex.ST5) }, { (RegisterIndex.Sp, RegisterIndex.Si), (InstructionType.Fcomi, FpuRegisterIndex.ST0, FpuRegisterIndex.ST6) }, { (RegisterIndex.Sp, RegisterIndex.Di), (InstructionType.Fcomi, FpuRegisterIndex.ST0, FpuRegisterIndex.ST7) } }; /// /// Initializes a new instance of the LoadStoreInt32Handler class /// /// The instruction decoder that owns this handler public LoadStoreInt32Handler(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) { return opcode == 0xDB; } /// /// Decodes a floating-point instruction for load/store int32 and miscellaneous operations /// /// 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) { if (!Decoder.CanReadByte()) { return false; } // Read the ModR/M byte var (mod, reg, rm, memoryOperand) = ModRMDecoder.ReadModRM(); // Handle based on addressing mode if (mod != 3) // Memory operand { // Set the instruction type based on the reg field instruction.Type = MemoryInstructionTypes[(int)reg]; // Set the size based on the operation if (reg == RegisterIndex.A || reg == RegisterIndex.C || reg == RegisterIndex.D) // 32-bit integer operations { // Keep the default 32-bit size memoryOperand.Size = 32; } else if (reg == RegisterIndex.Di || reg == RegisterIndex.Bp) // 80-bit extended precision operations { // Set to 80-bit for extended precision memoryOperand.Size = 80; } // Set the structured operands instruction.StructuredOperands = [ memoryOperand ]; } else // Register operand (ST(i)) { // Look up the instruction type in the register operations dictionary if (RegisterOperations.TryGetValue((reg, rm), out var operation)) { instruction.Type = operation.Type; // Create the FPU register operands var destOperand = OperandFactory.CreateFPURegisterOperand(operation.DestIndex); // Set the structured operands if (operation.SrcIndex.HasValue) { var srcOperand = OperandFactory.CreateFPURegisterOperand(operation.SrcIndex.Value); instruction.StructuredOperands = [ destOperand, srcOperand ]; } else { instruction.StructuredOperands = [ destOperand ]; } } else { // Unknown instruction instruction.Type = InstructionType.Unknown; instruction.StructuredOperands = []; } } return true; } }