From 2a8cf9534e5eb44dc0ed574516576317776b5585 Mon Sep 17 00:00:00 2001 From: bird_egop Date: Fri, 18 Apr 2025 01:25:34 +0300 Subject: [PATCH] Fixed floating point comparison handlers for FCOM ST(i) and FCOMP ST(i) instructions --- .../Comparison/FcomFloat32Handler.cs | 3 +- .../{FcomSt0Handler.cs => FcomStHandler.cs} | 48 +++++++------------ .../Comparison/FcompFloat32Handler.cs | 3 +- .../Comparison/FcompStHandler.cs | 31 ++++++------ .../X86/Handlers/InstructionHandlerFactory.cs | 3 +- X86DisassemblerTests/TestData/fcom_tests.csv | 16 +++---- 6 files changed, 47 insertions(+), 57 deletions(-) rename X86Disassembler/X86/Handlers/FloatingPoint/Comparison/{FcomSt0Handler.cs => FcomStHandler.cs} (52%) diff --git a/X86Disassembler/X86/Handlers/FloatingPoint/Comparison/FcomFloat32Handler.cs b/X86Disassembler/X86/Handlers/FloatingPoint/Comparison/FcomFloat32Handler.cs index 8a541b7..576174f 100644 --- a/X86Disassembler/X86/Handlers/FloatingPoint/Comparison/FcomFloat32Handler.cs +++ b/X86Disassembler/X86/Handlers/FloatingPoint/Comparison/FcomFloat32Handler.cs @@ -35,7 +35,8 @@ public class FcomFloat32Handler : InstructionHandler byte modRm = Decoder.PeakByte(); byte reg = (byte)((modRm >> 3) & 0x7); - return reg == 2; + // special handling of modRM for D8 D0+i FCOM ST(i) + return reg == 2 && modRm is < 0xD0 or > 0xD7; } /// diff --git a/X86Disassembler/X86/Handlers/FloatingPoint/Comparison/FcomSt0Handler.cs b/X86Disassembler/X86/Handlers/FloatingPoint/Comparison/FcomStHandler.cs similarity index 52% rename from X86Disassembler/X86/Handlers/FloatingPoint/Comparison/FcomSt0Handler.cs rename to X86Disassembler/X86/Handlers/FloatingPoint/Comparison/FcomStHandler.cs index c93cf0b..afc2b72 100644 --- a/X86Disassembler/X86/Handlers/FloatingPoint/Comparison/FcomSt0Handler.cs +++ b/X86Disassembler/X86/Handlers/FloatingPoint/Comparison/FcomStHandler.cs @@ -3,15 +3,15 @@ namespace X86Disassembler.X86.Handlers.FloatingPoint.Comparison; using X86Disassembler.X86.Operands; /// -/// Handler for FCOM ST(0), ST(i) instruction (D8 D0-D7) +/// Handler for FCOM ST(i) instruction (D8 D0-D7) - compares ST(0) with ST(i) /// -public class FcomSt0Handler : InstructionHandler +public class FcomStHandler : InstructionHandler { /// - /// Initializes a new instance of the FcomSt0Handler class + /// Initializes a new instance of the FcomStHandler class /// /// The instruction decoder that owns this handler - public FcomSt0Handler(InstructionDecoder decoder) + public FcomStHandler(InstructionDecoder decoder) : base(decoder) { } @@ -23,7 +23,7 @@ public class FcomSt0Handler : InstructionHandler /// True if this handler can decode the opcode public override bool CanHandle(byte opcode) { - // FCOM ST(0), ST(i) is D8 D0-D7 + // FCOM ST(i) is D8 D0-D7 (compares ST(0) with ST(i)) if (opcode != 0xD8) return false; if (!Decoder.CanReadByte()) @@ -31,17 +31,17 @@ public class FcomSt0Handler : InstructionHandler return false; } - // Check if the ModR/M byte has reg field = 2 and mod = 3 - byte modRm = Decoder.PeakByte(); - byte reg = (byte)((modRm >> 3) & 0x7); - byte mod = (byte)((modRm >> 6) & 0x3); - - // Only handle register operands (mod = 3) with reg = 2 - return reg == 2 && mod == 3; + var opcodeSecond = Decoder.PeakByte(); + + // this is a special case of a handler, only handling FCOM with ST(i) + if (opcodeSecond < 0xD0 || opcodeSecond > 0xD7) + return false; + + return true; } /// - /// Decodes a FCOM ST(0), ST(i) instruction + /// Decodes a FCOM ST(i) instruction - compares ST(0) with ST(i) /// /// The opcode of the instruction /// The instruction object to populate @@ -52,26 +52,11 @@ public class FcomSt0Handler : InstructionHandler { return false; } - - // Read the ModR/M byte - var (mod, reg, rm, _) = ModRMDecoder.ReadModRMFpu(); + var stIndex = (FpuRegisterIndex)(Decoder.ReadByte() - 0xD0); + // Set the instruction type instruction.Type = InstructionType.Fcom; - - // Map rm field to FPU register index - FpuRegisterIndex stIndex = rm switch - { - FpuRegisterIndex.ST0 => FpuRegisterIndex.ST0, - FpuRegisterIndex.ST1 => FpuRegisterIndex.ST1, - FpuRegisterIndex.ST2 => FpuRegisterIndex.ST2, - FpuRegisterIndex.ST3 => FpuRegisterIndex.ST3, - FpuRegisterIndex.ST4 => FpuRegisterIndex.ST4, - FpuRegisterIndex.ST5 => FpuRegisterIndex.ST5, - FpuRegisterIndex.ST6 => FpuRegisterIndex.ST6, - FpuRegisterIndex.ST7 => FpuRegisterIndex.ST7, - _ => FpuRegisterIndex.ST0 // Default case, should not happen - }; // Create the FPU register operands var st0Operand = OperandFactory.CreateFPURegisterOperand(FpuRegisterIndex.ST0); @@ -80,8 +65,7 @@ public class FcomSt0Handler : InstructionHandler // Set the structured operands instruction.StructuredOperands = [ - st0Operand, - stiOperand + stiOperand // The instruction is FCOM ST(i), which compares ST(0) with ST(i) ]; return true; diff --git a/X86Disassembler/X86/Handlers/FloatingPoint/Comparison/FcompFloat32Handler.cs b/X86Disassembler/X86/Handlers/FloatingPoint/Comparison/FcompFloat32Handler.cs index 0be84e5..0f07eec 100644 --- a/X86Disassembler/X86/Handlers/FloatingPoint/Comparison/FcompFloat32Handler.cs +++ b/X86Disassembler/X86/Handlers/FloatingPoint/Comparison/FcompFloat32Handler.cs @@ -35,7 +35,8 @@ public class FcompFloat32Handler : InstructionHandler byte modRm = Decoder.PeakByte(); byte reg = (byte)((modRm >> 3) & 0x7); - return reg == 3; + // special handling of modRM for D8 D8+i FCOMP ST(i) + return reg == 3 && modRm is < 0xD8 or > 0xDE; } /// diff --git a/X86Disassembler/X86/Handlers/FloatingPoint/Comparison/FcompStHandler.cs b/X86Disassembler/X86/Handlers/FloatingPoint/Comparison/FcompStHandler.cs index 6fb400f..6946fb6 100644 --- a/X86Disassembler/X86/Handlers/FloatingPoint/Comparison/FcompStHandler.cs +++ b/X86Disassembler/X86/Handlers/FloatingPoint/Comparison/FcompStHandler.cs @@ -3,7 +3,7 @@ namespace X86Disassembler.X86.Handlers.FloatingPoint.Comparison; using X86Disassembler.X86.Operands; /// -/// Handler for FCOMP ST(0) instruction (DE D3) +/// Handler for FCOMP ST(i) instruction (D8 D8-DF) - compares ST(0) with ST(i) and pops the register stack /// public class FcompStHandler : InstructionHandler { @@ -23,21 +23,25 @@ public class FcompStHandler : InstructionHandler /// True if this handler can decode the opcode public override bool CanHandle(byte opcode) { - // FCOMP ST(0) is DE D3 - if (opcode != 0xDE) return false; + // FCOMP ST(i) is D8 D8-DF (compares ST(0) with ST(i) and pops the register stack) + if (opcode != 0xD8) return false; if (!Decoder.CanReadByte()) { return false; } - // Check if the ModR/M byte is exactly D3 (reg = 2, rm = 3, mod = 3) - byte modRm = Decoder.PeakByte(); - return modRm == 0xD3; + var opcodeSecond = Decoder.PeakByte(); + + // this is a special case of a handler, only handling FCOMP with ST(i) + if (opcodeSecond < 0xD8 || opcodeSecond > 0xDF) + return false; + + return true; } /// - /// Decodes a FCOMP ST(0) instruction + /// Decodes a FCOMP ST(i) instruction - compares ST(0) with ST(i) and pops the register stack /// /// The opcode of the instruction /// The instruction object to populate @@ -48,20 +52,19 @@ public class FcompStHandler : InstructionHandler { return false; } - - // Read the ModR/M byte - var (mod, reg, rm, _) = ModRMDecoder.ReadModRM(); + var stIndex = (FpuRegisterIndex)(Decoder.ReadByte() - 0xD8); + // Set the instruction type instruction.Type = InstructionType.Fcomp; - - // Create the FPU register operand - var fpuRegisterOperand = OperandFactory.CreateFPURegisterOperand(FpuRegisterIndex.ST0); + + // Create the FPU register operands + var stiOperand = OperandFactory.CreateFPURegisterOperand(stIndex); // Set the structured operands instruction.StructuredOperands = [ - fpuRegisterOperand + stiOperand // The instruction is FCOMP ST(i), which compares ST(0) with ST(i) and pops the register stack ]; return true; diff --git a/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs b/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs index 7ea1957..18a8d3d 100644 --- a/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs +++ b/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs @@ -441,7 +441,8 @@ public class InstructionHandlerFactory // D8 opcode handlers (register operations) _handlers.Add(new FloatingPoint.Arithmetic.FaddRegisterHandler(_decoder)); // FADD ST(0), ST(i) (D8 C0-C7) _handlers.Add(new FloatingPoint.Arithmetic.FmulRegisterHandler(_decoder)); // FMUL ST(0), ST(i) (D8 C8-CF) - _handlers.Add(new FloatingPoint.Comparison.FcomSt0Handler(_decoder)); // FCOM ST(0), ST(i) (D8 D0-D7) + _handlers.Add(new FloatingPoint.Comparison.FcomStHandler(_decoder)); // FCOM ST(i) (D8 D0-D7) + _handlers.Add(new FloatingPoint.Comparison.FcompStHandler(_decoder)); // FCOMP ST(i) (D8 D8-DF) _handlers.Add(new FloatingPoint.Arithmetic.FsubRegisterHandler(_decoder)); // FSUB ST(0), ST(i) (D8 E0-E7) _handlers.Add(new FloatingPoint.Arithmetic.FsubrRegisterHandler(_decoder)); // FSUBR ST(0), ST(i) (D8 E8-EF) _handlers.Add(new FloatingPoint.Arithmetic.FdivRegisterHandler(_decoder)); // FDIV ST(0), ST(i) (D8 F0-F7) diff --git a/X86DisassemblerTests/TestData/fcom_tests.csv b/X86DisassemblerTests/TestData/fcom_tests.csv index dc609e2..4dcfe5c 100644 --- a/X86DisassemblerTests/TestData/fcom_tests.csv +++ b/X86DisassemblerTests/TestData/fcom_tests.csv @@ -15,16 +15,16 @@ D8D7;[{ "Type": "Fcom", "Operands": ["ST(7)"] }] # Memory operands D8142510000000;[{ "Type": "Fcom", "Operands": ["dword ptr [0x10]"] }] DC142510000000;[{ "Type": "Fcom", "Operands": ["qword ptr [0x10]"] }] -D81425;[{ "Type": "Fcom", "Operands": ["dword ptr [eax]"] }] -DC1425;[{ "Type": "Fcom", "Operands": ["qword ptr [eax]"] }] +D810;[{ "Type": "Fcom", "Operands": ["dword ptr [eax]"] }] +DC10;[{ "Type": "Fcom", "Operands": ["qword ptr [eax]"] }] # With segment override prefixes -26D81425;[{ "Type": "Fcom", "Operands": ["dword ptr es:[eax]"] }] -2ED81425;[{ "Type": "Fcom", "Operands": ["dword ptr cs:[eax]"] }] -36D81425;[{ "Type": "Fcom", "Operands": ["dword ptr ss:[eax]"] }] -3ED81425;[{ "Type": "Fcom", "Operands": ["dword ptr ds:[eax]"] }] -64D81425;[{ "Type": "Fcom", "Operands": ["dword ptr fs:[eax]"] }] -65D81425;[{ "Type": "Fcom", "Operands": ["dword ptr gs:[eax]"] }] +26D810;[{ "Type": "Fcom", "Operands": ["dword ptr es:[eax]"] }] +2ED810;[{ "Type": "Fcom", "Operands": ["dword ptr cs:[eax]"] }] +36D810;[{ "Type": "Fcom", "Operands": ["dword ptr ss:[eax]"] }] +3ED810;[{ "Type": "Fcom", "Operands": ["dword ptr ds:[eax]"] }] +64D810;[{ "Type": "Fcom", "Operands": ["dword ptr fs:[eax]"] }] +65D810;[{ "Type": "Fcom", "Operands": ["dword ptr gs:[eax]"] }] # FCOMP - Compare floating point values and pop D8D8;[{ "Type": "Fcomp", "Operands": ["ST(0)"] }]