diff --git a/X86Disassembler/X86/Handlers/FloatingPoint/Float32OperationHandler.cs b/X86Disassembler/X86/Handlers/FloatingPoint/Float32OperationHandler.cs new file mode 100644 index 0000000..0eb961f --- /dev/null +++ b/X86Disassembler/X86/Handlers/FloatingPoint/Float32OperationHandler.cs @@ -0,0 +1,83 @@ +namespace X86Disassembler.X86.Handlers.FloatingPoint; + +/// +/// Handler for floating-point operations on float32 (D8 opcode) +/// +public class Float32OperationHandler : FloatingPointBaseHandler +{ + // D8 opcode - operations on float32 + private static readonly string[] Mnemonics = + [ + "fadd", + "fmul", + "fcom", + "fcomp", + "fsub", + "fsubr", + "fdiv", + "fdivr" + ]; + + /// + /// Initializes a new instance of the Float32OperationHandler class + /// + /// The buffer containing the code to decode + /// The instruction decoder that owns this handler + /// The length of the buffer + public Float32OperationHandler(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 == 0xD8; + } + + /// + /// Decodes a floating-point instruction for float32 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) + { + int position = Decoder.GetPosition(); + + if (position >= Length) + { + return false; + } + + // Read the ModR/M byte + byte modRM = CodeBuffer[position++]; + Decoder.SetPosition(position); + + // Extract the fields from the ModR/M byte + byte mod = (byte) ((modRM & 0xC0) >> 6); + byte reg = (byte) ((modRM & 0x38) >> 3); + byte rm = (byte) (modRM & 0x07); + + // Set the mnemonic based on the opcode and reg field + instruction.Mnemonic = Mnemonics[reg]; + + // For memory operands, set the operand + if (mod != 3) // Memory operand + { + string operand = ModRMDecoder.DecodeModRM(mod, rm, false); + instruction.Operands = $"dword ptr {operand}"; + } + else // Register operand (ST(i)) + { + // For register operands, we need to handle the stack registers + instruction.Operands = $"st(0), st({rm})"; + } + + return true; + } +} \ No newline at end of file diff --git a/X86Disassembler/X86/Handlers/FloatingPoint/Float64OperationHandler.cs b/X86Disassembler/X86/Handlers/FloatingPoint/Float64OperationHandler.cs new file mode 100644 index 0000000..2aceddf --- /dev/null +++ b/X86Disassembler/X86/Handlers/FloatingPoint/Float64OperationHandler.cs @@ -0,0 +1,83 @@ +namespace X86Disassembler.X86.Handlers.FloatingPoint; + +/// +/// Handler for floating-point operations on float64 (DC opcode) +/// +public class Float64OperationHandler : FloatingPointBaseHandler +{ + // DC opcode - operations on float64 + private static readonly string[] Mnemonics = + [ + "fadd", + "fmul", + "fcom", + "fcomp", + "fsub", + "fsubr", + "fdiv", + "fdivr" + ]; + + /// + /// Initializes a new instance of the Float64OperationHandler class + /// + /// The buffer containing the code to decode + /// The instruction decoder that owns this handler + /// The length of the buffer + public Float64OperationHandler(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 == 0xDC; + } + + /// + /// Decodes a floating-point instruction for float64 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) + { + int position = Decoder.GetPosition(); + + if (position >= Length) + { + return false; + } + + // Read the ModR/M byte + byte modRM = CodeBuffer[position++]; + Decoder.SetPosition(position); + + // Extract the fields from the ModR/M byte + byte mod = (byte)((modRM & 0xC0) >> 6); + byte reg = (byte)((modRM & 0x38) >> 3); + byte rm = (byte)(modRM & 0x07); + + // Set the mnemonic based on the opcode and reg field + instruction.Mnemonic = Mnemonics[reg]; + + // For memory operands, set the operand + if (mod != 3) // Memory operand + { + string operand = ModRMDecoder.DecodeModRM(mod, rm, false); + instruction.Operands = $"qword ptr {operand}"; + } + else // Register operand (ST(i)) + { + // For DC C0-DC FF, the operands are reversed: ST(i), ST(0) + instruction.Operands = $"st({rm}), st(0)"; + } + + return true; + } +} diff --git a/X86Disassembler/X86/Handlers/FloatingPoint/FloatingPointBaseHandler.cs b/X86Disassembler/X86/Handlers/FloatingPoint/FloatingPointBaseHandler.cs new file mode 100644 index 0000000..b4040da --- /dev/null +++ b/X86Disassembler/X86/Handlers/FloatingPoint/FloatingPointBaseHandler.cs @@ -0,0 +1,18 @@ +namespace X86Disassembler.X86.Handlers.FloatingPoint; + +/// +/// Base class for floating-point instruction handlers +/// +public abstract class FloatingPointBaseHandler : InstructionHandler +{ + /// + /// Initializes a new instance of the FloatingPointBaseHandler class + /// + /// The buffer containing the code to decode + /// The instruction decoder that owns this handler + /// The length of the buffer + protected FloatingPointBaseHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) + : base(codeBuffer, decoder, length) + { + } +} diff --git a/X86Disassembler/X86/Handlers/FnstswHandler.cs b/X86Disassembler/X86/Handlers/FloatingPoint/FnstswHandler.cs similarity index 97% rename from X86Disassembler/X86/Handlers/FnstswHandler.cs rename to X86Disassembler/X86/Handlers/FloatingPoint/FnstswHandler.cs index 635b75d..9fec71d 100644 --- a/X86Disassembler/X86/Handlers/FnstswHandler.cs +++ b/X86Disassembler/X86/Handlers/FloatingPoint/FnstswHandler.cs @@ -1,4 +1,4 @@ -namespace X86Disassembler.X86.Handlers; +namespace X86Disassembler.X86.Handlers.FloatingPoint; /// /// Handler for FNSTSW instruction (0xDFE0) diff --git a/X86Disassembler/X86/Handlers/FloatingPoint/Int16OperationHandler.cs b/X86Disassembler/X86/Handlers/FloatingPoint/Int16OperationHandler.cs new file mode 100644 index 0000000..e375852 --- /dev/null +++ b/X86Disassembler/X86/Handlers/FloatingPoint/Int16OperationHandler.cs @@ -0,0 +1,128 @@ +namespace X86Disassembler.X86.Handlers.FloatingPoint; + +/// +/// Handler for floating-point operations on int16 (DE opcode) +/// +public class Int16OperationHandler : FloatingPointBaseHandler +{ + // DE opcode - operations on int16 + private static readonly string[] Mnemonics = + [ + "fiadd", + "fimul", + "ficom", + "ficomp", + "fisub", + "fisubr", + "fidiv", + "fidivr" + ]; + + /// + /// Initializes a new instance of the Int16OperationHandler class + /// + /// The buffer containing the code to decode + /// The instruction decoder that owns this handler + /// The length of the buffer + public Int16OperationHandler(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 == 0xDE; + } + + /// + /// Decodes a floating-point instruction for int16 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) + { + int position = Decoder.GetPosition(); + + if (position >= Length) + { + return false; + } + + // Read the ModR/M byte + byte modRM = CodeBuffer[position++]; + Decoder.SetPosition(position); + + // Extract the fields from the ModR/M byte + byte mod = (byte) ((modRM & 0xC0) >> 6); + byte reg = (byte) ((modRM & 0x38) >> 3); + byte rm = (byte) (modRM & 0x07); + + // Set the mnemonic based on the opcode and reg field + instruction.Mnemonic = Mnemonics[reg]; + + // For memory operands, set the operand + if (mod != 3) // Memory operand + { + string operand = ModRMDecoder.DecodeModRM(mod, rm, false); + instruction.Operands = $"word ptr {operand}"; + } + else // Register operand (ST(i)) + { + // Special handling for register-register operations + if (reg == 0) // FADDP + { + instruction.Mnemonic = "faddp"; + instruction.Operands = $"st({rm}), st(0)"; + } + else if (reg == 1) // FMULP + { + instruction.Mnemonic = "fmulp"; + instruction.Operands = $"st({rm}), st(0)"; + } + else if (reg == 2 && rm == 1) // FCOMP + { + instruction.Mnemonic = "fcomp"; + instruction.Operands = ""; + } + else if (reg == 3 && rm == 1) // FCOMPP + { + instruction.Mnemonic = "fcompp"; + instruction.Operands = ""; + } + else if (reg == 4) // FSUBP + { + instruction.Mnemonic = "fsubp"; + instruction.Operands = $"st({rm}), st(0)"; + } + else if (reg == 5) // FSUBRP + { + instruction.Mnemonic = "fsubrp"; + instruction.Operands = $"st({rm}), st(0)"; + } + else if (reg == 6) // FDIVP + { + instruction.Mnemonic = "fdivp"; + instruction.Operands = $"st({rm}), st(0)"; + } + else if (reg == 7) // FDIVRP + { + instruction.Mnemonic = "fdivrp"; + instruction.Operands = $"st({rm}), st(0)"; + } + else + { + // Unknown instruction + instruction.Mnemonic = "??"; + instruction.Operands = ""; + } + } + + return true; + } +} \ No newline at end of file diff --git a/X86Disassembler/X86/Handlers/FloatingPoint/Int32OperationHandler.cs b/X86Disassembler/X86/Handlers/FloatingPoint/Int32OperationHandler.cs new file mode 100644 index 0000000..9776071 --- /dev/null +++ b/X86Disassembler/X86/Handlers/FloatingPoint/Int32OperationHandler.cs @@ -0,0 +1,113 @@ +namespace X86Disassembler.X86.Handlers.FloatingPoint; + +/// +/// Handler for floating-point operations on int32 (DA opcode) +/// +public class Int32OperationHandler : FloatingPointBaseHandler +{ + // DA opcode - operations on int32 + private static readonly string[] Mnemonics = + { + "fiadd", + "fimul", + "ficom", + "ficomp", + "fisub", + "fisubr", + "fidiv", + "fidivr", + }; + + /// + /// Initializes a new instance of the Int32OperationHandler class + /// + /// The buffer containing the code to decode + /// The instruction decoder that owns this handler + /// The length of the buffer + public Int32OperationHandler(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 == 0xDA; + } + + /// + /// Decodes a floating-point instruction for int32 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) + { + int position = Decoder.GetPosition(); + + if (position >= Length) + { + return false; + } + + // Read the ModR/M byte + byte modRM = CodeBuffer[position++]; + Decoder.SetPosition(position); + + // Extract the fields from the ModR/M byte + byte mod = (byte) ((modRM & 0xC0) >> 6); + byte reg = (byte) ((modRM & 0x38) >> 3); + byte rm = (byte) (modRM & 0x07); + + // Set the mnemonic based on the opcode and reg field + instruction.Mnemonic = Mnemonics[reg]; + + // For memory operands, set the operand + if (mod != 3) // Memory operand + { + string operand = ModRMDecoder.DecodeModRM(mod, rm, false); + instruction.Operands = $"dword ptr {operand}"; + } + else // Register operand (ST(i)) + { + // Special handling for register-register operations + if (reg == 0) // FCMOVB + { + instruction.Mnemonic = "fcmovb"; + instruction.Operands = $"st(0), st({rm})"; + } + else if (reg == 1) // FCMOVE + { + instruction.Mnemonic = "fcmove"; + instruction.Operands = $"st(0), st({rm})"; + } + else if (reg == 2) // FCMOVBE + { + instruction.Mnemonic = "fcmovbe"; + instruction.Operands = $"st(0), st({rm})"; + } + else if (reg == 3) // FCMOVU + { + instruction.Mnemonic = "fcmovu"; + instruction.Operands = $"st(0), st({rm})"; + } + else if (reg == 5 && rm == 1) // FUCOMPP + { + instruction.Mnemonic = "fucompp"; + instruction.Operands = ""; + } + else + { + // Unknown instruction + instruction.Mnemonic = "??"; + instruction.Operands = ""; + } + } + + return true; + } +} \ No newline at end of file diff --git a/X86Disassembler/X86/Handlers/FloatingPoint/LoadStoreControlHandler.cs b/X86Disassembler/X86/Handlers/FloatingPoint/LoadStoreControlHandler.cs new file mode 100644 index 0000000..dfbe247 --- /dev/null +++ b/X86Disassembler/X86/Handlers/FloatingPoint/LoadStoreControlHandler.cs @@ -0,0 +1,213 @@ +namespace X86Disassembler.X86.Handlers.FloatingPoint; + +/// +/// Handler for floating-point load, store, and control operations (D9 opcode) +/// +public class LoadStoreControlHandler : FloatingPointBaseHandler +{ + // D9 opcode - load, store, and control operations + private static readonly string[] Mnemonics = + [ + "fld", + "??", + "fst", + "fstp", + "fldenv", + "fldcw", + "fnstenv", + "fnstcw" + ]; + + /// + /// Initializes a new instance of the LoadStoreControlHandler class + /// + /// The buffer containing the code to decode + /// The instruction decoder that owns this handler + /// The length of the buffer + public LoadStoreControlHandler(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 == 0xD9; + } + + /// + /// Decodes a floating-point instruction for load, store, and control 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) + { + int position = Decoder.GetPosition(); + + if (position >= Length) + { + return false; + } + + // Read the ModR/M byte + byte modRM = CodeBuffer[position++]; + Decoder.SetPosition(position); + + // Extract the fields from the ModR/M byte + byte mod = (byte)((modRM & 0xC0) >> 6); + byte reg = (byte)((modRM & 0x38) >> 3); + byte rm = (byte)(modRM & 0x07); + + // Set the mnemonic based on the opcode and reg field + instruction.Mnemonic = Mnemonics[reg]; + + // For memory operands, set the operand + if (mod != 3) // Memory operand + { + string operand = ModRMDecoder.DecodeModRM(mod, rm, false); + + // Different operand types based on the instruction + if (reg == 0 || reg == 2 || reg == 3) // fld, fst, fstp + { + instruction.Operands = $"dword ptr {operand}"; + } + else // fldenv, fldcw, fnstenv, fnstcw + { + instruction.Operands = operand; + } + } + else // Register operand (ST(i)) + { + // Special handling for D9C0-D9FF (register-register operations) + if (reg == 0) // FLD ST(i) + { + instruction.Operands = $"st({rm})"; + } + else if (reg == 1) // FXCH ST(i) + { + instruction.Mnemonic = "fxch"; + instruction.Operands = $"st({rm})"; + } + else if (reg == 4) + { + // D9E0-D9EF special instructions + switch (rm) + { + case 0: + instruction.Mnemonic = "fchs"; + instruction.Operands = ""; + break; + case 1: + instruction.Mnemonic = "fabs"; + instruction.Operands = ""; + break; + case 4: + instruction.Mnemonic = "ftst"; + instruction.Operands = ""; + break; + case 5: + instruction.Mnemonic = "fxam"; + instruction.Operands = ""; + break; + default: + instruction.Mnemonic = "??"; + instruction.Operands = ""; + break; + } + } + else if (reg == 5) + { + // D9F0-D9FF special instructions + switch (rm) + { + case 0: + instruction.Mnemonic = "f2xm1"; + instruction.Operands = ""; + break; + case 1: + instruction.Mnemonic = "fyl2x"; + instruction.Operands = ""; + break; + case 2: + instruction.Mnemonic = "fptan"; + instruction.Operands = ""; + break; + case 3: + instruction.Mnemonic = "fpatan"; + instruction.Operands = ""; + break; + case 4: + instruction.Mnemonic = "fxtract"; + instruction.Operands = ""; + break; + case 5: + instruction.Mnemonic = "fprem1"; + instruction.Operands = ""; + break; + case 6: + instruction.Mnemonic = "fdecstp"; + instruction.Operands = ""; + break; + case 7: + instruction.Mnemonic = "fincstp"; + instruction.Operands = ""; + break; + default: + instruction.Mnemonic = "??"; + instruction.Operands = ""; + break; + } + } + else if (reg == 6) + { + // D9F0-D9FF more special instructions + switch (rm) + { + case 0: + instruction.Mnemonic = "fprem"; + instruction.Operands = ""; + break; + case 1: + instruction.Mnemonic = "fyl2xp1"; + instruction.Operands = ""; + break; + case 2: + instruction.Mnemonic = "fsqrt"; + instruction.Operands = ""; + break; + case 3: + instruction.Mnemonic = "fsincos"; + instruction.Operands = ""; + break; + case 4: + instruction.Mnemonic = "frndint"; + instruction.Operands = ""; + break; + case 5: + instruction.Mnemonic = "fscale"; + instruction.Operands = ""; + break; + case 6: + instruction.Mnemonic = "fsin"; + instruction.Operands = ""; + break; + case 7: + instruction.Mnemonic = "fcos"; + instruction.Operands = ""; + break; + default: + instruction.Mnemonic = "??"; + instruction.Operands = ""; + break; + } + } + } + + return true; + } +} diff --git a/X86Disassembler/X86/Handlers/FloatingPoint/LoadStoreFloat64Handler.cs b/X86Disassembler/X86/Handlers/FloatingPoint/LoadStoreFloat64Handler.cs new file mode 100644 index 0000000..e760a27 --- /dev/null +++ b/X86Disassembler/X86/Handlers/FloatingPoint/LoadStoreFloat64Handler.cs @@ -0,0 +1,120 @@ +namespace X86Disassembler.X86.Handlers.FloatingPoint; + +/// +/// Handler for floating-point load/store float64 operations (DD opcode) +/// +public class LoadStoreFloat64Handler : FloatingPointBaseHandler +{ + // DD opcode - load/store float64 + private static readonly string[] Mnemonics = + [ + "fld", + "??", + "fst", + "fstp", + "frstor", + "fnsave", + "fnstsw" + ]; + + /// + /// Initializes a new instance of the LoadStoreFloat64Handler class + /// + /// The buffer containing the code to decode + /// The instruction decoder that owns this handler + /// The length of the buffer + public LoadStoreFloat64Handler(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 == 0xDD; + } + + /// + /// Decodes a floating-point instruction for load/store float64 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) + { + int position = Decoder.GetPosition(); + + if (position >= Length) + { + return false; + } + + // Read the ModR/M byte + byte modRM = CodeBuffer[position++]; + Decoder.SetPosition(position); + + // Extract the fields from the ModR/M byte + byte mod = (byte) ((modRM & 0xC0) >> 6); + byte reg = (byte) ((modRM & 0x38) >> 3); + byte rm = (byte) (modRM & 0x07); + + // Set the mnemonic based on the opcode and reg field + instruction.Mnemonic = Mnemonics[reg]; + + // For memory operands, set the operand + if (mod != 3) // Memory operand + { + string operand = ModRMDecoder.DecodeModRM(mod, rm, false); + + if (reg == 0 || reg == 2 || reg == 3) // fld, fst, fstp + { + instruction.Operands = $"qword ptr {operand}"; + } + else // frstor, fnsave, fnstsw + { + instruction.Operands = operand; + } + } + else // Register operand (ST(i)) + { + // Special handling for register-register operations + if (reg == 0) // FFREE + { + instruction.Mnemonic = "ffree"; + instruction.Operands = $"st({rm})"; + } + else if (reg == 2) // FST + { + instruction.Mnemonic = "fst"; + instruction.Operands = $"st({rm})"; + } + else if (reg == 3) // FSTP + { + instruction.Mnemonic = "fstp"; + instruction.Operands = $"st({rm})"; + } + else if (reg == 4) // FUCOM + { + instruction.Mnemonic = "fucom"; + instruction.Operands = $"st({rm})"; + } + else if (reg == 5) // FUCOMP + { + instruction.Mnemonic = "fucomp"; + instruction.Operands = $"st({rm})"; + } + else + { + // Unknown instruction + instruction.Mnemonic = "??"; + instruction.Operands = ""; + } + } + + return true; + } +} \ No newline at end of file diff --git a/X86Disassembler/X86/Handlers/FloatingPoint/LoadStoreInt16Handler.cs b/X86Disassembler/X86/Handlers/FloatingPoint/LoadStoreInt16Handler.cs new file mode 100644 index 0000000..1b420dc --- /dev/null +++ b/X86Disassembler/X86/Handlers/FloatingPoint/LoadStoreInt16Handler.cs @@ -0,0 +1,150 @@ +namespace X86Disassembler.X86.Handlers.FloatingPoint; + +/// +/// Handler for floating-point load/store int16 and miscellaneous operations (DF opcode) +/// +public class LoadStoreInt16Handler : FloatingPointBaseHandler +{ + // DF opcode - load/store int16, misc + private static readonly string[] Mnemonics = + [ + "fild", + "??", + "fist", + "fistp", + "fbld", + "fild", + "fbstp", + "fistp" + ]; + + /// + /// Initializes a new instance of the LoadStoreInt16Handler class + /// + /// The buffer containing the code to decode + /// The instruction decoder that owns this handler + /// The length of the buffer + public LoadStoreInt16Handler(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 == 0xDF; + } + + /// + /// Decodes a floating-point instruction for load/store int16 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) + { + int position = Decoder.GetPosition(); + + if (position >= Length) + { + return false; + } + + // Read the ModR/M byte + byte modRM = CodeBuffer[position++]; + Decoder.SetPosition(position); + + // Extract the fields from the ModR/M byte + byte mod = (byte) ((modRM & 0xC0) >> 6); + byte reg = (byte) ((modRM & 0x38) >> 3); + byte rm = (byte) (modRM & 0x07); + + // Check for FNSTSW AX (DF E0) + if (mod == 3 && reg == 7 && rm == 0) + { + // This is handled by the FnstswHandler, so we should not handle it here + return false; + } + + // Set the mnemonic based on the opcode and reg field + instruction.Mnemonic = Mnemonics[reg]; + + // For memory operands, set the operand + if (mod != 3) // Memory operand + { + string operand = ModRMDecoder.DecodeModRM(mod, rm, false); + + if (reg == 0 || reg == 2 || reg == 3 || reg == 5 || reg == 7) // fild, fist, fistp, fild, fistp + { + if (reg == 5 || reg == 7) // 64-bit integer + { + instruction.Operands = $"qword ptr {operand}"; + } + else // 16-bit integer + { + instruction.Operands = $"word ptr {operand}"; + } + } + else if (reg == 4 || reg == 6) // fbld, fbstp + { + instruction.Operands = $"tbyte ptr {operand}"; + } + else + { + instruction.Operands = operand; + } + } + else // Register operand (ST(i)) + { + // Special handling for register-register operations + if (reg == 0) // FFREEP + { + instruction.Mnemonic = "ffreep"; + instruction.Operands = $"st({rm})"; + } + else if (reg == 1 && rm == 0) // FXCH + { + instruction.Mnemonic = "fxch"; + instruction.Operands = ""; + } + else if (reg == 2 && rm == 0) // FSTP + { + instruction.Mnemonic = "fstp"; + instruction.Operands = "st(1)"; + } + else if (reg == 3 && rm == 0) // FSTP + { + instruction.Mnemonic = "fstp"; + instruction.Operands = "st(1)"; + } + else if (reg == 4) // FNSTSW + { + // This should not happen as FNSTSW AX is handled by FnstswHandler + instruction.Mnemonic = "??"; + instruction.Operands = ""; + } + else if (reg == 5) // FUCOMIP + { + instruction.Mnemonic = "fucomip"; + instruction.Operands = $"st(0), st({rm})"; + } + else if (reg == 6) // FCOMIP + { + instruction.Mnemonic = "fcomip"; + instruction.Operands = $"st(0), st({rm})"; + } + else + { + // Unknown instruction + instruction.Mnemonic = "??"; + instruction.Operands = ""; + } + } + + return true; + } +} \ No newline at end of file diff --git a/X86Disassembler/X86/Handlers/FloatingPoint/LoadStoreInt32Handler.cs b/X86Disassembler/X86/Handlers/FloatingPoint/LoadStoreInt32Handler.cs new file mode 100644 index 0000000..eb7974b --- /dev/null +++ b/X86Disassembler/X86/Handlers/FloatingPoint/LoadStoreInt32Handler.cs @@ -0,0 +1,148 @@ +namespace X86Disassembler.X86.Handlers.FloatingPoint; + +/// +/// Handler for floating-point load/store int32 and miscellaneous operations (DB opcode) +/// +public class LoadStoreInt32Handler : FloatingPointBaseHandler +{ + // DB opcode - load/store int32, misc + private static readonly string[] Mnemonics = + [ + "fild", + "??", + "fist", + "fistp", + "??", + "fld", + "??", + "fstp", + ]; + + /// + /// Initializes a new instance of the LoadStoreInt32Handler class + /// + /// The buffer containing the code to decode + /// The instruction decoder that owns this handler + /// The length of the buffer + public LoadStoreInt32Handler(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 == 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) + { + int position = Decoder.GetPosition(); + + if (position >= Length) + { + return false; + } + + // Read the ModR/M byte + byte modRM = CodeBuffer[position++]; + Decoder.SetPosition(position); + + // Extract the fields from the ModR/M byte + byte mod = (byte) ((modRM & 0xC0) >> 6); + byte reg = (byte) ((modRM & 0x38) >> 3); + byte rm = (byte) (modRM & 0x07); + + // Set the mnemonic based on the opcode and reg field + instruction.Mnemonic = Mnemonics[reg]; + + // For memory operands, set the operand + if (mod != 3) // Memory operand + { + string operand = ModRMDecoder.DecodeModRM(mod, rm, false); + + if (reg == 0 || reg == 2 || reg == 3) // fild, fist, fistp + { + instruction.Operands = $"dword ptr {operand}"; + } + else if (reg == 5 || reg == 7) // fld, fstp (extended precision) + { + instruction.Operands = $"tword ptr {operand}"; + } + else + { + instruction.Operands = operand; + } + } + else // Register operand (ST(i)) + { + // Special handling for register-register operations + if (reg == 0) // FCMOVNB + { + instruction.Mnemonic = "fcmovnb"; + instruction.Operands = $"st(0), st({rm})"; + } + else if (reg == 1) // FCMOVNE + { + instruction.Mnemonic = "fcmovne"; + instruction.Operands = $"st(0), st({rm})"; + } + else if (reg == 2) // FCMOVNBE + { + instruction.Mnemonic = "fcmovnbe"; + instruction.Operands = $"st(0), st({rm})"; + } + else if (reg == 3) // FCMOVNU + { + instruction.Mnemonic = "fcmovnu"; + instruction.Operands = $"st(0), st({rm})"; + } + else if (reg == 4) + { + if (rm == 2) // FCLEX + { + instruction.Mnemonic = "fclex"; + instruction.Operands = ""; + } + else if (rm == 3) // FINIT + { + instruction.Mnemonic = "finit"; + instruction.Operands = ""; + } + else + { + instruction.Mnemonic = "??"; + instruction.Operands = ""; + } + } + else if (reg == 5) // FUCOMI + { + instruction.Mnemonic = "fucomi"; + instruction.Operands = $"st(0), st({rm})"; + } + else if (reg == 6) // FCOMI + { + instruction.Mnemonic = "fcomi"; + instruction.Operands = $"st(0), st({rm})"; + } + else + { + // Unknown instruction + instruction.Mnemonic = "??"; + instruction.Operands = ""; + } + } + + return true; + } +} \ No newline at end of file diff --git a/X86Disassembler/X86/Handlers/FloatingPointHandler.cs b/X86Disassembler/X86/Handlers/FloatingPointHandler.cs deleted file mode 100644 index 9902f48..0000000 --- a/X86Disassembler/X86/Handlers/FloatingPointHandler.cs +++ /dev/null @@ -1,167 +0,0 @@ -namespace X86Disassembler.X86.Handlers; - -/// -/// Handler for floating-point instructions (D8-DF opcodes) -/// -public class FloatingPointHandler : InstructionHandler -{ - // Floating-point instruction mnemonics based on opcode and ModR/M reg field - private static readonly string[][] FpuMnemonics = new string[8][]; - - /// - /// Static constructor to initialize the FPU mnemonic tables - /// - static FloatingPointHandler() - { - InitializeFpuMnemonics(); - } - - /// - /// Initializes the FPU mnemonic tables - /// - private static void InitializeFpuMnemonics() - { - // Initialize all tables - for (int i = 0; i < 8; i++) - { - FpuMnemonics[i] = new string[8]; - for (int j = 0; j < 8; j++) - { - FpuMnemonics[i][j] = "??"; - } - } - - // D8 opcode - operations on float32 - FpuMnemonics[0][0] = "fadd"; - FpuMnemonics[0][1] = "fmul"; - FpuMnemonics[0][2] = "fcom"; - FpuMnemonics[0][3] = "fcomp"; - FpuMnemonics[0][4] = "fsub"; - FpuMnemonics[0][5] = "fsubr"; - FpuMnemonics[0][6] = "fdiv"; - FpuMnemonics[0][7] = "fdivr"; - - // D9 opcode - load, store, and control operations - FpuMnemonics[1][0] = "fld"; - FpuMnemonics[1][2] = "fst"; - FpuMnemonics[1][3] = "fstp"; - FpuMnemonics[1][4] = "fldenv"; - FpuMnemonics[1][5] = "fldcw"; - FpuMnemonics[1][6] = "fnstenv"; - FpuMnemonics[1][7] = "fnstcw"; - - // DA opcode - operations on int32 - FpuMnemonics[2][0] = "fiadd"; - FpuMnemonics[2][1] = "fimul"; - FpuMnemonics[2][2] = "ficom"; - FpuMnemonics[2][3] = "ficomp"; - FpuMnemonics[2][4] = "fisub"; - FpuMnemonics[2][5] = "fisubr"; - FpuMnemonics[2][6] = "fidiv"; - FpuMnemonics[2][7] = "fidivr"; - - // DB opcode - load/store int32, misc - FpuMnemonics[3][0] = "fild"; - FpuMnemonics[3][2] = "fist"; - FpuMnemonics[3][3] = "fistp"; - FpuMnemonics[3][5] = "fld"; - FpuMnemonics[3][7] = "fstp"; - - // DC opcode - operations on float64 - FpuMnemonics[4][0] = "fadd"; - FpuMnemonics[4][1] = "fmul"; - FpuMnemonics[4][2] = "fcom"; - FpuMnemonics[4][3] = "fcomp"; - FpuMnemonics[4][4] = "fsub"; - FpuMnemonics[4][5] = "fsubr"; - FpuMnemonics[4][6] = "fdiv"; - FpuMnemonics[4][7] = "fdivr"; - - // DD opcode - load/store float64 - FpuMnemonics[5][0] = "fld"; - FpuMnemonics[5][2] = "fst"; - FpuMnemonics[5][3] = "fstp"; - FpuMnemonics[5][4] = "frstor"; - FpuMnemonics[5][6] = "fnsave"; - FpuMnemonics[5][7] = "fnstsw"; - - // DE opcode - operations on int16 - FpuMnemonics[6][0] = "fiadd"; - FpuMnemonics[6][1] = "fimul"; - FpuMnemonics[6][2] = "ficom"; - FpuMnemonics[6][3] = "ficomp"; - FpuMnemonics[6][4] = "fisub"; - FpuMnemonics[6][5] = "fisubr"; - FpuMnemonics[6][6] = "fidiv"; - FpuMnemonics[6][7] = "fidivr"; - - // DF opcode - load/store int16, misc - FpuMnemonics[7][0] = "fild"; - FpuMnemonics[7][2] = "fist"; - FpuMnemonics[7][3] = "fistp"; - FpuMnemonics[7][4] = "fbld"; - FpuMnemonics[7][5] = "fild"; - FpuMnemonics[7][6] = "fbstp"; - FpuMnemonics[7][7] = "fistp"; - } - - /// - /// Initializes a new instance of the FloatingPointHandler class - /// - /// The buffer containing the code to decode - /// The instruction decoder that owns this handler - /// The length of the buffer - public FloatingPointHandler(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 >= 0xD8 && opcode <= 0xDF; - } - - /// - /// Decodes a floating-point 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) - { - int position = Decoder.GetPosition(); - - if (position >= Length) - { - return false; - } - - // The opcode index in our tables (0-7 for D8-DF) - int opcodeIndex = opcode - 0xD8; - - // Read the ModR/M byte - var (mod, reg, rm, operand) = ModRMDecoder.ReadModRM(opcodeIndex == 7); // DF uses 64-bit operands - - // Set the mnemonic based on the opcode and reg field - instruction.Mnemonic = FpuMnemonics[opcodeIndex][reg]; - - // For memory operands, set the operand - if (mod != 3) // Memory operand - { - instruction.Operands = operand; - } - else // Register operand (ST(i)) - { - // For register operands, we need to handle the stack registers - // This is a simplified implementation and may need to be expanded - instruction.Operands = $"st({rm})"; - } - - return true; - } -} diff --git a/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs b/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs index 5a17c85..e49643d 100644 --- a/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs +++ b/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs @@ -1,4 +1,5 @@ using X86Disassembler.X86.Handlers.Call; +using X86Disassembler.X86.Handlers.FloatingPoint; using X86Disassembler.X86.Handlers.Group1; using X86Disassembler.X86.Handlers.Group3; using X86Disassembler.X86.Handlers.Jump; @@ -68,8 +69,7 @@ public class InstructionHandlerFactory RegisterDataTransferHandlers(); // Register floating point handlers - _handlers.Add(new FnstswHandler(_codeBuffer, _decoder, _length)); - _handlers.Add(new FloatingPointHandler(_codeBuffer, _decoder, _length)); + RegisterFloatingPointHandlers(); } /// @@ -220,6 +220,23 @@ public class InstructionHandlerFactory _handlers.Add(new XchgEaxRegHandler(_codeBuffer, _decoder, _length)); } + /// + /// Registers all Floating Point instruction handlers + /// + private void RegisterFloatingPointHandlers() + { + // Add Floating Point handlers + _handlers.Add(new FnstswHandler(_codeBuffer, _decoder, _length)); + _handlers.Add(new Float32OperationHandler(_codeBuffer, _decoder, _length)); + _handlers.Add(new LoadStoreControlHandler(_codeBuffer, _decoder, _length)); + _handlers.Add(new Int32OperationHandler(_codeBuffer, _decoder, _length)); + _handlers.Add(new LoadStoreInt32Handler(_codeBuffer, _decoder, _length)); + _handlers.Add(new Float64OperationHandler(_codeBuffer, _decoder, _length)); + _handlers.Add(new LoadStoreFloat64Handler(_codeBuffer, _decoder, _length)); + _handlers.Add(new Int16OperationHandler(_codeBuffer, _decoder, _length)); + _handlers.Add(new LoadStoreInt16Handler(_codeBuffer, _decoder, _length)); + } + /// /// Gets the handler that can decode the given opcode /// diff --git a/X86Disassembler/X86/Handlers/Test/TestRegMem8Handler.cs b/X86Disassembler/X86/Handlers/Test/TestRegMem8Handler.cs index c7f28bc..6ee011b 100644 --- a/X86Disassembler/X86/Handlers/Test/TestRegMem8Handler.cs +++ b/X86Disassembler/X86/Handlers/Test/TestRegMem8Handler.cs @@ -5,9 +5,6 @@ namespace X86Disassembler.X86.Handlers.Test; /// public class TestRegMem8Handler : InstructionHandler { - // ModR/M decoder - private readonly ModRMDecoder _modRMDecoder; - /// /// Initializes a new instance of the TestRegMem8Handler class /// @@ -17,7 +14,6 @@ public class TestRegMem8Handler : InstructionHandler public TestRegMem8Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(codeBuffer, decoder, length) { - _modRMDecoder = new ModRMDecoder(codeBuffer, decoder, length); } /// @@ -73,7 +69,7 @@ public class TestRegMem8Handler : InstructionHandler else { // Decode the memory operand - string memOperand = _modRMDecoder.DecodeModRM(mod, rm, true); + string memOperand = ModRMDecoder.DecodeModRM(mod, rm, true); // Get the register name string regReg = GetRegister8(reg); @@ -84,15 +80,4 @@ public class TestRegMem8Handler : InstructionHandler return true; } - - /// - /// Gets the 8-bit register name for the given register index - /// - /// The register index - /// The register name - private static string GetRegister8(byte reg) - { - string[] registerNames = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" }; - return registerNames[reg & 0x07]; - } } diff --git a/X86Disassembler/X86/Handlers/Test/TestRegMemHandler.cs b/X86Disassembler/X86/Handlers/Test/TestRegMemHandler.cs index 1ab8e90..69c5c1a 100644 --- a/X86Disassembler/X86/Handlers/Test/TestRegMemHandler.cs +++ b/X86Disassembler/X86/Handlers/Test/TestRegMemHandler.cs @@ -5,9 +5,6 @@ namespace X86Disassembler.X86.Handlers.Test; /// public class TestRegMemHandler : InstructionHandler { - // ModR/M decoder - private readonly ModRMDecoder _modRMDecoder; - /// /// Initializes a new instance of the TestRegMemHandler class /// @@ -17,7 +14,6 @@ public class TestRegMemHandler : InstructionHandler public TestRegMemHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(codeBuffer, decoder, length) { - _modRMDecoder = new ModRMDecoder(codeBuffer, decoder, length); } /// @@ -73,7 +69,7 @@ public class TestRegMemHandler : InstructionHandler else { // Decode the memory operand - string memOperand = _modRMDecoder.DecodeModRM(mod, rm, false); + string memOperand = ModRMDecoder.DecodeModRM(mod, rm, false); // Get the register name string regReg = GetRegister32(reg); @@ -84,15 +80,4 @@ public class TestRegMemHandler : InstructionHandler return true; } - - /// - /// Gets the 32-bit register name for the given register index - /// - /// The register index - /// The register name - private static string GetRegister32(byte reg) - { - string[] registerNames = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" }; - return registerNames[reg & 0x07]; - } } diff --git a/X86Disassembler/X86/Handlers/Xor/XorMemRegHandler.cs b/X86Disassembler/X86/Handlers/Xor/XorMemRegHandler.cs index 8cb0cd4..2dea822 100644 --- a/X86Disassembler/X86/Handlers/Xor/XorMemRegHandler.cs +++ b/X86Disassembler/X86/Handlers/Xor/XorMemRegHandler.cs @@ -5,9 +5,6 @@ namespace X86Disassembler.X86.Handlers.Xor; /// public class XorMemRegHandler : InstructionHandler { - // ModR/M decoder - private readonly ModRMDecoder _modRMDecoder; - /// /// Initializes a new instance of the XorMemRegHandler class /// @@ -17,7 +14,6 @@ public class XorMemRegHandler : InstructionHandler public XorMemRegHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(codeBuffer, decoder, length) { - _modRMDecoder = new ModRMDecoder(codeBuffer, decoder, length); } /// @@ -58,7 +54,7 @@ public class XorMemRegHandler : InstructionHandler byte rm = (byte)(modRM & 0x07); // Decode the destination operand - string destOperand = _modRMDecoder.DecodeModRM(mod, rm, false); + string destOperand = ModRMDecoder.DecodeModRM(mod, rm, false); // Get the source register string srcReg = GetRegister32(reg); @@ -68,15 +64,4 @@ public class XorMemRegHandler : InstructionHandler return true; } - - /// - /// Gets the 32-bit register name for the given register index - /// - /// The register index - /// The register name - private static string GetRegister32(byte reg) - { - string[] registerNames = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" }; - return registerNames[reg & 0x07]; - } } diff --git a/X86Disassembler/X86/Handlers/Xor/XorRegMemHandler.cs b/X86Disassembler/X86/Handlers/Xor/XorRegMemHandler.cs index 10e1604..183297d 100644 --- a/X86Disassembler/X86/Handlers/Xor/XorRegMemHandler.cs +++ b/X86Disassembler/X86/Handlers/Xor/XorRegMemHandler.cs @@ -5,9 +5,6 @@ namespace X86Disassembler.X86.Handlers.Xor; /// public class XorRegMemHandler : InstructionHandler { - // ModR/M decoder - private readonly ModRMDecoder _modRMDecoder; - /// /// Initializes a new instance of the XorRegMemHandler class /// @@ -17,7 +14,6 @@ public class XorRegMemHandler : InstructionHandler public XorRegMemHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(codeBuffer, decoder, length) { - _modRMDecoder = new ModRMDecoder(codeBuffer, decoder, length); } /// @@ -58,7 +54,7 @@ public class XorRegMemHandler : InstructionHandler byte rm = (byte)(modRM & 0x07); // Decode the source operand - string srcOperand = _modRMDecoder.DecodeModRM(mod, rm, false); + string srcOperand = ModRMDecoder.DecodeModRM(mod, rm, false); // Get the destination register string destReg = GetRegister32(reg); @@ -68,15 +64,4 @@ public class XorRegMemHandler : InstructionHandler return true; } - - /// - /// Gets the 32-bit register name for the given register index - /// - /// The register index - /// The register name - private static string GetRegister32(byte reg) - { - string[] registerNames = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" }; - return registerNames[reg & 0x07]; - } }