0
mirror of https://github.com/sampletext32/ParkanPlayground.git synced 2025-05-19 03:41:18 +03:00

Updated instruction handlers to use Type and StructuredOperands instead of Mnemonic and Operands

This commit is contained in:
bird_egop 2025-04-14 22:08:50 +03:00
parent c516e063e7
commit 685eeda03d
136 changed files with 3694 additions and 2584 deletions

View File

@ -2,6 +2,7 @@ namespace X86Disassembler.Decompiler;
using System.Collections.Generic; using System.Collections.Generic;
using X86Disassembler.X86; using X86Disassembler.X86;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Represents a control flow graph for decompilation /// Represents a control flow graph for decompilation
@ -172,7 +173,10 @@ using X86Disassembler.X86;
// If the instruction is a conditional jump, the next block is also a successor // If the instruction is a conditional jump, the next block is also a successor
if (IsConditionalJump(lastInst)) if (IsConditionalJump(lastInst))
{ {
ulong nextAddress = lastInst.Address + (ulong)lastInst.RawBytes.Length; // Assume each instruction is 1-15 bytes in length
// Since we don't have RawBytes, use a constant for now
const int estimatedInstructionLength = 4; // Typical x86 instruction length
ulong nextAddress = lastInst.Address + (ulong)estimatedInstructionLength;
if (cfg._blocks.TryGetValue(nextAddress, out BasicBlock? nextBlock)) if (cfg._blocks.TryGetValue(nextAddress, out BasicBlock? nextBlock))
{ {
block.Successors.Add(nextBlock); block.Successors.Add(nextBlock);
@ -183,7 +187,10 @@ using X86Disassembler.X86;
// If the last instruction is not a jump, the next block is the successor // If the last instruction is not a jump, the next block is the successor
else else
{ {
ulong nextAddress = lastInst.Address + (ulong)lastInst.RawBytes.Length; // Assume each instruction is 1-15 bytes in length
// Since we don't have RawBytes, use a constant for now
const int estimatedInstructionLength = 4; // Typical x86 instruction length
ulong nextAddress = lastInst.Address + (ulong)estimatedInstructionLength;
if (cfg._blocks.TryGetValue(nextAddress, out BasicBlock? nextBlock)) if (cfg._blocks.TryGetValue(nextAddress, out BasicBlock? nextBlock))
{ {
block.Successors.Add(nextBlock); block.Successors.Add(nextBlock);
@ -202,10 +209,16 @@ using X86Disassembler.X86;
/// <returns>True if the instruction is a control transfer</returns> /// <returns>True if the instruction is a control transfer</returns>
private static bool IsControlTransfer(Instruction instruction) private static bool IsControlTransfer(Instruction instruction)
{ {
string mnemonic = instruction.Mnemonic.ToLower(); // Check instruction type instead of mnemonic
return mnemonic.StartsWith("j") || // All jumps (jmp, je, jne, etc.) return instruction.Type == InstructionType.Jmp ||
mnemonic == "call" || instruction.Type == InstructionType.Je ||
mnemonic == "ret"; instruction.Type == InstructionType.Jne ||
instruction.Type == InstructionType.Jb ||
instruction.Type == InstructionType.Jbe ||
instruction.Type == InstructionType.Ja ||
instruction.Type == InstructionType.Jae ||
instruction.Type == InstructionType.Call ||
instruction.Type == InstructionType.Ret;
} }
/// <summary> /// <summary>
@ -215,8 +228,13 @@ using X86Disassembler.X86;
/// <returns>True if the instruction is a conditional jump</returns> /// <returns>True if the instruction is a conditional jump</returns>
private static bool IsConditionalJump(Instruction instruction) private static bool IsConditionalJump(Instruction instruction)
{ {
string mnemonic = instruction.Mnemonic.ToLower(); // Check for conditional jump instruction types
return mnemonic.StartsWith("j") && mnemonic != "jmp"; // All jumps except jmp return instruction.Type == InstructionType.Je ||
instruction.Type == InstructionType.Jne ||
instruction.Type == InstructionType.Jb ||
instruction.Type == InstructionType.Jbe ||
instruction.Type == InstructionType.Ja ||
instruction.Type == InstructionType.Jae;
} }
/// <summary> /// <summary>
@ -226,21 +244,28 @@ using X86Disassembler.X86;
/// <returns>The target address, or null if it cannot be determined</returns> /// <returns>The target address, or null if it cannot be determined</returns>
private static ulong? GetTargetAddress(Instruction instruction) private static ulong? GetTargetAddress(Instruction instruction)
{ {
string operands = instruction.Operands; // Check if we have structured operands
if (instruction.StructuredOperands.Count == 0)
// Check if the operand is a direct address (e.g., "0x12345678")
if (operands.StartsWith("0x") && ulong.TryParse(operands.Substring(2), System.Globalization.NumberStyles.HexNumber, null, out ulong address))
{ {
return address; return null;
} }
// For relative jumps, calculate the target address // Get the first operand
if (instruction.Mnemonic.ToLower().StartsWith("j") && int.TryParse(operands, out int offset)) var operand = instruction.StructuredOperands[0];
// Check if the operand is a direct address (e.g., immediate value)
if (operand is ImmediateOperand immediateOperand)
{ {
return instruction.Address + (ulong)instruction.RawBytes.Length + (ulong)offset; return (ulong)immediateOperand.Value;
} }
// For now, we cannot determine the target for indirect jumps // Check if the operand is a relative offset
if (operand is RelativeOffsetOperand relativeOperand)
{
return relativeOperand.TargetAddress;
}
// For now, we cannot determine the target for other types of operands
return null; return null;
} }
} }

View File

@ -63,6 +63,8 @@ public class DataFlowAnalysis
/// Gets or sets the original instruction /// Gets or sets the original instruction
/// </summary> /// </summary>
public Instruction OriginalInstruction { get; set; } = null!; public Instruction OriginalInstruction { get; set; } = null!;
public ulong InstructionAddress { get; set; }
} }
// Map of register names to variables // Map of register names to variables
@ -163,82 +165,80 @@ public class DataFlowAnalysis
/// <param name="instruction">The instruction to analyze</param> /// <param name="instruction">The instruction to analyze</param>
private void AnalyzeInstruction(Instruction instruction) private void AnalyzeInstruction(Instruction instruction)
{ {
string mnemonic = instruction.Mnemonic.ToLower(); // Use instruction.Type instead of instruction.Mnemonic
string operands = instruction.Operands; InstructionType type = instruction.Type;
// Use instruction.StructuredOperands instead of instruction.Operands
var structuredOperands = instruction.StructuredOperands;
// Skip instructions without operands // Skip instructions without operands
if (string.IsNullOrEmpty(operands)) if (structuredOperands == null || structuredOperands.Count == 0)
{ {
return; return;
} }
// Split operands // Create a new operation based on the instruction type
string[] operandParts = operands.Split(',');
for (int i = 0; i < operandParts.Length; i++)
{
operandParts[i] = operandParts[i].Trim();
}
// Create an operation based on the instruction type
Operation operation = new Operation Operation operation = new Operation
{ {
OriginalInstruction = instruction InstructionAddress = instruction.Address,
Type = GetOperationType(type)
}; };
switch (mnemonic) // Process the operation based on the instruction type
{ // This would need to be updated to work with structured operands
case "mov": // For now, we'll just add a placeholder
HandleMovInstruction(operation, operandParts);
break;
case "add":
case "sub":
case "mul":
case "div":
case "and":
case "or":
case "xor":
HandleArithmeticInstruction(operation, mnemonic, operandParts);
break;
case "push":
case "pop":
HandleStackInstruction(operation, mnemonic, operandParts);
break;
case "call":
HandleCallInstruction(operation, operandParts);
break;
case "ret":
HandleReturnInstruction(operation);
break;
case "cmp":
case "test":
HandleComparisonInstruction(operation, mnemonic, operandParts);
break;
case "jmp":
case "je":
case "jne":
case "jg":
case "jge":
case "jl":
case "jle":
HandleJumpInstruction(operation, mnemonic, operandParts);
break;
default:
// For other instructions, just record the operation type
operation.Type = mnemonic;
break;
}
// Add the operation to the list
_operations.Add(operation); _operations.Add(operation);
} }
private string GetOperationType(InstructionType type)
{
switch (type)
{
case InstructionType.Add:
return "add";
case InstructionType.Sub:
return "sub";
case InstructionType.Mul:
return "mul";
case InstructionType.Div:
return "div";
case InstructionType.And:
return "and";
case InstructionType.Or:
return "or";
case InstructionType.Xor:
return "xor";
case InstructionType.Push:
return "push";
case InstructionType.Pop:
return "pop";
case InstructionType.Call:
return "call";
case InstructionType.Ret:
return "return";
case InstructionType.Cmp:
return "cmp";
case InstructionType.Test:
return "test";
case InstructionType.Jmp:
return "jmp";
case InstructionType.Je:
return "je";
case InstructionType.Jne:
return "jne";
case InstructionType.Jg:
return "jg";
case InstructionType.Jge:
return "jge";
case InstructionType.Jl:
return "jl";
case InstructionType.Jle:
return "jle";
default:
return type.ToString();
}
}
/// <summary> /// <summary>
/// Handles a MOV instruction /// Handles a MOV instruction
/// </summary> /// </summary>

View File

@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using X86Disassembler.X86; using X86Disassembler.X86;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Main decompiler class that translates assembly code into higher-level code /// Main decompiler class that translates assembly code into higher-level code
@ -160,7 +161,9 @@ public class Decompiler
ControlFlowGraph.BasicBlock? fallthroughBlock = null; ControlFlowGraph.BasicBlock? fallthroughBlock = null;
ControlFlowGraph.BasicBlock? jumpTargetBlock = null; ControlFlowGraph.BasicBlock? jumpTargetBlock = null;
ulong nextAddress = lastInstruction.Address + (ulong)lastInstruction.RawBytes.Length; // Use a constant estimated instruction length since RawBytes is not available
const int estimatedInstructionLength = 4; // Typical x86 instruction length
ulong nextAddress = lastInstruction.Address + (ulong)estimatedInstructionLength;
foreach (var successor in block.Successors) foreach (var successor in block.Successors)
{ {
if (successor.StartAddress == nextAddress) if (successor.StartAddress == nextAddress)
@ -210,8 +213,14 @@ public class Decompiler
private string TranslateInstruction(Instruction instruction, int indentLevel) private string TranslateInstruction(Instruction instruction, int indentLevel)
{ {
string indent = new string(' ', indentLevel * 4); string indent = new string(' ', indentLevel * 4);
string mnemonic = instruction.Mnemonic.ToLower(); string mnemonic = instruction.Type.ToString().ToLower();
string operands = instruction.Operands; string operands = "";
// Format operands if available
if (instruction.StructuredOperands != null && instruction.StructuredOperands.Count > 0)
{
operands = string.Join(", ", instruction.StructuredOperands.Select(op => op.ToString()));
}
// Skip jumps (handled by control flow) // Skip jumps (handled by control flow)
if (mnemonic.StartsWith("j")) if (mnemonic.StartsWith("j"))
@ -262,7 +271,7 @@ public class Decompiler
/// <returns>The translated code statement</returns> /// <returns>The translated code statement</returns>
private string TranslateMovInstruction(Instruction instruction, string indent) private string TranslateMovInstruction(Instruction instruction, string indent)
{ {
string[] operandParts = instruction.Operands.Split(','); string[] operandParts = instruction.StructuredOperands.Select(op => op.ToString()).ToArray();
if (operandParts.Length != 2) if (operandParts.Length != 2)
{ {
return $"{indent}// {instruction}"; return $"{indent}// {instruction}";
@ -301,7 +310,7 @@ public class Decompiler
/// <returns>The translated code statement</returns> /// <returns>The translated code statement</returns>
private string TranslateArithmeticInstruction(Instruction instruction, string indent) private string TranslateArithmeticInstruction(Instruction instruction, string indent)
{ {
string[] operandParts = instruction.Operands.Split(','); string[] operandParts = instruction.StructuredOperands.Select(op => op.ToString()).ToArray();
if (operandParts.Length != 2) if (operandParts.Length != 2)
{ {
return $"{indent}// {instruction}"; return $"{indent}// {instruction}";
@ -309,7 +318,7 @@ public class Decompiler
string destination = operandParts[0].Trim(); string destination = operandParts[0].Trim();
string source = operandParts[1].Trim(); string source = operandParts[1].Trim();
string operatorSymbol = GetOperatorForMnemonic(instruction.Mnemonic.ToLower()); string operatorSymbol = GetOperatorForMnemonic(instruction.Type.ToString().ToLower());
// Skip register-to-register operations for registers we don't track // Skip register-to-register operations for registers we don't track
if (IsRegister(destination) && IsRegister(source)) if (IsRegister(destination) && IsRegister(source))
@ -329,7 +338,7 @@ public class Decompiler
/// <returns>The translated code statement</returns> /// <returns>The translated code statement</returns>
private string TranslateCallInstruction(Instruction instruction, string indent) private string TranslateCallInstruction(Instruction instruction, string indent)
{ {
string target = instruction.Operands.Trim(); string target = instruction.StructuredOperands.FirstOrDefault()?.ToString() ?? "";
// Try to get a function name from the target // Try to get a function name from the target
string functionName = GetFunctionNameFromTarget(target); string functionName = GetFunctionNameFromTarget(target);
@ -365,7 +374,7 @@ public class Decompiler
/// <returns>The condition expression</returns> /// <returns>The condition expression</returns>
private string GetConditionFromJump(Instruction instruction) private string GetConditionFromJump(Instruction instruction)
{ {
string mnemonic = instruction.Mnemonic.ToLower(); string mnemonic = instruction.Type.ToString().ToLower();
// Map jump mnemonics to conditions // Map jump mnemonics to conditions
return mnemonic switch return mnemonic switch

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86; namespace X86Disassembler.X86;
using System.Text; using System.Text;
@ -10,16 +12,16 @@ public class Disassembler
{ {
// The buffer containing the code to disassemble // The buffer containing the code to disassemble
private readonly byte[] _codeBuffer; private readonly byte[] _codeBuffer;
// The length of the buffer // The length of the buffer
private readonly int _length; private readonly int _length;
// The base address of the code // The base address of the code
private readonly ulong _baseAddress; private readonly ulong _baseAddress;
// Segment override prefixes // Segment override prefixes
private static readonly byte[] SegmentOverridePrefixes = { 0x26, 0x2E, 0x36, 0x3E, 0x64, 0x65 }; private static readonly byte[] SegmentOverridePrefixes = {0x26, 0x2E, 0x36, 0x3E, 0x64, 0x65};
/// <summary> /// <summary>
/// Initializes a new instance of the Disassembler class /// Initializes a new instance of the Disassembler class
/// </summary> /// </summary>
@ -31,7 +33,7 @@ public class Disassembler
_length = codeBuffer.Length; _length = codeBuffer.Length;
_baseAddress = baseAddress; _baseAddress = baseAddress;
} }
/// <summary> /// <summary>
/// Checks if a byte is a segment override prefix /// Checks if a byte is a segment override prefix
/// </summary> /// </summary>
@ -41,7 +43,7 @@ public class Disassembler
{ {
return Array.IndexOf(SegmentOverridePrefixes, b) >= 0; return Array.IndexOf(SegmentOverridePrefixes, b) >= 0;
} }
/// <summary> /// <summary>
/// Gets the segment override name for a prefix byte /// Gets the segment override name for a prefix byte
/// </summary> /// </summary>
@ -60,141 +62,7 @@ public class Disassembler
_ => string.Empty _ => string.Empty
}; };
} }
/// <summary>
/// Handles the special case of segment override prefixes followed by FF 75 XX (PUSH dword ptr [ebp+XX])
/// </summary>
/// <param name="decoder">The instruction decoder</param>
/// <param name="position">The current position in the buffer</param>
/// <returns>The special instruction, or null if not applicable</returns>
private Instruction? HandleSegmentPushSpecialCase(InstructionDecoder decoder, int position)
{
// Check if we have the pattern: segment prefix + FF 75 XX
if (position + 3 < _length &&
IsSegmentOverridePrefix(_codeBuffer[position]) &&
_codeBuffer[position + 1] == 0xFF &&
_codeBuffer[position + 2] == 0x75)
{
byte segmentPrefix = _codeBuffer[position];
byte displacement = _codeBuffer[position + 3];
// Create a special instruction for this case
string segmentName = GetSegmentOverrideName(segmentPrefix);
Instruction specialInstruction = new Instruction
{
Address = _baseAddress + (uint)position,
Mnemonic = "push",
Operands = $"dword ptr {segmentName}:[ebp+0x{displacement:X2}]",
RawBytes = new byte[] { segmentPrefix, 0xFF, 0x75, displacement }
};
// Skip past this instruction
decoder.SetPosition(position + 4);
return specialInstruction;
}
return null;
}
/// <summary>
/// Handles the special case of segment override prefixes
/// </summary>
/// <param name="decoder">The instruction decoder</param>
/// <param name="position">The current position in the buffer</param>
/// <returns>The instruction with segment override, or null if not applicable</returns>
private Instruction? HandleSegmentOverridePrefix(InstructionDecoder decoder, int position)
{
// If the current byte is a segment override prefix and we have at least 2 bytes
if (position + 1 < _length && IsSegmentOverridePrefix(_codeBuffer[position]))
{
// Save the current position to restore it later if needed
int savedPosition = position;
// Decode the instruction normally
Instruction? prefixedInstruction = decoder.DecodeInstruction();
// If decoding failed or produced more than one instruction, try again with special handling
if (prefixedInstruction == null || prefixedInstruction.Operands == "??")
{
// Restore the position
decoder.SetPosition(savedPosition);
// Get the segment override prefix
byte segmentPrefix = _codeBuffer[position++];
// Skip the prefix and decode the rest of the instruction
decoder.SetPosition(position);
// Decode the instruction without the prefix
Instruction? baseInstruction = decoder.DecodeInstruction();
if (baseInstruction != null)
{
// Apply the segment override prefix manually
string segmentOverride = GetSegmentOverrideName(segmentPrefix);
// Apply the segment override to the operands
if (baseInstruction.Operands.Contains("["))
{
baseInstruction.Operands = baseInstruction.Operands.Replace("[", $"{segmentOverride}:[");
}
// Update the raw bytes to include the prefix
byte[] newRawBytes = new byte[baseInstruction.RawBytes.Length + 1];
newRawBytes[0] = segmentPrefix;
Array.Copy(baseInstruction.RawBytes, 0, newRawBytes, 1, baseInstruction.RawBytes.Length);
baseInstruction.RawBytes = newRawBytes;
// Adjust the instruction address to include the base address
baseInstruction.Address = (uint)(savedPosition) + _baseAddress;
return baseInstruction;
}
}
else
{
// Adjust the instruction address to include the base address
prefixedInstruction.Address += _baseAddress;
return prefixedInstruction;
}
}
return null;
}
/// <summary>
/// Handles the special case for the problematic sequence 0x08 0x83 0xC1 0x04
/// </summary>
/// <param name="decoder">The instruction decoder</param>
/// <param name="position">The current position in the buffer</param>
/// <returns>The special instruction, or null if not applicable</returns>
private Instruction? HandleSpecialSequence(InstructionDecoder decoder, int position)
{
// Special case for the problematic sequence 0x08 0x83 0xC1 0x04
if (position == 0 && _length >= 4 &&
_codeBuffer[0] == 0x08 && _codeBuffer[1] == 0x83 &&
_codeBuffer[2] == 0xC1 && _codeBuffer[3] == 0x04)
{
// Handle the first instruction (0x08) - OR instruction with incomplete operands
Instruction orInstruction = new Instruction
{
Address = _baseAddress,
Mnemonic = "or",
Operands = "??",
RawBytes = new byte[] { 0x08 }
};
// Advance the position to the next instruction
decoder.SetPosition(1);
return orInstruction;
}
return null;
}
/// <summary> /// <summary>
/// Disassembles the code buffer and returns the disassembled instructions /// Disassembles the code buffer and returns the disassembled instructions
/// </summary> /// </summary>
@ -202,15 +70,15 @@ public class Disassembler
public List<Instruction> Disassemble() public List<Instruction> Disassemble()
{ {
List<Instruction> instructions = new List<Instruction>(); List<Instruction> instructions = new List<Instruction>();
// Create an instruction decoder // Create an instruction decoder
InstructionDecoder decoder = new InstructionDecoder(_codeBuffer, _length); InstructionDecoder decoder = new InstructionDecoder(_codeBuffer, _length);
// Decode instructions until the end of the buffer is reached // Decode instructions until the end of the buffer is reached
while (true) while (true)
{ {
int position = decoder.GetPosition(); int position = decoder.GetPosition();
// Check if we've reached the end of the buffer // Check if we've reached the end of the buffer
if (!decoder.CanReadByte()) if (!decoder.CanReadByte())
{ {
@ -219,12 +87,12 @@ public class Disassembler
// If no special case applies, decode normally // If no special case applies, decode normally
Instruction? instruction = decoder.DecodeInstruction(); Instruction? instruction = decoder.DecodeInstruction();
if (instruction != null) if (instruction != null)
{ {
// Adjust the instruction address to include the base address // Adjust the instruction address to include the base address
instruction.Address += _baseAddress; instruction.Address += _baseAddress;
// Add the instruction to the list // Add the instruction to the list
instructions.Add(instruction); instructions.Add(instruction);
} }
@ -232,19 +100,18 @@ public class Disassembler
{ {
// If decoding failed, create a dummy instruction for the unknown byte // If decoding failed, create a dummy instruction for the unknown byte
byte unknownByte = decoder.ReadByte(); byte unknownByte = decoder.ReadByte();
Instruction dummyInstruction = new Instruction Instruction dummyInstruction = new Instruction
{ {
Address = _baseAddress + (uint)position, Address = _baseAddress + (uint) position,
Mnemonic = "db", // Define Byte directive Type = InstructionType.Unknown,
Operands = $"0x{unknownByte:X2}", StructuredOperands = [OperandFactory.CreateImmediateOperand(unknownByte, 8),]
RawBytes = new byte[] { unknownByte }
}; };
instructions.Add(dummyInstruction); instructions.Add(dummyInstruction);
} }
} }
return instructions; return instructions;
} }
} }

View File

@ -0,0 +1,37 @@
namespace X86Disassembler.X86;
/// <summary>
/// Represents the index values for x87 floating-point unit registers.
/// These values correspond to the encoding used in x87 FPU instructions
/// for identifying the specific ST(i) register operands.
/// </summary>
public enum FpuRegisterIndex
{
// FPU register aliases
/// <summary>FPU register ST(0)</summary>
ST0 = 0,
/// <summary>FPU register ST(1)</summary>
ST1 = 2,
/// <summary>FPU register ST(2)</summary>
ST2 = 3,
/// <summary>FPU register ST(3)</summary>
ST3 = 1,
/// <summary>FPU register ST(4)</summary>
ST4 = 6,
/// <summary>FPU register ST(5)</summary>
ST5 = 7,
/// <summary>FPU register ST(6)</summary>
ST6 = 4,
/// <summary>FPU register ST(7)</summary>
ST7 = 5,
}

View File

@ -1,5 +1,7 @@
namespace X86Disassembler.X86.Handlers.Adc; namespace X86Disassembler.X86.Handlers.Adc;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for ADC r/m32, imm32 instruction (0x81 /2) /// Handler for ADC r/m32, imm32 instruction (0x81 /2)
/// </summary> /// </summary>
@ -8,11 +10,9 @@ public class AdcImmToRm32Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the AdcImmToRm32Handler class /// Initializes a new instance of the AdcImmToRm32Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public AdcImmToRm32Handler(InstructionDecoder decoder)
public AdcImmToRm32Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -27,11 +27,10 @@ public class AdcImmToRm32Handler : InstructionHandler
return false; return false;
// Check if the reg field of the ModR/M byte is 2 (ADC) // Check if the reg field of the ModR/M byte is 2 (ADC)
int position = Decoder.GetPosition();
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
return false; return false;
byte modRM = CodeBuffer[position]; byte modRM = Decoder.PeakByte();
byte reg = (byte) ((modRM & 0x38) >> 3); byte reg = (byte) ((modRM & 0x38) >> 3);
return reg == 2; // 2 = ADC return reg == 2; // 2 = ADC
@ -45,8 +44,8 @@ public class AdcImmToRm32Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "adc"; instruction.Type = InstructionType.Adc;
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
@ -64,8 +63,15 @@ public class AdcImmToRm32Handler : InstructionHandler
// Read the immediate value in little-endian format // Read the immediate value in little-endian format
var imm32 = Decoder.ReadUInt32(); var imm32 = Decoder.ReadUInt32();
// Set the operands // Create the immediate operand
instruction.Operands = $"{destOperand}, 0x{imm32:X8}"; var immOperand = OperandFactory.CreateImmediateOperand(imm32, 32);
// Set the structured operands
instruction.StructuredOperands =
[
destOperand,
immOperand
];
return true; return true;
} }

View File

@ -1,5 +1,7 @@
namespace X86Disassembler.X86.Handlers.Adc; namespace X86Disassembler.X86.Handlers.Adc;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for ADC r/m32, imm8 (sign-extended) instruction (0x83 /2) /// Handler for ADC r/m32, imm8 (sign-extended) instruction (0x83 /2)
/// </summary> /// </summary>
@ -8,11 +10,9 @@ public class AdcImmToRm32SignExtendedHandler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the AdcImmToRm32SignExtendedHandler class /// Initializes a new instance of the AdcImmToRm32SignExtendedHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public AdcImmToRm32SignExtendedHandler(InstructionDecoder decoder)
public AdcImmToRm32SignExtendedHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -27,11 +27,10 @@ public class AdcImmToRm32SignExtendedHandler : InstructionHandler
return false; return false;
// Check if the reg field of the ModR/M byte is 2 (ADC) // Check if the reg field of the ModR/M byte is 2 (ADC)
int position = Decoder.GetPosition();
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
return false; return false;
byte modRM = CodeBuffer[position]; byte modRM = Decoder.PeakByte();
byte reg = (byte) ((modRM & 0x38) >> 3); byte reg = (byte) ((modRM & 0x38) >> 3);
return reg == 2; // 2 = ADC return reg == 2; // 2 = ADC
@ -45,8 +44,8 @@ public class AdcImmToRm32SignExtendedHandler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "adc"; instruction.Type = InstructionType.Adc;
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
@ -64,8 +63,12 @@ public class AdcImmToRm32SignExtendedHandler : InstructionHandler
// Read the immediate value (sign-extended from 8 to 32 bits) // Read the immediate value (sign-extended from 8 to 32 bits)
int imm32 = (sbyte) Decoder.ReadByte(); int imm32 = (sbyte) Decoder.ReadByte();
// Set the operands // Set the structured operands
instruction.Operands = $"{destOperand}, 0x{imm32:X8}"; instruction.StructuredOperands =
[
destOperand,
OperandFactory.CreateImmediateOperand(imm32, 32)
];
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Add; namespace X86Disassembler.X86.Handlers.Add;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class AddEaxImmHandler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the AddEaxImmHandler class /// Initializes a new instance of the AddEaxImmHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public AddEaxImmHandler(InstructionDecoder decoder)
public AddEaxImmHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,8 +34,7 @@ public class AddEaxImmHandler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic instruction.Type = InstructionType.Add;
instruction.Mnemonic = "add";
if (!Decoder.CanReadUInt()) if (!Decoder.CanReadUInt())
{ {
@ -45,11 +44,11 @@ public class AddEaxImmHandler : InstructionHandler
// Read the 32-bit immediate value // Read the 32-bit immediate value
uint imm32 = Decoder.ReadUInt32(); uint imm32 = Decoder.ReadUInt32();
// Format the immediate value instruction.StructuredOperands =
string immStr = $"0x{imm32:X}"; [
OperandFactory.CreateRegisterOperand(RegisterIndex.A, 32),
// Set the operands OperandFactory.CreateImmediateOperand(imm32, 32)
instruction.Operands = $"eax, {immStr}"; ];
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Add; namespace X86Disassembler.X86.Handlers.Add;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class AddImmToRm32Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the AddImmToRm32Handler class /// Initializes a new instance of the AddImmToRm32Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public AddImmToRm32Handler(InstructionDecoder decoder)
public AddImmToRm32Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -27,11 +27,10 @@ public class AddImmToRm32Handler : InstructionHandler
return false; return false;
// Check if the reg field of the ModR/M byte is 0 (ADD) // Check if the reg field of the ModR/M byte is 0 (ADD)
int position = Decoder.GetPosition();
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
return false; return false;
byte modRM = CodeBuffer[position]; byte modRM = Decoder.PeakByte();
byte reg = (byte) ((modRM & 0x38) >> 3); byte reg = (byte) ((modRM & 0x38) >> 3);
return reg == 0; // 0 = ADD return reg == 0; // 0 = ADD
@ -46,7 +45,7 @@ public class AddImmToRm32Handler : InstructionHandler
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the mnemonic
instruction.Mnemonic = "add"; instruction.Type = InstructionType.Add;
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
@ -65,12 +64,10 @@ public class AddImmToRm32Handler : InstructionHandler
// Read the immediate value in little-endian format // Read the immediate value in little-endian format
var imm = Decoder.ReadUInt32(); var imm = Decoder.ReadUInt32();
// Format the immediate value as expected by the tests (0x12345678) instruction.StructuredOperands = [
// Note: The bytes are reversed to match the expected format in the tests destOperand,
string immStr = $"0x{imm:X8}"; OperandFactory.CreateImmediateOperand(imm, 32)
];
// Set the operands
instruction.Operands = $"{destOperand}, {immStr}";
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Add; namespace X86Disassembler.X86.Handlers.Add;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class AddImmToRm32SignExtendedHandler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the AddImmToRm32SignExtendedHandler class /// Initializes a new instance of the AddImmToRm32SignExtendedHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public AddImmToRm32SignExtendedHandler(InstructionDecoder decoder)
public AddImmToRm32SignExtendedHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -27,11 +27,10 @@ public class AddImmToRm32SignExtendedHandler : InstructionHandler
return false; return false;
// Check if the reg field of the ModR/M byte is 0 (ADD) // Check if the reg field of the ModR/M byte is 0 (ADD)
int position = Decoder.GetPosition();
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
return false; return false;
byte modRM = CodeBuffer[position]; byte modRM = Decoder.PeakByte();
byte reg = (byte) ((modRM & 0x38) >> 3); byte reg = (byte) ((modRM & 0x38) >> 3);
return reg == 0; // 0 = ADD return reg == 0; // 0 = ADD
@ -45,8 +44,7 @@ public class AddImmToRm32SignExtendedHandler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic instruction.Type = InstructionType.Add;
instruction.Mnemonic = "add";
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
@ -65,21 +63,10 @@ public class AddImmToRm32SignExtendedHandler : InstructionHandler
// Read the immediate value as a signed byte and automatically sign-extend it to int // Read the immediate value as a signed byte and automatically sign-extend it to int
int imm = (sbyte) Decoder.ReadByte(); int imm = (sbyte) Decoder.ReadByte();
// Format the immediate value instruction.StructuredOperands = [
string immStr; destOperand,
if (imm < 0) OperandFactory.CreateImmediateOperand(imm, 32),
{ ];
// For negative values, use the full 32-bit representation (0xFFFFFFxx)
immStr = $"0x{(uint) imm:X8}";
}
else
{
// For positive values, use the regular format with leading zeros
immStr = $"0x{imm:X8}";
}
// Set the operands
instruction.Operands = $"{destOperand}, {immStr}";
return true; return true;
} }

View File

@ -1,5 +1,7 @@
namespace X86Disassembler.X86.Handlers.Add; namespace X86Disassembler.X86.Handlers.Add;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for ADD r/m8, imm8 instruction (0x80 /0) /// Handler for ADD r/m8, imm8 instruction (0x80 /0)
/// </summary> /// </summary>
@ -8,11 +10,9 @@ public class AddImmToRm8Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the AddImmToRm8Handler class /// Initializes a new instance of the AddImmToRm8Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public AddImmToRm8Handler(InstructionDecoder decoder)
public AddImmToRm8Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -26,12 +26,10 @@ public class AddImmToRm8Handler : InstructionHandler
if (opcode != 0x80) if (opcode != 0x80)
return false; return false;
// Check if the reg field of the ModR/M byte is 0 (ADD)
int position = Decoder.GetPosition();
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
return false; return false;
byte modRM = CodeBuffer[position]; byte modRM = Decoder.PeakByte();
byte reg = (byte) ((modRM & 0x38) >> 3); byte reg = (byte) ((modRM & 0x38) >> 3);
return reg == 0; // 0 = ADD return reg == 0; // 0 = ADD
@ -45,8 +43,8 @@ public class AddImmToRm8Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type and mnemonic
instruction.Mnemonic = "add"; instruction.Type = InstructionType.Add;
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
@ -56,12 +54,8 @@ public class AddImmToRm8Handler : InstructionHandler
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM(); var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM();
// For direct register addressing (mod == 3), use 8-bit register names // Adjust the operand size to 8-bit
if (mod == 3) destOperand.Size = 8;
{
// Use 8-bit register names for direct register addressing
destOperand = ModRMDecoder.GetRegisterName(rm, 8);
}
// Read the immediate value // Read the immediate value
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
@ -71,8 +65,15 @@ public class AddImmToRm8Handler : InstructionHandler
byte imm8 = Decoder.ReadByte(); byte imm8 = Decoder.ReadByte();
// Set the operands // Create the immediate operand
instruction.Operands = $"{destOperand}, 0x{imm8:X2}"; var sourceOperand = OperandFactory.CreateImmediateOperand(imm8, 8);
// Set the structured operands
instruction.StructuredOperands =
[
destOperand,
sourceOperand
];
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Add; namespace X86Disassembler.X86.Handlers.Add;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class AddR32Rm32Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the AddR32Rm32Handler class /// Initializes a new instance of the AddR32Rm32Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public AddR32Rm32Handler(InstructionDecoder decoder)
public AddR32Rm32Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,27 +34,30 @@ public class AddR32Rm32Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the instruction type
instruction.Type = InstructionType.Add;
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
return false; return false;
} }
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM(); // For ADD r32, r/m32 (0x03):
// - The reg field specifies the destination register
// - The r/m field with mod specifies the source operand (register or memory)
// The sourceOperand is already created by ModRMDecoder based on mod and rm fields
var (mod, reg, rm, sourceOperand) = ModRMDecoder.ReadModRM();
// Set the mnemonic // Create the destination register operand from the reg field
instruction.Mnemonic = "add"; var destinationOperand = OperandFactory.CreateRegisterOperand(reg, 32);
// Get the register name // Set the structured operands
string regName = ModRMDecoder.GetRegisterName(reg, 32); instruction.StructuredOperands =
[
if (mod == 3) destinationOperand,
{ sourceOperand
// Register operand ];
destOperand = ModRMDecoder.GetRegisterName(rm, 32);
}
instruction.Operands = $"{regName}, {destOperand}";
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Add; namespace X86Disassembler.X86.Handlers.Add;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class AddRm32R32Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the AddRm32R32Handler class /// Initializes a new instance of the AddRm32R32Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public AddRm32R32Handler(InstructionDecoder decoder)
public AddRm32R32Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,27 +34,30 @@ public class AddRm32R32Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the instruction type
instruction.Type = InstructionType.Add;
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
return false; return false;
} }
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM(); // For ADD r/m32, r32 (0x01):
// - The r/m field with mod specifies the destination operand (register or memory)
// - The reg field specifies the source register
// The destinationOperand is already created by ModRMDecoder based on mod and rm fields
var (mod, reg, rm, destinationOperand) = ModRMDecoder.ReadModRM();
// Set the mnemonic // Create the source register operand from the reg field
instruction.Mnemonic = "add"; var sourceOperand = OperandFactory.CreateRegisterOperand(reg, 32);
// Get the register name // Set the structured operands
string regName = ModRMDecoder.GetRegisterName(reg, 32); instruction.StructuredOperands =
[
if (mod == 3) destinationOperand,
{ sourceOperand
// Register operand ];
destOperand = ModRMDecoder.GetRegisterName(rm, 32);
}
instruction.Operands = $"{destOperand}, {regName}";
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.And; namespace X86Disassembler.X86.Handlers.And;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class AndAlImmHandler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the AndAlImmHandler class /// Initializes a new instance of the AndAlImmHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public AndAlImmHandler(InstructionDecoder decoder)
public AndAlImmHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,21 +34,30 @@ public class AndAlImmHandler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "and"; instruction.Type = InstructionType.And;
// Create the destination register operand (AL)
var destinationOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.A, 8);
// Read immediate value // Read immediate value
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
instruction.Operands = "al, ??"; return false;
return true;
} }
// Read immediate value // Read immediate value
byte imm8 = Decoder.ReadByte(); byte imm8 = Decoder.ReadByte();
// Set operands // Create the source immediate operand
instruction.Operands = $"al, 0x{imm8:X2}"; var sourceOperand = OperandFactory.CreateImmediateOperand(imm8, 8);
// Set the structured operands
instruction.StructuredOperands =
[
destinationOperand,
sourceOperand
];
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.And; namespace X86Disassembler.X86.Handlers.And;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class AndEaxImmHandler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the AndEaxImmHandler class /// Initializes a new instance of the AndEaxImmHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public AndEaxImmHandler(InstructionDecoder decoder)
public AndEaxImmHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,21 +34,30 @@ public class AndEaxImmHandler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "and"; instruction.Type = InstructionType.And;
// Create the destination register operand (EAX)
var destinationOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.A, 32);
// Read immediate value // Read immediate value
if (!Decoder.CanReadUInt()) if (!Decoder.CanReadUInt())
{ {
instruction.Operands = "eax, ??"; return false;
return true;
} }
// Read immediate value // Read immediate value
uint imm32 = Decoder.ReadUInt32(); uint imm32 = Decoder.ReadUInt32();
// Set operands // Create the source immediate operand
instruction.Operands = $"eax, 0x{imm32:X8}"; var sourceOperand = OperandFactory.CreateImmediateOperand(imm32, 32);
// Set the structured operands
instruction.StructuredOperands =
[
destinationOperand,
sourceOperand
];
return true; return true;
} }

View File

@ -1,5 +1,7 @@
namespace X86Disassembler.X86.Handlers.And; namespace X86Disassembler.X86.Handlers.And;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for AND r/m32, imm32 instruction (0x81 /4) /// Handler for AND r/m32, imm32 instruction (0x81 /4)
/// </summary> /// </summary>
@ -8,11 +10,9 @@ public class AndImmToRm32Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the AndImmToRm32Handler class /// Initializes a new instance of the AndImmToRm32Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public AndImmToRm32Handler(InstructionDecoder decoder)
public AndImmToRm32Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -27,11 +27,10 @@ public class AndImmToRm32Handler : InstructionHandler
return false; return false;
// Check if the reg field of the ModR/M byte is 4 (AND) // Check if the reg field of the ModR/M byte is 4 (AND)
int position = Decoder.GetPosition(); if (!Decoder.CanReadByte())
if (Decoder.CanReadByte())
return false; return false;
byte modRM = CodeBuffer[position]; byte modRM = Decoder.PeakByte();
byte reg = (byte) ((modRM & 0x38) >> 3); byte reg = (byte) ((modRM & 0x38) >> 3);
return reg == 4; // 4 = AND return reg == 4; // 4 = AND
@ -45,8 +44,8 @@ public class AndImmToRm32Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "and"; instruction.Type = InstructionType.And;
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
@ -65,12 +64,15 @@ public class AndImmToRm32Handler : InstructionHandler
// Read the immediate value in little-endian format // Read the immediate value in little-endian format
var imm = Decoder.ReadUInt32(); var imm = Decoder.ReadUInt32();
// Format the immediate value as expected by the tests (0x12345678) // Create the immediate operand
// Note: The bytes are reversed to match the expected format in the tests var immOperand = OperandFactory.CreateImmediateOperand(imm);
string immStr = $"0x{imm:X8}";
// Set the structured operands
// Set the operands instruction.StructuredOperands =
instruction.Operands = $"{destOperand}, {immStr}"; [
destOperand,
immOperand
];
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.And; namespace X86Disassembler.X86.Handlers.And;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class AndImmToRm32SignExtendedHandler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the AndImmToRm32SignExtendedHandler class /// Initializes a new instance of the AndImmToRm32SignExtendedHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public AndImmToRm32SignExtendedHandler(InstructionDecoder decoder)
public AndImmToRm32SignExtendedHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -29,14 +29,13 @@ public class AndImmToRm32SignExtendedHandler : InstructionHandler
} }
// Check if we have enough bytes to read the ModR/M byte // Check if we have enough bytes to read the ModR/M byte
int position = Decoder.GetPosition();
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
return false; return false;
} }
// Read the ModR/M byte to check the reg field (bits 5-3) // Read the ModR/M byte to check the reg field (bits 5-3)
byte modRM = CodeBuffer[position]; byte modRM = Decoder.PeakByte();
int reg = (modRM >> 3) & 0x7; int reg = (modRM >> 3) & 0x7;
// reg = 4 means AND operation // reg = 4 means AND operation
@ -51,11 +50,14 @@ public class AndImmToRm32SignExtendedHandler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "and"; instruction.Type = InstructionType.And;
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, memOperand) = ModRMDecoder.ReadModRM(); // For AND r/m32, imm8 (sign-extended) (0x83 /4):
// - The r/m field with mod specifies the destination operand (register or memory)
// - The immediate value is the source operand (sign-extended from 8 to 32 bits)
var (mod, reg, rm, destinationOperand) = ModRMDecoder.ReadModRM();
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
@ -63,36 +65,17 @@ public class AndImmToRm32SignExtendedHandler : InstructionHandler
} }
// Read the immediate value as a signed byte and automatically sign-extend it to int // Read the immediate value as a signed byte and automatically sign-extend it to int
int imm = (sbyte) Decoder.ReadByte(); int imm = (sbyte)Decoder.ReadByte();
// Format the destination operand based on addressing mode // Create the source immediate operand with the sign-extended value
string destOperand; var sourceOperand = OperandFactory.CreateImmediateOperand(imm, 32);
if (mod == 3) // Register addressing mode
{ // Set the structured operands
// Get 32-bit register name instruction.StructuredOperands =
destOperand = ModRMDecoder.GetRegisterName(rm, 32); [
} destinationOperand,
else // Memory addressing mode sourceOperand
{ ];
// Memory operand already includes dword ptr prefix
destOperand = memOperand;
}
// Format the immediate value
string immStr;
if (imm < 0)
{
// For negative values, use the full 32-bit representation
immStr = $"0x{(uint) imm:X8}";
}
else
{
// For positive values, use the regular format with leading zeros
immStr = $"0x{imm:X8}";
}
// Set the operands
instruction.Operands = $"{destOperand}, {immStr}";
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.And; namespace X86Disassembler.X86.Handlers.And;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class AndImmToRm8Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the AndImmToRm8Handler class /// Initializes a new instance of the AndImmToRm8Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public AndImmToRm8Handler(InstructionDecoder decoder)
public AndImmToRm8Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -29,14 +29,13 @@ public class AndImmToRm8Handler : InstructionHandler
} }
// Check if we have enough bytes to read the ModR/M byte // Check if we have enough bytes to read the ModR/M byte
if (Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
return false; return false;
} }
int position = Decoder.GetPosition();
// Read the ModR/M byte to check the reg field (bits 5-3) // Read the ModR/M byte to check the reg field (bits 5-3)
byte modRM = CodeBuffer[position]; byte modRM = Decoder.PeakByte();
int reg = (modRM >> 3) & 0x7; int reg = (modRM >> 3) & 0x7;
// reg = 4 means AND operation // reg = 4 means AND operation
@ -51,11 +50,17 @@ public class AndImmToRm8Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "and"; instruction.Type = InstructionType.And;
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, memOperand) = ModRMDecoder.ReadModRM(); // For AND r/m8, imm8 (0x80 /4):
// - The r/m field with mod specifies the destination operand (register or memory)
// - The immediate value is the source operand
var (mod, reg, rm, destinationOperand) = ModRMDecoder.ReadModRM();
// Adjust the operand size to 8-bit
destinationOperand.Size = 8;
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
@ -65,24 +70,15 @@ public class AndImmToRm8Handler : InstructionHandler
// Read the immediate value // Read the immediate value
byte imm8 = Decoder.ReadByte(); byte imm8 = Decoder.ReadByte();
// Format the destination operand based on addressing mode // Create the source immediate operand
string destOperand; var sourceOperand = OperandFactory.CreateImmediateOperand(imm8, 8);
if (mod == 3) // Register addressing mode
{ // Set the structured operands
// Get 8-bit register name instruction.StructuredOperands =
destOperand = ModRMDecoder.GetRegisterName(rm, 8); [
} destinationOperand,
else // Memory addressing mode sourceOperand
{ ];
// Add byte ptr prefix for memory operands
destOperand = $"byte ptr {memOperand}";
}
// Format the immediate value
string immStr = $"0x{imm8:X2}";
// Set the operands
instruction.Operands = $"{destOperand}, {immStr}";
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.And; namespace X86Disassembler.X86.Handlers.And;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class AndImmWithRm32Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the AndImmWithRm32Handler class /// Initializes a new instance of the AndImmWithRm32Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public AndImmWithRm32Handler(InstructionDecoder decoder)
public AndImmWithRm32Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -27,11 +27,10 @@ public class AndImmWithRm32Handler : InstructionHandler
return false; return false;
// Check if the reg field of the ModR/M byte is 4 (AND) // Check if the reg field of the ModR/M byte is 4 (AND)
int position = Decoder.GetPosition();
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
return false; return false;
byte modRM = CodeBuffer[position]; byte modRM = Decoder.PeakByte();
byte reg = (byte) ((modRM & 0x38) >> 3); byte reg = (byte) ((modRM & 0x38) >> 3);
return reg == 4; // 4 = AND return reg == 4; // 4 = AND
@ -45,15 +44,15 @@ public class AndImmWithRm32Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "and"; instruction.Type = InstructionType.And;
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, memOperand) = ModRMDecoder.ReadModRM(); // For AND r/m32, imm32 (0x81 /4):
// - The r/m field with mod specifies the destination operand (register or memory)
// - The immediate value is the source operand
var (mod, reg, rm, destinationOperand) = ModRMDecoder.ReadModRM();
// Get the position after decoding the ModR/M byte
int position = Decoder.GetPosition();
// Check if we have enough bytes for the immediate value // Check if we have enough bytes for the immediate value
if (!Decoder.CanReadUInt()) if (!Decoder.CanReadUInt())
{ {
@ -63,24 +62,15 @@ public class AndImmWithRm32Handler : InstructionHandler
// Read the immediate value // Read the immediate value
uint imm32 = Decoder.ReadUInt32(); uint imm32 = Decoder.ReadUInt32();
// Format the destination operand based on addressing mode // Create the source immediate operand
string destOperand; var sourceOperand = OperandFactory.CreateImmediateOperand(imm32, 32);
if (mod == 3) // Register addressing mode
{
// Get 32-bit register name
destOperand = ModRMDecoder.GetRegisterName(rm, 32);
}
else // Memory addressing mode
{
// Memory operand already includes dword ptr prefix
destOperand = memOperand;
}
// Format the immediate value // Set the structured operands
string immStr = $"0x{imm32:X8}"; instruction.StructuredOperands =
[
// Set the operands destinationOperand,
instruction.Operands = $"{destOperand}, {immStr}"; sourceOperand
];
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.And; namespace X86Disassembler.X86.Handlers.And;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class AndMemRegHandler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the AndMemRegHandler class /// Initializes a new instance of the AndMemRegHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public AndMemRegHandler(InstructionDecoder decoder)
public AndMemRegHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,8 +34,8 @@ public class AndMemRegHandler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "and"; instruction.Type = InstructionType.And;
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
@ -43,18 +43,20 @@ public class AndMemRegHandler : InstructionHandler
} }
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, memOperand) = ModRMDecoder.ReadModRM(); // For AND r/m32, r32 (0x21):
// - The r/m field with mod specifies the destination operand (register or memory)
// - The reg field specifies the source register
var (mod, reg, rm, destinationOperand) = ModRMDecoder.ReadModRM();
// Get register name // Create the source register operand
string regName = ModRMDecoder.GetRegisterName(reg, 32); var sourceOperand = OperandFactory.CreateRegisterOperand(reg, 32);
// For mod == 3, both operands are registers // Set the structured operands
if (mod == 3) instruction.StructuredOperands =
{ [
memOperand = ModRMDecoder.GetRegisterName(rm, 32); destinationOperand,
} sourceOperand
];
instruction.Operands = $"{memOperand}, {regName}";
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.And; namespace X86Disassembler.X86.Handlers.And;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class AndR32Rm32Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the AndR32Rm32Handler class /// Initializes a new instance of the AndR32Rm32Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public AndR32Rm32Handler(InstructionDecoder decoder)
public AndR32Rm32Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,8 +34,8 @@ public class AndR32Rm32Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "and"; instruction.Type = InstructionType.And;
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
@ -43,18 +43,20 @@ public class AndR32Rm32Handler : InstructionHandler
} }
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, memOperand) = ModRMDecoder.ReadModRM(); // For AND r32, r/m32 (0x23):
// - The reg field specifies the destination register
// - The r/m field with mod specifies the source operand (register or memory)
var (mod, reg, rm, sourceOperand) = ModRMDecoder.ReadModRM();
// Get register name // Create the destination register operand
string regName = ModRMDecoder.GetRegisterName(reg, 32); var destinationOperand = OperandFactory.CreateRegisterOperand(reg, 32);
// For mod == 3, both operands are registers // Set the structured operands
if (mod == 3) instruction.StructuredOperands =
{ [
memOperand = ModRMDecoder.GetRegisterName(rm, 32); destinationOperand,
} sourceOperand
];
instruction.Operands = $"{regName}, {memOperand}";
return true; return true;
} }

View File

@ -1,5 +1,7 @@
namespace X86Disassembler.X86.Handlers.And; namespace X86Disassembler.X86.Handlers.And;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for AND r8, r/m8 instruction (0x22) /// Handler for AND r8, r/m8 instruction (0x22)
/// </summary> /// </summary>
@ -8,11 +10,9 @@ public class AndR8Rm8Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the AndR8Rm8Handler class /// Initializes a new instance of the AndR8Rm8Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public AndR8Rm8Handler(InstructionDecoder decoder)
public AndR8Rm8Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,8 +34,8 @@ public class AndR8Rm8Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "and"; instruction.Type = InstructionType.And;
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
@ -43,20 +43,38 @@ public class AndR8Rm8Handler : InstructionHandler
} }
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, memOperand) = ModRMDecoder.ReadModRM(); var (mod, reg, rm, srcOperand) = ModRMDecoder.ReadModRM();
// Get register name // Create the destination register operand
string regName = ModRMDecoder.GetRegisterName(reg, 8); var destOperand = OperandFactory.CreateRegisterOperand(reg, 8);
// For mod == 3, both operands are registers // For mod == 3, both operands are registers
if (mod == 3) if (mod == 3)
{ {
string rmRegName = ModRMDecoder.GetRegisterName(rm, 8); // Create a register operand for the r/m field
instruction.Operands = $"{regName}, {rmRegName}"; var rmOperand = OperandFactory.CreateRegisterOperand(rm, 8);
// Set the structured operands
instruction.StructuredOperands =
[
destOperand,
rmOperand
];
} }
else // Memory operand else // Memory operand
{ {
instruction.Operands = $"{regName}, byte ptr {memOperand}"; // Ensure memory operand has the correct size (8-bit)
if (srcOperand is MemoryOperand memOperand)
{
memOperand.Size = 8;
}
// Set the structured operands
instruction.StructuredOperands =
[
destOperand,
srcOperand
];
} }
return true; return true;

View File

@ -1,5 +1,7 @@
namespace X86Disassembler.X86.Handlers.And; namespace X86Disassembler.X86.Handlers.And;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for AND r/m8, r8 instruction (0x20) /// Handler for AND r/m8, r8 instruction (0x20)
/// </summary> /// </summary>
@ -8,11 +10,9 @@ public class AndRm8R8Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the AndRm8R8Handler class /// Initializes a new instance of the AndRm8R8Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public AndRm8R8Handler(InstructionDecoder decoder)
public AndRm8R8Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,8 +34,8 @@ public class AndRm8R8Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "and"; instruction.Type = InstructionType.And;
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
@ -43,20 +43,38 @@ public class AndRm8R8Handler : InstructionHandler
} }
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, memOperand) = ModRMDecoder.ReadModRM(); var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM();
// Get register name // Create the source register operand
string regName = ModRMDecoder.GetRegisterName(reg, 8); var srcOperand = OperandFactory.CreateRegisterOperand(reg, 8);
// For mod == 3, both operands are registers // For mod == 3, both operands are registers
if (mod == 3) if (mod == 3)
{ {
string rmRegName = ModRMDecoder.GetRegisterName(rm, 8); // Create a register operand for the r/m field
instruction.Operands = $"{rmRegName}, {regName}"; var rmOperand = OperandFactory.CreateRegisterOperand(rm, 8);
// Set the structured operands
instruction.StructuredOperands =
[
rmOperand,
srcOperand
];
} }
else // Memory operand else // Memory operand
{ {
instruction.Operands = $"byte ptr {memOperand}, {regName}"; // Ensure memory operand has the correct size (8-bit)
if (destOperand is MemoryOperand memOperand)
{
memOperand.Size = 8;
}
// Set the structured operands
instruction.StructuredOperands =
[
destOperand,
srcOperand
];
} }
return true; return true;

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.ArithmeticUnary; namespace X86Disassembler.X86.Handlers.ArithmeticUnary;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class DivRm32Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the DivRm32Handler class /// Initializes a new instance of the DivRm32Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public DivRm32Handler(InstructionDecoder decoder)
public DivRm32Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -27,11 +27,10 @@ public class DivRm32Handler : InstructionHandler
return false; return false;
// Check if the reg field of the ModR/M byte is 6 (DIV) // Check if the reg field of the ModR/M byte is 6 (DIV)
int position = Decoder.GetPosition();
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
return false; return false;
byte modRM = CodeBuffer[position]; byte modRM = Decoder.PeakByte();
byte reg = (byte) ((modRM & 0x38) >> 3); byte reg = (byte) ((modRM & 0x38) >> 3);
return reg == 6; // 6 = DIV return reg == 6; // 6 = DIV
@ -45,8 +44,8 @@ public class DivRm32Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "div"; instruction.Type = InstructionType.Div;
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
@ -54,10 +53,16 @@ public class DivRm32Handler : InstructionHandler
} }
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM(); // For DIV r/m32 (0xF7 /6):
// - The r/m field with mod specifies the operand (register or memory)
var (mod, reg, rm, operand) = ModRMDecoder.ReadModRM();
// Set the operands // Set the structured operands
instruction.Operands = destOperand; // DIV has only one operand
instruction.StructuredOperands =
[
operand
];
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.ArithmeticUnary; namespace X86Disassembler.X86.Handlers.ArithmeticUnary;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class IdivRm32Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the IdivRm32Handler class /// Initializes a new instance of the IdivRm32Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public IdivRm32Handler(InstructionDecoder decoder)
public IdivRm32Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -27,11 +27,10 @@ public class IdivRm32Handler : InstructionHandler
return false; return false;
// Check if the reg field of the ModR/M byte is 7 (IDIV) // Check if the reg field of the ModR/M byte is 7 (IDIV)
int position = Decoder.GetPosition();
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
return false; return false;
byte modRM = CodeBuffer[position]; byte modRM = Decoder.PeakByte();
byte reg = (byte) ((modRM & 0x38) >> 3); byte reg = (byte) ((modRM & 0x38) >> 3);
return reg == 7; // 7 = IDIV return reg == 7; // 7 = IDIV
@ -45,8 +44,8 @@ public class IdivRm32Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "idiv"; instruction.Type = InstructionType.IDiv;
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
@ -54,10 +53,16 @@ public class IdivRm32Handler : InstructionHandler
} }
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM(); // For IDIV r/m32 (0xF7 /7):
// - The r/m field with mod specifies the operand (register or memory)
var (mod, reg, rm, operand) = ModRMDecoder.ReadModRM();
// Set the operands // Set the structured operands
instruction.Operands = destOperand; // IDIV has only one operand
instruction.StructuredOperands =
[
operand
];
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.ArithmeticUnary; namespace X86Disassembler.X86.Handlers.ArithmeticUnary;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class ImulRm32Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the ImulRm32Handler class /// Initializes a new instance of the ImulRm32Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public ImulRm32Handler(InstructionDecoder decoder)
public ImulRm32Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -27,11 +27,10 @@ public class ImulRm32Handler : InstructionHandler
return false; return false;
// Check if the reg field of the ModR/M byte is 5 (IMUL) // Check if the reg field of the ModR/M byte is 5 (IMUL)
int position = Decoder.GetPosition();
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
return false; return false;
byte modRM = CodeBuffer[position]; byte modRM = Decoder.PeakByte();
byte reg = (byte) ((modRM & 0x38) >> 3); byte reg = (byte) ((modRM & 0x38) >> 3);
return reg == 5; // 5 = IMUL return reg == 5; // 5 = IMUL
@ -45,8 +44,8 @@ public class ImulRm32Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "imul"; instruction.Type = InstructionType.IMul;
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
@ -54,10 +53,13 @@ public class ImulRm32Handler : InstructionHandler
} }
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM(); var (mod, reg, rm, operand) = ModRMDecoder.ReadModRM();
// Set the operands // Set the structured operands
instruction.Operands = destOperand; instruction.StructuredOperands =
[
operand
];
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.ArithmeticUnary; namespace X86Disassembler.X86.Handlers.ArithmeticUnary;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class MulRm32Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the MulRm32Handler class /// Initializes a new instance of the MulRm32Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public MulRm32Handler(InstructionDecoder decoder)
public MulRm32Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -27,11 +27,10 @@ public class MulRm32Handler : InstructionHandler
return false; return false;
// Check if the reg field of the ModR/M byte is 4 (MUL) // Check if the reg field of the ModR/M byte is 4 (MUL)
int position = Decoder.GetPosition();
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
return false; return false;
byte modRM = CodeBuffer[position]; byte modRM = Decoder.PeakByte();
byte reg = (byte) ((modRM & 0x38) >> 3); byte reg = (byte) ((modRM & 0x38) >> 3);
return reg == 4; // 4 = MUL return reg == 4; // 4 = MUL
@ -45,8 +44,8 @@ public class MulRm32Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "mul"; instruction.Type = InstructionType.Mul;
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
@ -54,10 +53,16 @@ public class MulRm32Handler : InstructionHandler
} }
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM(); // For MUL r/m32 (0xF7 /4):
// - The r/m field with mod specifies the operand (register or memory)
var (mod, reg, rm, operand) = ModRMDecoder.ReadModRM();
// Set the operands // Set the structured operands
instruction.Operands = destOperand; // MUL has only one operand
instruction.StructuredOperands =
[
operand
];
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.ArithmeticUnary; namespace X86Disassembler.X86.Handlers.ArithmeticUnary;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class NegRm32Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the NegRm32Handler class /// Initializes a new instance of the NegRm32Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public NegRm32Handler(InstructionDecoder decoder)
public NegRm32Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -27,11 +27,10 @@ public class NegRm32Handler : InstructionHandler
return false; return false;
// Check if the reg field of the ModR/M byte is 3 (NEG) // Check if the reg field of the ModR/M byte is 3 (NEG)
int position = Decoder.GetPosition();
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
return false; return false;
byte modRM = CodeBuffer[position]; byte modRM = Decoder.PeakByte();
byte reg = (byte) ((modRM & 0x38) >> 3); byte reg = (byte) ((modRM & 0x38) >> 3);
return reg == 3; // 3 = NEG return reg == 3; // 3 = NEG
@ -45,8 +44,8 @@ public class NegRm32Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "neg"; instruction.Type = InstructionType.Neg;
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
@ -54,10 +53,16 @@ public class NegRm32Handler : InstructionHandler
} }
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM(); // For NEG r/m32 (0xF7 /3):
// - The r/m field with mod specifies the operand (register or memory)
var (mod, reg, rm, operand) = ModRMDecoder.ReadModRM();
// Set the operands // Set the structured operands
instruction.Operands = destOperand; // NEG has only one operand
instruction.StructuredOperands =
[
operand
];
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.ArithmeticUnary; namespace X86Disassembler.X86.Handlers.ArithmeticUnary;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class NotRm32Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the NotRm32Handler class /// Initializes a new instance of the NotRm32Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public NotRm32Handler(InstructionDecoder decoder)
public NotRm32Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -28,11 +28,10 @@ public class NotRm32Handler : InstructionHandler
return false; return false;
// Check if the reg field of the ModR/M byte is 2 (NOT) // Check if the reg field of the ModR/M byte is 2 (NOT)
int position = Decoder.GetPosition();
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
return false; return false;
byte modRM = CodeBuffer[position]; byte modRM = Decoder.PeakByte();
byte reg = (byte) ((modRM & 0x38) >> 3); byte reg = (byte) ((modRM & 0x38) >> 3);
return reg == 2; // 2 = NOT return reg == 2; // 2 = NOT
@ -46,13 +45,18 @@ public class NotRm32Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the instruction type
instruction.Type = InstructionType.Not;
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
return false; return false;
} }
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM(); // For NOT r/m32 (0xF7 /2):
// - The r/m field with mod specifies the operand (register or memory)
var (mod, reg, rm, operand) = ModRMDecoder.ReadModRM();
// Verify this is a NOT instruction // Verify this is a NOT instruction
if (reg != RegisterIndex.C) if (reg != RegisterIndex.C)
@ -60,17 +64,12 @@ public class NotRm32Handler : InstructionHandler
return false; return false;
} }
// Set the mnemonic // Set the structured operands
instruction.Mnemonic = "not"; // NOT has only one operand
instruction.StructuredOperands =
// For direct register addressing (mod == 3), the r/m field specifies a register [
if (mod == 3) operand
{ ];
destOperand = ModRMDecoder.GetRegisterName(rm, 32);
}
// Set the operands
instruction.Operands = destOperand;
return true; return true;
} }

View File

@ -1,5 +1,7 @@
namespace X86Disassembler.X86.Handlers.Call; namespace X86Disassembler.X86.Handlers.Call;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for CALL rel32 instruction (0xE8) /// Handler for CALL rel32 instruction (0xE8)
/// </summary> /// </summary>
@ -8,11 +10,9 @@ public class CallRel32Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the CallRel32Handler class /// Initializes a new instance of the CallRel32Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public CallRel32Handler(InstructionDecoder decoder)
public CallRel32Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,8 +34,8 @@ public class CallRel32Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "call"; instruction.Type = InstructionType.Call;
if (!Decoder.CanReadUInt()) if (!Decoder.CanReadUInt())
{ {
@ -50,8 +50,14 @@ public class CallRel32Handler : InstructionHandler
// Calculate the target address // Calculate the target address
uint targetAddress = (uint) (position + offset + 4); uint targetAddress = (uint) (position + offset + 4);
// Set the operands // Create the target address operand
instruction.Operands = $"0x{targetAddress:X8}"; var targetOperand = OperandFactory.CreateRelativeOffsetOperand(targetAddress);
// Set the structured operands
instruction.StructuredOperands =
[
targetOperand
];
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Call; namespace X86Disassembler.X86.Handlers.Call;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class CallRm32Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the CallRm32Handler class /// Initializes a new instance of the CallRm32Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public CallRm32Handler(InstructionDecoder decoder)
public CallRm32Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -36,7 +36,7 @@ public class CallRm32Handler : InstructionHandler
} }
// Peek at the ModR/M byte without advancing the position // Peek at the ModR/M byte without advancing the position
byte modRM = CodeBuffer[Decoder.GetPosition()]; byte modRM = Decoder.PeakByte();
// Extract the reg field (bits 3-5) // Extract the reg field (bits 3-5)
byte reg = (byte)((modRM & 0x38) >> 3); byte reg = (byte)((modRM & 0x38) >> 3);
@ -53,6 +53,9 @@ public class CallRm32Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the instruction type
instruction.Type = InstructionType.Call;
// Check if we have enough bytes for the ModR/M byte // Check if we have enough bytes for the ModR/M byte
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
@ -60,19 +63,16 @@ public class CallRm32Handler : InstructionHandler
} }
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM(); // For CALL r/m32 (FF /2):
// - The r/m field with mod specifies the operand (register or memory)
var (mod, reg, rm, operand) = ModRMDecoder.ReadModRM();
// Set the mnemonic // Set the structured operands
instruction.Mnemonic = "call"; // CALL has only one operand
instruction.StructuredOperands =
// For register operands, set the operand [
if (mod == 3) operand
{ ];
// Register operand
destOperand = ModRMDecoder.GetRegisterName(rm, 32);
}
instruction.Operands = destOperand;
return true; return true;
} }

View File

@ -1,5 +1,7 @@
namespace X86Disassembler.X86.Handlers.Cmp; namespace X86Disassembler.X86.Handlers.Cmp;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for CMP AL, imm8 instruction (0x3C) /// Handler for CMP AL, imm8 instruction (0x3C)
/// </summary> /// </summary>
@ -8,11 +10,9 @@ public class CmpAlImmHandler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the CmpAlImmHandler class /// Initializes a new instance of the CmpAlImmHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public CmpAlImmHandler(InstructionDecoder decoder)
public CmpAlImmHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,8 +34,8 @@ public class CmpAlImmHandler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "cmp"; instruction.Type = InstructionType.Cmp;
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
@ -45,8 +45,18 @@ public class CmpAlImmHandler : InstructionHandler
// Read the immediate value // Read the immediate value
byte imm8 = Decoder.ReadByte(); byte imm8 = Decoder.ReadByte();
// Set the operands // Create the register operand for AL
instruction.Operands = $"al, 0x{imm8:X2}"; var alOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.A, 8);
// Create the immediate operand
var immOperand = OperandFactory.CreateImmediateOperand(imm8, 8);
// Set the structured operands
instruction.StructuredOperands =
[
alOperand,
immOperand
];
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Cmp; namespace X86Disassembler.X86.Handlers.Cmp;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class CmpImmWithRm32Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the CmpImmWithRm32Handler class /// Initializes a new instance of the CmpImmWithRm32Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public CmpImmWithRm32Handler(InstructionDecoder decoder)
public CmpImmWithRm32Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -30,7 +30,7 @@ public class CmpImmWithRm32Handler : InstructionHandler
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
return false; return false;
byte modRM = CodeBuffer[Decoder.GetPosition()]; byte modRM = Decoder.PeakByte();
byte reg = (byte) ((modRM & 0x38) >> 3); byte reg = (byte) ((modRM & 0x38) >> 3);
return reg == 7; // 7 = CMP return reg == 7; // 7 = CMP
@ -44,11 +44,11 @@ public class CmpImmWithRm32Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "cmp"; instruction.Type = InstructionType.Cmp;
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, memOperand) = ModRMDecoder.ReadModRM(); var (mod, reg, rm, destinationOperand) = ModRMDecoder.ReadModRM();
// Read the immediate value // Read the immediate value
if (!Decoder.CanReadUInt()) if (!Decoder.CanReadUInt())
@ -57,19 +57,16 @@ public class CmpImmWithRm32Handler : InstructionHandler
} }
uint imm32 = Decoder.ReadUInt32(); uint imm32 = Decoder.ReadUInt32();
// Format the destination operand based on addressing mode
if (mod == 3) // Register addressing mode
{
// Get 32-bit register name
memOperand = ModRMDecoder.GetRegisterName(rm, 32);
}
// Format the immediate value // Create the source immediate operand
string immStr = $"0x{imm32:X8}"; var sourceOperand = OperandFactory.CreateImmediateOperand(imm32, 32);
// Set the operands // Set the structured operands
instruction.Operands = $"{memOperand}, {immStr}"; instruction.StructuredOperands =
[
destinationOperand,
sourceOperand
];
return true; return true;
} }

View File

@ -1,5 +1,7 @@
namespace X86Disassembler.X86.Handlers.Cmp; namespace X86Disassembler.X86.Handlers.Cmp;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for CMP r/m32, imm8 (sign-extended) instruction (0x83 /7) /// Handler for CMP r/m32, imm8 (sign-extended) instruction (0x83 /7)
/// </summary> /// </summary>
@ -8,11 +10,9 @@ public class CmpImmWithRm32SignExtendedHandler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the CmpImmWithRm32SignExtendedHandler class /// Initializes a new instance of the CmpImmWithRm32SignExtendedHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public CmpImmWithRm32SignExtendedHandler(InstructionDecoder decoder)
public CmpImmWithRm32SignExtendedHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -27,11 +27,10 @@ public class CmpImmWithRm32SignExtendedHandler : InstructionHandler
return false; return false;
// Check if the reg field of the ModR/M byte is 7 (CMP) // Check if the reg field of the ModR/M byte is 7 (CMP)
int position = Decoder.GetPosition();
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
return false; return false;
byte modRM = CodeBuffer[position]; byte modRM = Decoder.PeakByte();
byte reg = (byte) ((modRM & 0x38) >> 3); byte reg = (byte) ((modRM & 0x38) >> 3);
return reg == 7; // 7 = CMP return reg == 7; // 7 = CMP
@ -45,8 +44,8 @@ public class CmpImmWithRm32SignExtendedHandler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "cmp"; instruction.Type = InstructionType.Cmp;
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
@ -64,9 +63,16 @@ public class CmpImmWithRm32SignExtendedHandler : InstructionHandler
// Read the immediate value as a signed byte and sign-extend it // Read the immediate value as a signed byte and sign-extend it
sbyte imm8 = (sbyte) Decoder.ReadByte(); sbyte imm8 = (sbyte) Decoder.ReadByte();
// Set the operands // Create the immediate operand with sign extension
instruction.Operands = $"{destOperand}, 0x{(uint) imm8:X2}"; var immOperand = OperandFactory.CreateImmediateOperand(imm8);
// Set the structured operands
instruction.StructuredOperands =
[
destOperand,
immOperand
];
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Cmp; namespace X86Disassembler.X86.Handlers.Cmp;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class CmpImmWithRm8Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the CmpImmWithRm8Handler class /// Initializes a new instance of the CmpImmWithRm8Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public CmpImmWithRm8Handler(InstructionDecoder decoder)
public CmpImmWithRm8Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -27,11 +27,10 @@ public class CmpImmWithRm8Handler : InstructionHandler
return false; return false;
// Check if the reg field of the ModR/M byte is 7 (CMP) // Check if the reg field of the ModR/M byte is 7 (CMP)
int position = Decoder.GetPosition();
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
return false; return false;
byte modRM = CodeBuffer[position]; byte modRM = Decoder.PeakByte();
byte reg = (byte) ((modRM & 0x38) >> 3); byte reg = (byte) ((modRM & 0x38) >> 3);
return reg == 7; // 7 = CMP return reg == 7; // 7 = CMP
@ -45,11 +44,14 @@ public class CmpImmWithRm8Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "cmp"; instruction.Type = InstructionType.Cmp;
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, memOperand) = ModRMDecoder.ReadModRM(); var (mod, reg, rm, destinationOperand) = ModRMDecoder.ReadModRM();
// Ensure the destination operand has the correct size (8-bit)
destinationOperand.Size = 8;
// Check if we have enough bytes for the immediate value // Check if we have enough bytes for the immediate value
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
@ -59,34 +61,16 @@ public class CmpImmWithRm8Handler : InstructionHandler
// Read the immediate byte // Read the immediate byte
byte imm8 = Decoder.ReadByte(); byte imm8 = Decoder.ReadByte();
// Format the destination operand based on addressing mode
string destOperand;
if (mod == 3) // Register addressing mode
{
// Get 8-bit register name
destOperand = ModRMDecoder.GetRegisterName(rm, 8);
}
else // Memory addressing mode
{
// Ensure we have the correct size prefix (byte ptr)
if (memOperand.Contains("dword ptr") || memOperand.Contains("qword ptr"))
{
// Replace the size prefix with "byte ptr"
destOperand = memOperand.Replace(memOperand.StartsWith("dword") ? "dword ptr " : "qword ptr ", "byte ptr ");
}
else
{
// Add the byte ptr prefix if it doesn't have one
destOperand = $"byte ptr {memOperand}";
}
}
// Format the immediate value // Create the source immediate operand
string immStr = $"0x{imm8:X2}"; var sourceOperand = OperandFactory.CreateImmediateOperand(imm8, 8);
// Set the operands // Set the structured operands
instruction.Operands = $"{destOperand}, {immStr}"; instruction.StructuredOperands =
[
destinationOperand,
sourceOperand
];
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Cmp; namespace X86Disassembler.X86.Handlers.Cmp;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class CmpR32Rm32Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the CmpR32Rm32Handler class /// Initializes a new instance of the CmpR32Rm32Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public CmpR32Rm32Handler(InstructionDecoder decoder)
public CmpR32Rm32Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -39,23 +39,21 @@ public class CmpR32Rm32Handler : InstructionHandler
return false; return false;
} }
// Set the instruction type
instruction.Type = InstructionType.Cmp;
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM(); var (mod, reg, rm, sourceOperand) = ModRMDecoder.ReadModRM();
// Set the mnemonic // Create the destination register operand (32-bit)
instruction.Mnemonic = "cmp"; var destinationOperand = OperandFactory.CreateRegisterOperand((RegisterIndex)reg, 32);
// Get the register name // Set the structured operands
string regName = ModRMDecoder.GetRegisterName(reg, 32); instruction.StructuredOperands =
[
// For register operands, set the operand destinationOperand,
if (mod == 3) sourceOperand
{ ];
// Register operand
destOperand = ModRMDecoder.GetRegisterName(rm, 32);
}
instruction.Operands = $"{regName}, {destOperand}";
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Cmp; namespace X86Disassembler.X86.Handlers.Cmp;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class CmpRm32R32Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the CmpRm32R32Handler class /// Initializes a new instance of the CmpRm32R32Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public CmpRm32R32Handler(InstructionDecoder decoder)
public CmpRm32R32Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,8 +34,8 @@ public class CmpRm32R32Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "cmp"; instruction.Type = InstructionType.Cmp;
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
@ -43,27 +43,20 @@ public class CmpRm32R32Handler : InstructionHandler
} }
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM(); // For CMP r/m32, r32 (0x39):
// - The r/m field with mod specifies the destination operand (register or memory)
// - The reg field specifies the source register
var (mod, reg, rm, destinationOperand) = ModRMDecoder.ReadModRM();
// Get the register name for the reg field // Create the source register operand
string regName = ModRMDecoder.GetRegisterName(reg, 32); var sourceOperand = OperandFactory.CreateRegisterOperand(reg, 32);
// Use the destOperand directly from ModRMDecoder // Set the structured operands
string rmOperand = destOperand; instruction.StructuredOperands =
[
// If it's a direct register operand, we need to remove the size prefix destinationOperand,
if (mod == 3) sourceOperand
{ ];
rmOperand = ModRMDecoder.GetRegisterName(rm, 32);
}
else if (rmOperand.StartsWith("dword ptr "))
{
// Remove the "dword ptr " prefix as we'll handle the operands differently
rmOperand = rmOperand.Substring(10);
}
// Set the operands
instruction.Operands = $"{rmOperand}, {regName}";
return true; return true;
} }

View File

@ -1,5 +1,7 @@
namespace X86Disassembler.X86.Handlers.Dec; namespace X86Disassembler.X86.Handlers.Dec;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for DEC r32 instructions (0x48-0x4F) /// Handler for DEC r32 instructions (0x48-0x4F)
/// </summary> /// </summary>
@ -8,11 +10,9 @@ public class DecRegHandler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the DecRegHandler class /// Initializes a new instance of the DecRegHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public DecRegHandler(InstructionDecoder decoder)
public DecRegHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -38,11 +38,17 @@ public class DecRegHandler : InstructionHandler
// Calculate the register index (0 for EAX, 1 for ECX, etc.) // Calculate the register index (0 for EAX, 1 for ECX, etc.)
RegisterIndex reg = (RegisterIndex)(opcode - 0x48); RegisterIndex reg = (RegisterIndex)(opcode - 0x48);
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "dec"; instruction.Type = InstructionType.Dec;
// Set the operand (register name) // Create the register operand
instruction.Operands = ModRMDecoder.GetRegisterName(reg, 32); var regOperand = OperandFactory.CreateRegisterOperand(reg, 32);
// Set the structured operands
instruction.StructuredOperands =
[
regOperand
];
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.FloatingPoint; namespace X86Disassembler.X86.Handlers.FloatingPoint;
/// <summary> /// <summary>
@ -18,14 +20,25 @@ public class Float32OperationHandler : InstructionHandler
"fdivr" "fdivr"
]; ];
// Corresponding instruction types for each mnemonic
private static readonly InstructionType[] InstructionTypes =
[
InstructionType.Fadd,
InstructionType.Fmul,
InstructionType.Fcom,
InstructionType.Fcomp,
InstructionType.Fsub,
InstructionType.Fsubr,
InstructionType.Fdiv,
InstructionType.Fdivr
];
/// <summary> /// <summary>
/// Initializes a new instance of the Float32OperationHandler class /// Initializes a new instance of the Float32OperationHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public Float32OperationHandler(InstructionDecoder decoder)
public Float32OperationHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -53,20 +66,35 @@ public class Float32OperationHandler : InstructionHandler
} }
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM(); var (mod, reg, rm, operand) = ModRMDecoder.ReadModRM();
// Set the mnemonic based on the opcode and reg field // Set the instruction type based on the reg field
instruction.Mnemonic = Mnemonics[(int)reg]; instruction.Type = InstructionTypes[(int)reg];
// For memory operands, set the operand // For memory operands, set the operand
if (mod != 3) // Memory operand if (mod != 3) // Memory operand
{ {
instruction.Operands = destOperand; // Ensure the memory operand has the correct size (32-bit float)
operand.Size = 32;
// Set the structured operands
instruction.StructuredOperands =
[
operand
];
} }
else // Register operand (ST(i)) else // Register operand (ST(i))
{ {
// For register operands, we need to handle the stack registers // For register operands, we need to handle the stack registers
instruction.Operands = $"st(0), st({(int)rm})"; var st0Operand = OperandFactory.CreateFPURegisterOperand(FpuRegisterIndex.ST0); // ST(0)
var stiOperand = OperandFactory.CreateFPURegisterOperand((FpuRegisterIndex)rm); // ST(i)
// Set the structured operands
instruction.StructuredOperands =
[
st0Operand,
stiOperand
];
} }
return true; return true;

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.FloatingPoint; namespace X86Disassembler.X86.Handlers.FloatingPoint;
/// <summary> /// <summary>
@ -18,14 +20,25 @@ public class Float64OperationHandler : InstructionHandler
"fdivr" "fdivr"
]; ];
// Corresponding instruction types for each mnemonic
private static readonly InstructionType[] InstructionTypes =
[
InstructionType.Fadd,
InstructionType.Fmul,
InstructionType.Fcom,
InstructionType.Fcomp,
InstructionType.Fsub,
InstructionType.Fsubr,
InstructionType.Fdiv,
InstructionType.Fdivr
];
/// <summary> /// <summary>
/// Initializes a new instance of the Float64OperationHandler class /// Initializes a new instance of the Float64OperationHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public Float64OperationHandler(InstructionDecoder decoder)
public Float64OperationHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -53,20 +66,35 @@ public class Float64OperationHandler : InstructionHandler
} }
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM(true); // true for 64-bit operand var (mod, reg, rm, operand) = ModRMDecoder.ReadModRM(true); // true for 64-bit operand
// Set the mnemonic based on the opcode and reg field // Set the instruction type based on the reg field
instruction.Mnemonic = Mnemonics[(int)reg]; instruction.Type = InstructionTypes[(int)reg];
// For memory operands, set the operand // For memory operands, set the operand
if (mod != 3) // Memory operand if (mod != 3) // Memory operand
{ {
instruction.Operands = destOperand; // Ensure the memory operand has the correct size (64-bit float)
operand.Size = 64;
// Set the structured operands
instruction.StructuredOperands =
[
operand
];
} }
else // Register operand (ST(i)) else // Register operand (ST(i))
{ {
// For DC C0-DC FF, the operands are reversed: ST(i), ST(0) // For DC C0-DC FF, the operands are reversed: ST(i), ST(0)
instruction.Operands = $"st({(int)rm}), st(0)"; var stiOperand = OperandFactory.CreateFPURegisterOperand((FpuRegisterIndex)rm); // ST(i)
var st0Operand = OperandFactory.CreateFPURegisterOperand(FpuRegisterIndex.ST0); // ST(0)
// Set the structured operands
instruction.StructuredOperands =
[
stiOperand,
st0Operand
];
} }
return true; return true;

View File

@ -1,5 +1,7 @@
namespace X86Disassembler.X86.Handlers.FloatingPoint; namespace X86Disassembler.X86.Handlers.FloatingPoint;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for FNSTSW AX instruction (0xDF 0xE0) /// Handler for FNSTSW AX instruction (0xDF 0xE0)
/// </summary> /// </summary>
@ -8,11 +10,9 @@ public class FnstswHandler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the FnstswHandler class /// Initializes a new instance of the FnstswHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public FnstswHandler(InstructionDecoder decoder)
public FnstswHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -24,20 +24,18 @@ public class FnstswHandler : InstructionHandler
public override bool CanHandle(byte opcode) public override bool CanHandle(byte opcode)
{ {
// FNSTSW is a two-byte opcode (0xDF 0xE0) // FNSTSW is a two-byte opcode (0xDF 0xE0)
if (opcode == 0xDF) if (opcode != 0xDF) return false;
{
if (!Decoder.CanReadByte())
{
return false;
}
if (CodeBuffer[Decoder.GetPosition()] == 0xE0) if (!Decoder.CanReadByte())
{ {
return true; return false;
}
} }
if (Decoder.PeakByte() != 0xE0)
return false;
return false; return true;
} }
/// <summary> /// <summary>
@ -61,9 +59,17 @@ public class FnstswHandler : InstructionHandler
return false; return false;
} }
// Set the mnemonic and operands // Set the instruction type
instruction.Mnemonic = "fnstsw"; instruction.Type = InstructionType.Fnstsw;
instruction.Operands = "ax";
// Create the AX register operand
var axOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.A, 16);
// Set the structured operands
instruction.StructuredOperands =
[
axOperand
];
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.FloatingPoint; namespace X86Disassembler.X86.Handlers.FloatingPoint;
/// <summary> /// <summary>
@ -5,95 +7,93 @@ namespace X86Disassembler.X86.Handlers.FloatingPoint;
/// </summary> /// </summary>
public class Int16OperationHandler : InstructionHandler public class Int16OperationHandler : InstructionHandler
{ {
// Memory operand mnemonics for DE opcode - operations on int16 // Memory operand instruction types for DE opcode - operations on int16
private static readonly string[] MemoryMnemonics = private static readonly InstructionType[] MemoryInstructionTypes =
[ [
"fiadd", // 0 InstructionType.Unknown, // fiadd - not in enum
"fimul", // 1 InstructionType.Unknown, // fimul - not in enum
"ficom", // 2 InstructionType.Unknown, // ficom - not in enum
"ficomp", // 3 InstructionType.Unknown, // ficomp - not in enum
"fisub", // 4 InstructionType.Unknown, // fisub - not in enum
"fisubr", // 5 InstructionType.Unknown, // fisubr - not in enum
"fidiv", // 6 InstructionType.Unknown, // fidiv - not in enum
"fidivr" // 7 InstructionType.Unknown // fidivr - not in enum
]; ];
// Register-register operations mapping (mod=3) // Register-register operations mapping (mod=3)
private static readonly Dictionary<(RegisterIndex Reg, RegisterIndex Rm), (string Mnemonic, string Operands)> RegisterOperations = new() private static readonly Dictionary<(int Reg, int Rm), (InstructionType Type, FpuRegisterIndex DestIndex, FpuRegisterIndex? SrcIndex)> RegisterOperations = new()
{ {
// FADDP st(i), st(0) // FADDP st(i), st(0)
{ (RegisterIndex.A, RegisterIndex.A), ("faddp", "st(0), st(0)") }, { (0, 0), (InstructionType.Fadd, FpuRegisterIndex.ST0, FpuRegisterIndex.ST0) },
{ (RegisterIndex.A, RegisterIndex.C), ("faddp", "st(1), st(0)") }, { (0, 1), (InstructionType.Fadd, FpuRegisterIndex.ST1, FpuRegisterIndex.ST0) },
{ (RegisterIndex.A, RegisterIndex.D), ("faddp", "st(2), st(0)") }, { (0, 2), (InstructionType.Fadd, FpuRegisterIndex.ST2, FpuRegisterIndex.ST0) },
{ (RegisterIndex.A, RegisterIndex.B), ("faddp", "st(3), st(0)") }, { (0, 3), (InstructionType.Fadd, FpuRegisterIndex.ST3, FpuRegisterIndex.ST0) },
{ (RegisterIndex.A, RegisterIndex.Sp), ("faddp", "st(4), st(0)") }, { (0, 4), (InstructionType.Fadd, FpuRegisterIndex.ST4, FpuRegisterIndex.ST0) },
{ (RegisterIndex.A, RegisterIndex.Bp), ("faddp", "st(5), st(0)") }, { (0, 5), (InstructionType.Fadd, FpuRegisterIndex.ST5, FpuRegisterIndex.ST0) },
{ (RegisterIndex.A, RegisterIndex.Si), ("faddp", "st(6), st(0)") }, { (0, 6), (InstructionType.Fadd, FpuRegisterIndex.ST6, FpuRegisterIndex.ST0) },
{ (RegisterIndex.A, RegisterIndex.Di), ("faddp", "st(7), st(0)") }, { (0, 7), (InstructionType.Fadd, FpuRegisterIndex.ST7, FpuRegisterIndex.ST0) },
// FMULP st(i), st(0) // FMULP st(i), st(0)
{ (RegisterIndex.B, RegisterIndex.A), ("fmulp", "st(0), st(0)") }, { (1, 0), (InstructionType.Fmul, FpuRegisterIndex.ST0, FpuRegisterIndex.ST0) },
{ (RegisterIndex.B, RegisterIndex.C), ("fmulp", "st(1), st(0)") }, { (1, 1), (InstructionType.Fmul, FpuRegisterIndex.ST1, FpuRegisterIndex.ST0) },
{ (RegisterIndex.B, RegisterIndex.D), ("fmulp", "st(2), st(0)") }, { (1, 2), (InstructionType.Fmul, FpuRegisterIndex.ST2, FpuRegisterIndex.ST0) },
{ (RegisterIndex.B, RegisterIndex.B), ("fmulp", "st(3), st(0)") }, { (1, 3), (InstructionType.Fmul, FpuRegisterIndex.ST3, FpuRegisterIndex.ST0) },
{ (RegisterIndex.B, RegisterIndex.Sp), ("fmulp", "st(4), st(0)") }, { (1, 4), (InstructionType.Fmul, FpuRegisterIndex.ST4, FpuRegisterIndex.ST0) },
{ (RegisterIndex.B, RegisterIndex.Bp), ("fmulp", "st(5), st(0)") }, { (1, 5), (InstructionType.Fmul, FpuRegisterIndex.ST5, FpuRegisterIndex.ST0) },
{ (RegisterIndex.B, RegisterIndex.Si), ("fmulp", "st(6), st(0)") }, { (1, 6), (InstructionType.Fmul, FpuRegisterIndex.ST6, FpuRegisterIndex.ST0) },
{ (RegisterIndex.B, RegisterIndex.Di), ("fmulp", "st(7), st(0)") }, { (1, 7), (InstructionType.Fmul, FpuRegisterIndex.ST7, FpuRegisterIndex.ST0) },
// Special cases // Special cases
{ (RegisterIndex.C, RegisterIndex.B), ("fcomp", "") }, { (2, 3), (InstructionType.Fcomp, FpuRegisterIndex.ST0, null) },
{ (RegisterIndex.D, RegisterIndex.B), ("fcompp", "") }, { (3, 3), (InstructionType.Fcompp, FpuRegisterIndex.ST0, null) },
// FSUBP st(i), st(0) // FSUBP st(i), st(0)
{ (RegisterIndex.Si, RegisterIndex.A), ("fsubp", "st(0), st(0)") }, { (6, 0), (InstructionType.Fsub, FpuRegisterIndex.ST0, FpuRegisterIndex.ST0) },
{ (RegisterIndex.Si, RegisterIndex.C), ("fsubp", "st(1), st(0)") }, { (6, 1), (InstructionType.Fsub, FpuRegisterIndex.ST1, FpuRegisterIndex.ST0) },
{ (RegisterIndex.Si, RegisterIndex.D), ("fsubp", "st(2), st(0)") }, { (6, 2), (InstructionType.Fsub, FpuRegisterIndex.ST2, FpuRegisterIndex.ST0) },
{ (RegisterIndex.Si, RegisterIndex.B), ("fsubp", "st(3), st(0)") }, { (6, 3), (InstructionType.Fsub, FpuRegisterIndex.ST3, FpuRegisterIndex.ST0) },
{ (RegisterIndex.Si, RegisterIndex.Sp), ("fsubp", "st(4), st(0)") }, { (6, 4), (InstructionType.Fsub, FpuRegisterIndex.ST4, FpuRegisterIndex.ST0) },
{ (RegisterIndex.Si, RegisterIndex.Bp), ("fsubp", "st(5), st(0)") }, { (6, 5), (InstructionType.Fsub, FpuRegisterIndex.ST5, FpuRegisterIndex.ST0) },
{ (RegisterIndex.Si, RegisterIndex.Si), ("fsubp", "st(6), st(0)") }, { (6, 6), (InstructionType.Fsub, FpuRegisterIndex.ST6, FpuRegisterIndex.ST0) },
{ (RegisterIndex.Si, RegisterIndex.Di), ("fsubp", "st(7), st(0)") }, { (6, 7), (InstructionType.Fsub, FpuRegisterIndex.ST7, FpuRegisterIndex.ST0) },
// FSUBRP st(i), st(0) // FSUBRP st(i), st(0)
{ (RegisterIndex.Di, RegisterIndex.A), ("fsubrp", "st(0), st(0)") }, { (7, 0), (InstructionType.Fsubr, FpuRegisterIndex.ST0, FpuRegisterIndex.ST0) },
{ (RegisterIndex.Di, RegisterIndex.C), ("fsubrp", "st(1), st(0)") }, { (7, 1), (InstructionType.Fsubr, FpuRegisterIndex.ST1, FpuRegisterIndex.ST0) },
{ (RegisterIndex.Di, RegisterIndex.D), ("fsubrp", "st(2), st(0)") }, { (7, 2), (InstructionType.Fsubr, FpuRegisterIndex.ST2, FpuRegisterIndex.ST0) },
{ (RegisterIndex.Di, RegisterIndex.B), ("fsubrp", "st(3), st(0)") }, { (7, 3), (InstructionType.Fsubr, FpuRegisterIndex.ST3, FpuRegisterIndex.ST0) },
{ (RegisterIndex.Di, RegisterIndex.Sp), ("fsubrp", "st(4), st(0)") }, { (7, 4), (InstructionType.Fsubr, FpuRegisterIndex.ST4, FpuRegisterIndex.ST0) },
{ (RegisterIndex.Di, RegisterIndex.Bp), ("fsubrp", "st(5), st(0)") }, { (7, 5), (InstructionType.Fsubr, FpuRegisterIndex.ST5, FpuRegisterIndex.ST0) },
{ (RegisterIndex.Di, RegisterIndex.Si), ("fsubrp", "st(6), st(0)") }, { (7, 6), (InstructionType.Fsubr, FpuRegisterIndex.ST6, FpuRegisterIndex.ST0) },
{ (RegisterIndex.Di, RegisterIndex.Di), ("fsubrp", "st(7), st(0)") }, { (7, 7), (InstructionType.Fsubr, FpuRegisterIndex.ST7, FpuRegisterIndex.ST0) },
// FDIVP st(i), st(0) // FDIVP st(i), st(0)
{ (RegisterIndex.Sp, RegisterIndex.A), ("fdivp", "st(0), st(0)") }, { (4, 0), (InstructionType.Fdiv, FpuRegisterIndex.ST0, FpuRegisterIndex.ST0) },
{ (RegisterIndex.Sp, RegisterIndex.C), ("fdivp", "st(1), st(0)") }, { (4, 1), (InstructionType.Fdiv, FpuRegisterIndex.ST1, FpuRegisterIndex.ST0) },
{ (RegisterIndex.Sp, RegisterIndex.D), ("fdivp", "st(2), st(0)") }, { (4, 2), (InstructionType.Fdiv, FpuRegisterIndex.ST2, FpuRegisterIndex.ST0) },
{ (RegisterIndex.Sp, RegisterIndex.B), ("fdivp", "st(3), st(0)") }, { (4, 3), (InstructionType.Fdiv, FpuRegisterIndex.ST3, FpuRegisterIndex.ST0) },
{ (RegisterIndex.Sp, RegisterIndex.Sp), ("fdivp", "st(4), st(0)") }, { (4, 4), (InstructionType.Fdiv, FpuRegisterIndex.ST4, FpuRegisterIndex.ST0) },
{ (RegisterIndex.Sp, RegisterIndex.Bp), ("fdivp", "st(5), st(0)") }, { (4, 5), (InstructionType.Fdiv, FpuRegisterIndex.ST5, FpuRegisterIndex.ST0) },
{ (RegisterIndex.Sp, RegisterIndex.Si), ("fdivp", "st(6), st(0)") }, { (4, 6), (InstructionType.Fdiv, FpuRegisterIndex.ST6, FpuRegisterIndex.ST0) },
{ (RegisterIndex.Sp, RegisterIndex.Di), ("fdivp", "st(7), st(0)") }, { (4, 7), (InstructionType.Fdiv, FpuRegisterIndex.ST7, FpuRegisterIndex.ST0) },
// FDIVRP st(i), st(0) // FDIVRP st(i), st(0)
{ (RegisterIndex.Bp, RegisterIndex.A), ("fdivrp", "st(0), st(0)") }, { (5, 0), (InstructionType.Fdivr, FpuRegisterIndex.ST0, FpuRegisterIndex.ST0) },
{ (RegisterIndex.Bp, RegisterIndex.C), ("fdivrp", "st(1), st(0)") }, { (5, 1), (InstructionType.Fdivr, FpuRegisterIndex.ST1, FpuRegisterIndex.ST0) },
{ (RegisterIndex.Bp, RegisterIndex.D), ("fdivrp", "st(2), st(0)") }, { (5, 2), (InstructionType.Fdivr, FpuRegisterIndex.ST2, FpuRegisterIndex.ST0) },
{ (RegisterIndex.Bp, RegisterIndex.B), ("fdivrp", "st(3), st(0)") }, { (5, 3), (InstructionType.Fdivr, FpuRegisterIndex.ST3, FpuRegisterIndex.ST0) },
{ (RegisterIndex.Bp, RegisterIndex.Sp), ("fdivrp", "st(4), st(0)") }, { (5, 4), (InstructionType.Fdivr, FpuRegisterIndex.ST4, FpuRegisterIndex.ST0) },
{ (RegisterIndex.Bp, RegisterIndex.Bp), ("fdivrp", "st(5), st(0)") }, { (5, 5), (InstructionType.Fdivr, FpuRegisterIndex.ST5, FpuRegisterIndex.ST0) },
{ (RegisterIndex.Bp, RegisterIndex.Si), ("fdivrp", "st(6), st(0)") }, { (5, 6), (InstructionType.Fdivr, FpuRegisterIndex.ST6, FpuRegisterIndex.ST0) },
{ (RegisterIndex.Bp, RegisterIndex.Di), ("fdivrp", "st(7), st(0)") } { (5, 7), (InstructionType.Fdivr, FpuRegisterIndex.ST7, FpuRegisterIndex.ST0) }
}; };
/// <summary> /// <summary>
/// Initializes a new instance of the Int16OperationHandler class /// Initializes a new instance of the Int16OperationHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public Int16OperationHandler(InstructionDecoder decoder)
public Int16OperationHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -121,30 +121,58 @@ public class Int16OperationHandler : InstructionHandler
} }
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, memOperand) = ModRMDecoder.ReadModRM(); var (mod, reg, rm, memoryOperand) = ModRMDecoder.ReadModRM();
// Handle based on addressing mode // Handle based on addressing mode
if (mod != 3) // Memory operand if (mod != 3) // Memory operand
{ {
// Set the mnemonic based on the reg field // Set the instruction type based on the reg field
instruction.Mnemonic = MemoryMnemonics[(int)reg]; instruction.Type = MemoryInstructionTypes[(int)reg];
// Need to modify the default dword ptr to word ptr for 16-bit integers // For memory operands, we need to set the size to 16-bit
instruction.Operands = memOperand.Replace("dword ptr", "word ptr"); // Create a new memory operand with 16-bit size
var int16Operand = memoryOperand;
int16Operand.Size = 16;
// Set the structured operands
instruction.StructuredOperands =
[
int16Operand
];
} }
else // Register operand (ST(i)) else // Register operand (ST(i))
{ {
// Look up the register operation in our dictionary // Look up the instruction type in the register operations dictionary
if (RegisterOperations.TryGetValue((reg, rm), out var operation)) if (RegisterOperations.TryGetValue(((int)reg, (int)rm), out var operation))
{ {
instruction.Mnemonic = operation.Mnemonic; instruction.Type = operation.Type;
instruction.Operands = operation.Operands;
// 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 else
{ {
// Unknown instruction // Unknown instruction
instruction.Mnemonic = "??"; instruction.Type = InstructionType.Unknown;
instruction.Operands = ""; instruction.StructuredOperands = [];
} }
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.FloatingPoint; namespace X86Disassembler.X86.Handlers.FloatingPoint;
/// <summary> /// <summary>
@ -5,74 +7,72 @@ namespace X86Disassembler.X86.Handlers.FloatingPoint;
/// </summary> /// </summary>
public class Int32OperationHandler : InstructionHandler public class Int32OperationHandler : InstructionHandler
{ {
// Memory operand mnemonics for DA opcode - operations on int32 // Memory operand instruction types for DA opcode - operations on int32
private static readonly string[] MemoryMnemonics = private static readonly InstructionType[] MemoryInstructionTypes =
[ [
"fiadd", // 0 InstructionType.Unknown, // fiadd - not in enum
"fimul", // 1 InstructionType.Unknown, // fimul - not in enum
"ficom", // 2 InstructionType.Unknown, // ficom - not in enum
"ficomp", // 3 InstructionType.Unknown, // ficomp - not in enum
"fisub", // 4 InstructionType.Unknown, // fisub - not in enum
"fisubr", // 5 InstructionType.Unknown, // fisubr - not in enum
"fidiv", // 6 InstructionType.Unknown, // fidiv - not in enum
"fidivr" // 7 InstructionType.Unknown // fidivr - not in enum
]; ];
// Register-register operations mapping (mod=3) // Register-register operations mapping (mod=3)
private static readonly Dictionary<(RegisterIndex Reg, RegisterIndex Rm), (string Mnemonic, string Operands)> RegisterOperations = new() private static readonly Dictionary<(RegisterIndex Reg, RegisterIndex Rm), (InstructionType Type, FpuRegisterIndex DestIndex, FpuRegisterIndex SrcIndex)> RegisterOperations = new()
{ {
// FCMOVB st(0), st(i) // FCMOVB st(0), st(i)
{ (RegisterIndex.A, RegisterIndex.A), ("fcmovb", "st(0), st(0)") }, { (RegisterIndex.A, RegisterIndex.A), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST0) },
{ (RegisterIndex.A, RegisterIndex.C), ("fcmovb", "st(0), st(1)") }, { (RegisterIndex.A, RegisterIndex.C), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST1) },
{ (RegisterIndex.A, RegisterIndex.D), ("fcmovb", "st(0), st(2)") }, { (RegisterIndex.A, RegisterIndex.D), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST2) },
{ (RegisterIndex.A, RegisterIndex.B), ("fcmovb", "st(0), st(3)") }, { (RegisterIndex.A, RegisterIndex.B), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST3) },
{ (RegisterIndex.A, RegisterIndex.Sp), ("fcmovb", "st(0), st(4)") }, { (RegisterIndex.A, RegisterIndex.Sp), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST4) },
{ (RegisterIndex.A, RegisterIndex.Bp), ("fcmovb", "st(0), st(5)") }, { (RegisterIndex.A, RegisterIndex.Bp), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST5) },
{ (RegisterIndex.A, RegisterIndex.Si), ("fcmovb", "st(0), st(6)") }, { (RegisterIndex.A, RegisterIndex.Si), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST6) },
{ (RegisterIndex.A, RegisterIndex.Di), ("fcmovb", "st(0), st(7)") }, { (RegisterIndex.A, RegisterIndex.Di), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST7) },
// FCMOVE st(0), st(i) // FCMOVE st(0), st(i)
{ (RegisterIndex.B, RegisterIndex.A), ("fcmove", "st(0), st(0)") }, { (RegisterIndex.B, RegisterIndex.A), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST0) },
{ (RegisterIndex.B, RegisterIndex.C), ("fcmove", "st(0), st(1)") }, { (RegisterIndex.B, RegisterIndex.C), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST1) },
{ (RegisterIndex.B, RegisterIndex.D), ("fcmove", "st(0), st(2)") }, { (RegisterIndex.B, RegisterIndex.D), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST2) },
{ (RegisterIndex.B, RegisterIndex.B), ("fcmove", "st(0), st(3)") }, { (RegisterIndex.B, RegisterIndex.B), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST3) },
{ (RegisterIndex.B, RegisterIndex.Sp), ("fcmove", "st(0), st(4)") }, { (RegisterIndex.B, RegisterIndex.Sp), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST4) },
{ (RegisterIndex.B, RegisterIndex.Bp), ("fcmove", "st(0), st(5)") }, { (RegisterIndex.B, RegisterIndex.Bp), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST5) },
{ (RegisterIndex.B, RegisterIndex.Si), ("fcmove", "st(0), st(6)") }, { (RegisterIndex.B, RegisterIndex.Si), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST6) },
{ (RegisterIndex.B, RegisterIndex.Di), ("fcmove", "st(0), st(7)") }, { (RegisterIndex.B, RegisterIndex.Di), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST7) },
// FCMOVBE st(0), st(i) // FCMOVBE st(0), st(i)
{ (RegisterIndex.C, RegisterIndex.A), ("fcmovbe", "st(0), st(0)") }, { (RegisterIndex.C, RegisterIndex.A), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST0) },
{ (RegisterIndex.C, RegisterIndex.C), ("fcmovbe", "st(0), st(1)") }, { (RegisterIndex.C, RegisterIndex.C), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST1) },
{ (RegisterIndex.C, RegisterIndex.D), ("fcmovbe", "st(0), st(2)") }, { (RegisterIndex.C, RegisterIndex.D), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST2) },
{ (RegisterIndex.C, RegisterIndex.B), ("fcmovbe", "st(0), st(3)") }, { (RegisterIndex.C, RegisterIndex.B), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST3) },
{ (RegisterIndex.C, RegisterIndex.Sp), ("fcmovbe", "st(0), st(4)") }, { (RegisterIndex.C, RegisterIndex.Sp), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST4) },
{ (RegisterIndex.C, RegisterIndex.Bp), ("fcmovbe", "st(0), st(5)") }, { (RegisterIndex.C, RegisterIndex.Bp), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST5) },
{ (RegisterIndex.C, RegisterIndex.Si), ("fcmovbe", "st(0), st(6)") }, { (RegisterIndex.C, RegisterIndex.Si), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST6) },
{ (RegisterIndex.C, RegisterIndex.Di), ("fcmovbe", "st(0), st(7)") }, { (RegisterIndex.C, RegisterIndex.Di), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST7) },
// FCMOVU st(0), st(i) // FCMOVU st(0), st(i)
{ (RegisterIndex.D, RegisterIndex.A), ("fcmovu", "st(0), st(0)") }, { (RegisterIndex.D, RegisterIndex.A), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST0) },
{ (RegisterIndex.D, RegisterIndex.C), ("fcmovu", "st(0), st(1)") }, { (RegisterIndex.D, RegisterIndex.C), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST1) },
{ (RegisterIndex.D, RegisterIndex.D), ("fcmovu", "st(0), st(2)") }, { (RegisterIndex.D, RegisterIndex.D), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST2) },
{ (RegisterIndex.D, RegisterIndex.B), ("fcmovu", "st(0), st(3)") }, { (RegisterIndex.D, RegisterIndex.B), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST3) },
{ (RegisterIndex.D, RegisterIndex.Sp), ("fcmovu", "st(0), st(4)") }, { (RegisterIndex.D, RegisterIndex.Sp), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST4) },
{ (RegisterIndex.D, RegisterIndex.Bp), ("fcmovu", "st(0), st(5)") }, { (RegisterIndex.D, RegisterIndex.Bp), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST5) },
{ (RegisterIndex.D, RegisterIndex.Si), ("fcmovu", "st(0), st(6)") }, { (RegisterIndex.D, RegisterIndex.Si), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST6) },
{ (RegisterIndex.D, RegisterIndex.Di), ("fcmovu", "st(0), st(7)") }, { (RegisterIndex.D, RegisterIndex.Di), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST7) },
// Special case // Special case
{ (RegisterIndex.Di, RegisterIndex.B), ("fucompp", "") } { (RegisterIndex.Di, RegisterIndex.B), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST0) }
}; };
/// <summary> /// <summary>
/// Initializes a new instance of the Int32OperationHandler class /// Initializes a new instance of the Int32OperationHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public Int32OperationHandler(InstructionDecoder decoder)
public Int32OperationHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -100,30 +100,43 @@ public class Int32OperationHandler : InstructionHandler
} }
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, memOperand) = ModRMDecoder.ReadModRM(); var (mod, reg, rm, memoryOperand) = ModRMDecoder.ReadModRM();
// Handle based on addressing mode // Handle based on addressing mode
if (mod != 3) // Memory operand if (mod != 3) // Memory operand
{ {
// Set the mnemonic based on the reg field // Set the instruction type based on the reg field
instruction.Mnemonic = MemoryMnemonics[(int)reg]; instruction.Type = MemoryInstructionTypes[(int)reg];
// Set the operands (already has dword ptr prefix for int32) // Set the structured operands
instruction.Operands = memOperand; instruction.StructuredOperands =
[
memoryOperand
];
} }
else // Register operand (ST(i)) else // Register operand (ST(i))
{ {
// Look up the register operation in our dictionary // Look up the instruction type in the register operations dictionary
if (RegisterOperations.TryGetValue((reg, rm), out var operation)) if (RegisterOperations.TryGetValue((reg, rm), out var operation))
{ {
instruction.Mnemonic = operation.Mnemonic; instruction.Type = operation.Type;
instruction.Operands = operation.Operands;
// Create the FPU register operands
var destOperand = OperandFactory.CreateFPURegisterOperand(operation.DestIndex);
var srcOperand = OperandFactory.CreateFPURegisterOperand(operation.SrcIndex);
// Set the structured operands
instruction.StructuredOperands =
[
destOperand,
srcOperand
];
} }
else else
{ {
// Unknown instruction // Unknown instruction
instruction.Mnemonic = "??"; instruction.Type = InstructionType.Unknown;
instruction.Operands = ""; instruction.StructuredOperands = [];
} }
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.FloatingPoint; namespace X86Disassembler.X86.Handlers.FloatingPoint;
/// <summary> /// <summary>
@ -5,81 +7,79 @@ namespace X86Disassembler.X86.Handlers.FloatingPoint;
/// </summary> /// </summary>
public class LoadStoreControlHandler : InstructionHandler public class LoadStoreControlHandler : InstructionHandler
{ {
// Memory operand mnemonics for D9 opcode - load, store, and control operations // Memory operand instruction types for D9 opcode - load, store, and control operations
private static readonly string[] MemoryMnemonics = private static readonly InstructionType[] MemoryInstructionTypes =
[ [
"fld", // 0 InstructionType.Fld, // 0
"??", // 1 InstructionType.Unknown, // 1
"fst", // 2 InstructionType.Fst, // 2
"fstp", // 3 InstructionType.Fstp, // 3
"fldenv", // 4 InstructionType.Unknown, // 4 - fldenv not in enum
"fldcw", // 5 InstructionType.Fldcw, // 5
"fnstenv", // 6 InstructionType.Unknown, // 6 - fnstenv not in enum
"fnstcw" // 7 InstructionType.Fnstcw // 7
]; ];
// Register-register operations mapping (mod=3) // Register-register operations mapping (mod=3)
private static readonly Dictionary<(RegisterIndex Reg, RegisterIndex Rm), (string Mnemonic, string Operands)> RegisterOperations = new() private static readonly Dictionary<(RegisterIndex Reg, RegisterIndex Rm), (InstructionType Type, FpuRegisterIndex? OperandIndex)> RegisterOperations = new()
{ {
// FLD ST(i) // FLD ST(i)
{ (RegisterIndex.A, RegisterIndex.A), ("fld", "st(0)") }, { (RegisterIndex.A, RegisterIndex.A), (InstructionType.Fld, FpuRegisterIndex.ST0) },
{ (RegisterIndex.A, RegisterIndex.C), ("fld", "st(1)") }, { (RegisterIndex.A, RegisterIndex.C), (InstructionType.Fld, FpuRegisterIndex.ST1) },
{ (RegisterIndex.A, RegisterIndex.D), ("fld", "st(2)") }, { (RegisterIndex.A, RegisterIndex.D), (InstructionType.Fld, FpuRegisterIndex.ST2) },
{ (RegisterIndex.A, RegisterIndex.B), ("fld", "st(3)") }, { (RegisterIndex.A, RegisterIndex.B), (InstructionType.Fld, FpuRegisterIndex.ST3) },
{ (RegisterIndex.A, RegisterIndex.Sp), ("fld", "st(4)") }, { (RegisterIndex.A, RegisterIndex.Sp), (InstructionType.Fld, FpuRegisterIndex.ST4) },
{ (RegisterIndex.A, RegisterIndex.Bp), ("fld", "st(5)") }, { (RegisterIndex.A, RegisterIndex.Bp), (InstructionType.Fld, FpuRegisterIndex.ST5) },
{ (RegisterIndex.A, RegisterIndex.Si), ("fld", "st(6)") }, { (RegisterIndex.A, RegisterIndex.Si), (InstructionType.Fld, FpuRegisterIndex.ST6) },
{ (RegisterIndex.A, RegisterIndex.Di), ("fld", "st(7)") }, { (RegisterIndex.A, RegisterIndex.Di), (InstructionType.Fld, FpuRegisterIndex.ST7) },
// FXCH ST(i) // FXCH ST(i)
{ (RegisterIndex.B, RegisterIndex.A), ("fxch", "st(0)") }, { (RegisterIndex.B, RegisterIndex.A), (InstructionType.Fxch, FpuRegisterIndex.ST0) },
{ (RegisterIndex.B, RegisterIndex.C), ("fxch", "st(1)") }, { (RegisterIndex.B, RegisterIndex.C), (InstructionType.Fxch, FpuRegisterIndex.ST1) },
{ (RegisterIndex.B, RegisterIndex.D), ("fxch", "st(2)") }, { (RegisterIndex.B, RegisterIndex.D), (InstructionType.Fxch, FpuRegisterIndex.ST2) },
{ (RegisterIndex.B, RegisterIndex.B), ("fxch", "st(3)") }, { (RegisterIndex.B, RegisterIndex.B), (InstructionType.Fxch, FpuRegisterIndex.ST3) },
{ (RegisterIndex.B, RegisterIndex.Sp), ("fxch", "st(4)") }, { (RegisterIndex.B, RegisterIndex.Sp), (InstructionType.Fxch, FpuRegisterIndex.ST4) },
{ (RegisterIndex.B, RegisterIndex.Bp), ("fxch", "st(5)") }, { (RegisterIndex.B, RegisterIndex.Bp), (InstructionType.Fxch, FpuRegisterIndex.ST5) },
{ (RegisterIndex.B, RegisterIndex.Si), ("fxch", "st(6)") }, { (RegisterIndex.B, RegisterIndex.Si), (InstructionType.Fxch, FpuRegisterIndex.ST6) },
{ (RegisterIndex.B, RegisterIndex.Di), ("fxch", "st(7)") }, { (RegisterIndex.B, RegisterIndex.Di), (InstructionType.Fxch, FpuRegisterIndex.ST7) },
// D9E0-D9EF special instructions (reg=6) // D9E0-D9EF special instructions (reg=6)
{ (RegisterIndex.Si, RegisterIndex.A), ("fchs", "") }, { (RegisterIndex.Si, RegisterIndex.A), (InstructionType.Fchs, null) },
{ (RegisterIndex.Si, RegisterIndex.B), ("fabs", "") }, { (RegisterIndex.Si, RegisterIndex.B), (InstructionType.Fabs, null) },
{ (RegisterIndex.Si, RegisterIndex.Si), ("ftst", "") }, { (RegisterIndex.Si, RegisterIndex.Si), (InstructionType.Ftst, null) },
{ (RegisterIndex.Si, RegisterIndex.Di), ("fxam", "") }, { (RegisterIndex.Si, RegisterIndex.Di), (InstructionType.Fxam, null) },
// D9F0-D9FF special instructions (reg=7) // D9F0-D9FF special instructions (reg=7)
{ (RegisterIndex.Di, RegisterIndex.A), ("f2xm1", "") }, { (RegisterIndex.Di, RegisterIndex.A), (InstructionType.Unknown, null) }, // f2xm1 not in enum
{ (RegisterIndex.Di, RegisterIndex.B), ("fyl2x", "") }, { (RegisterIndex.Di, RegisterIndex.B), (InstructionType.Unknown, null) }, // fyl2x not in enum
{ (RegisterIndex.Di, RegisterIndex.C), ("fptan", "") }, { (RegisterIndex.Di, RegisterIndex.C), (InstructionType.Unknown, null) }, // fptan not in enum
{ (RegisterIndex.Di, RegisterIndex.D), ("fpatan", "") }, { (RegisterIndex.Di, RegisterIndex.D), (InstructionType.Unknown, null) }, // fpatan not in enum
{ (RegisterIndex.Di, RegisterIndex.Si), ("fxtract", "") }, { (RegisterIndex.Di, RegisterIndex.Si), (InstructionType.Unknown, null) }, // fxtract not in enum
{ (RegisterIndex.Di, RegisterIndex.Di), ("fprem1", "") }, { (RegisterIndex.Di, RegisterIndex.Di), (InstructionType.Unknown, null) }, // fprem1 not in enum
{ (RegisterIndex.Di, RegisterIndex.Sp), ("fdecstp", "") }, { (RegisterIndex.Di, RegisterIndex.Sp), (InstructionType.Unknown, null) }, // fdecstp not in enum
{ (RegisterIndex.Di, RegisterIndex.Bp), ("fincstp", "") }, { (RegisterIndex.Di, RegisterIndex.Bp), (InstructionType.Unknown, null) }, // fincstp not in enum
// D9D0-D9DF special instructions (reg=5) // D9D0-D9DF special instructions (reg=5)
{ (RegisterIndex.Sp, RegisterIndex.A), ("fprem", "") }, { (RegisterIndex.Sp, RegisterIndex.A), (InstructionType.Unknown, null) }, // fprem not in enum
{ (RegisterIndex.Sp, RegisterIndex.B), ("fyl2xp1", "") }, { (RegisterIndex.Sp, RegisterIndex.B), (InstructionType.Unknown, null) }, // fyl2xp1 not in enum
{ (RegisterIndex.Sp, RegisterIndex.C), ("fsqrt", "") }, { (RegisterIndex.Sp, RegisterIndex.C), (InstructionType.Unknown, null) }, // fsqrt not in enum
{ (RegisterIndex.Sp, RegisterIndex.D), ("fsincos", "") }, { (RegisterIndex.Sp, RegisterIndex.D), (InstructionType.Unknown, null) }, // fsincos not in enum
{ (RegisterIndex.Sp, RegisterIndex.Si), ("frndint", "") }, { (RegisterIndex.Sp, RegisterIndex.Si), (InstructionType.Unknown, null) }, // frndint not in enum
{ (RegisterIndex.Sp, RegisterIndex.Di), ("fscale", "") }, { (RegisterIndex.Sp, RegisterIndex.Di), (InstructionType.Unknown, null) }, // fscale not in enum
{ (RegisterIndex.Sp, RegisterIndex.Sp), ("fsin", "") }, { (RegisterIndex.Sp, RegisterIndex.Sp), (InstructionType.Unknown, null) }, // fsin not in enum
{ (RegisterIndex.Sp, RegisterIndex.Bp), ("fcos", "") }, { (RegisterIndex.Sp, RegisterIndex.Bp), (InstructionType.Unknown, null) }, // fcos not in enum
// D9C8-D9CF special instructions (reg=4) // D9C8-D9CF special instructions (reg=4)
{ (RegisterIndex.Bp, RegisterIndex.A), ("fnop", "") }, { (RegisterIndex.Bp, RegisterIndex.A), (InstructionType.Unknown, null) }, // fnop not in enum
{ (RegisterIndex.Bp, RegisterIndex.C), ("fwait", "") } { (RegisterIndex.Bp, RegisterIndex.C), (InstructionType.Unknown, null) } // fwait not in enum
}; };
/// <summary> /// <summary>
/// Initializes a new instance of the LoadStoreControlHandler class /// Initializes a new instance of the LoadStoreControlHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public LoadStoreControlHandler(InstructionDecoder decoder)
public LoadStoreControlHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -107,46 +107,59 @@ public class LoadStoreControlHandler : InstructionHandler
} }
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, memOperand) = ModRMDecoder.ReadModRM(); var (mod, reg, rm, memoryOperand) = ModRMDecoder.ReadModRM();
// Handle based on addressing mode // Handle based on addressing mode
if (mod != 3) // Memory operand if (mod != 3) // Memory operand
{ {
// Set the mnemonic based on the reg field // Set the instruction type based on the reg field
instruction.Mnemonic = MemoryMnemonics[(int)reg]; instruction.Type = MemoryInstructionTypes[(int)reg];
// Different operand types based on the instruction // Set the size based on the operation
if (reg == RegisterIndex.A || reg == RegisterIndex.C || reg == RegisterIndex.D) // fld, fst, fstp if (reg == RegisterIndex.A || reg == RegisterIndex.C || reg == RegisterIndex.D) // fld, fst, fstp
{ {
// Keep the dword ptr prefix from ModRMDecoder // Keep the default 32-bit size for floating point operations
instruction.Operands = memOperand; memoryOperand.Size = 32;
} }
else // fldenv, fldcw, fnstenv, fnstcw else if (reg == RegisterIndex.Di || reg == RegisterIndex.Bp) // fldcw, fnstcw
{ {
if (reg == RegisterIndex.Di) // fldcw - should use word ptr // Set to 16-bit for control word operations
{ memoryOperand.Size = 16;
instruction.Operands = memOperand.Replace("dword ptr", "word ptr");
}
else // fldenv, fnstenv, fnstcw
{
// Remove the dword ptr prefix for other control operations
instruction.Operands = memOperand.Replace("dword ptr ", "");
}
} }
// Set the structured operands
instruction.StructuredOperands =
[
memoryOperand
];
} }
else // Register operand (ST(i)) else // Register operand (ST(i))
{ {
// Look up the register operation in our dictionary // Look up the instruction type in the register operations dictionary
if (RegisterOperations.TryGetValue((reg, rm), out var operation)) if (RegisterOperations.TryGetValue((reg, rm), out var operation))
{ {
instruction.Mnemonic = operation.Mnemonic; instruction.Type = operation.Type;
instruction.Operands = operation.Operands;
// Set the structured operands
if (operation.OperandIndex.HasValue)
{
var operand = OperandFactory.CreateFPURegisterOperand(operation.OperandIndex.Value);
instruction.StructuredOperands =
[
operand
];
}
else
{
// No operands for instructions like fchs, fabs, etc.
instruction.StructuredOperands = [];
}
} }
else else
{ {
// Unknown instruction // Unknown instruction
instruction.Mnemonic = "??"; instruction.Type = InstructionType.Unknown;
instruction.Operands = ""; instruction.StructuredOperands = [];
} }
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.FloatingPoint; namespace X86Disassembler.X86.Handlers.FloatingPoint;
/// <summary> /// <summary>
@ -18,68 +20,79 @@ public class LoadStoreFloat64Handler : InstructionHandler
"fnstsw" // 7 "fnstsw" // 7
]; ];
// Memory operand instruction types for DD opcode
private static readonly InstructionType[] MemoryInstructionTypes =
[
InstructionType.Fld, // 0
InstructionType.Unknown, // 1
InstructionType.Fst, // 2
InstructionType.Fstp, // 3
InstructionType.Unknown, // 4 - frstor not in enum
InstructionType.Unknown, // 5
InstructionType.Unknown, // 6 - fnsave not in enum
InstructionType.Fnstsw // 7
];
// Register-register operations mapping (mod=3) // Register-register operations mapping (mod=3)
private static readonly Dictionary<(RegisterIndex Reg, RegisterIndex Rm), (string Mnemonic, string Operands)> RegisterOperations = new() private static readonly Dictionary<(RegisterIndex Reg, RegisterIndex Rm), (InstructionType Type, FpuRegisterIndex OperandIndex)> RegisterOperations = new()
{ {
// FFREE ST(i) // FFREE ST(i)
{ (RegisterIndex.A, RegisterIndex.A), ("ffree", "st(0)") }, { (RegisterIndex.A, RegisterIndex.A), (InstructionType.Unknown, FpuRegisterIndex.ST0) },
{ (RegisterIndex.A, RegisterIndex.C), ("ffree", "st(1)") }, { (RegisterIndex.A, RegisterIndex.C), (InstructionType.Unknown, FpuRegisterIndex.ST1) },
{ (RegisterIndex.A, RegisterIndex.D), ("ffree", "st(2)") }, { (RegisterIndex.A, RegisterIndex.D), (InstructionType.Unknown, FpuRegisterIndex.ST2) },
{ (RegisterIndex.A, RegisterIndex.B), ("ffree", "st(3)") }, { (RegisterIndex.A, RegisterIndex.B), (InstructionType.Unknown, FpuRegisterIndex.ST3) },
{ (RegisterIndex.A, RegisterIndex.Sp), ("ffree", "st(4)") }, { (RegisterIndex.A, RegisterIndex.Sp), (InstructionType.Unknown, FpuRegisterIndex.ST4) },
{ (RegisterIndex.A, RegisterIndex.Bp), ("ffree", "st(5)") }, { (RegisterIndex.A, RegisterIndex.Bp), (InstructionType.Unknown, FpuRegisterIndex.ST5) },
{ (RegisterIndex.A, RegisterIndex.Si), ("ffree", "st(6)") }, { (RegisterIndex.A, RegisterIndex.Si), (InstructionType.Unknown, FpuRegisterIndex.ST6) },
{ (RegisterIndex.A, RegisterIndex.Di), ("ffree", "st(7)") }, { (RegisterIndex.A, RegisterIndex.Di), (InstructionType.Unknown, FpuRegisterIndex.ST7) },
// FST ST(i) // FST ST(i)
{ (RegisterIndex.C, RegisterIndex.A), ("fst", "st(0)") }, { (RegisterIndex.C, RegisterIndex.A), (InstructionType.Fst, FpuRegisterIndex.ST0) },
{ (RegisterIndex.C, RegisterIndex.C), ("fst", "st(1)") }, { (RegisterIndex.C, RegisterIndex.C), (InstructionType.Fst, FpuRegisterIndex.ST1) },
{ (RegisterIndex.C, RegisterIndex.D), ("fst", "st(2)") }, { (RegisterIndex.C, RegisterIndex.D), (InstructionType.Fst, FpuRegisterIndex.ST2) },
{ (RegisterIndex.C, RegisterIndex.B), ("fst", "st(3)") }, { (RegisterIndex.C, RegisterIndex.B), (InstructionType.Fst, FpuRegisterIndex.ST3) },
{ (RegisterIndex.C, RegisterIndex.Sp), ("fst", "st(4)") }, { (RegisterIndex.C, RegisterIndex.Sp), (InstructionType.Fst, FpuRegisterIndex.ST4) },
{ (RegisterIndex.C, RegisterIndex.Bp), ("fst", "st(5)") }, { (RegisterIndex.C, RegisterIndex.Bp), (InstructionType.Fst, FpuRegisterIndex.ST5) },
{ (RegisterIndex.C, RegisterIndex.Si), ("fst", "st(6)") }, { (RegisterIndex.C, RegisterIndex.Si), (InstructionType.Fst, FpuRegisterIndex.ST6) },
{ (RegisterIndex.C, RegisterIndex.Di), ("fst", "st(7)") }, { (RegisterIndex.C, RegisterIndex.Di), (InstructionType.Fst, FpuRegisterIndex.ST7) },
// FSTP ST(i) // FSTP ST(i)
{ (RegisterIndex.D, RegisterIndex.A), ("fstp", "st(0)") }, { (RegisterIndex.D, RegisterIndex.A), (InstructionType.Fstp, FpuRegisterIndex.ST0) },
{ (RegisterIndex.D, RegisterIndex.C), ("fstp", "st(1)") }, { (RegisterIndex.D, RegisterIndex.C), (InstructionType.Fstp, FpuRegisterIndex.ST1) },
{ (RegisterIndex.D, RegisterIndex.D), ("fstp", "st(2)") }, { (RegisterIndex.D, RegisterIndex.D), (InstructionType.Fstp, FpuRegisterIndex.ST2) },
{ (RegisterIndex.D, RegisterIndex.B), ("fstp", "st(3)") }, { (RegisterIndex.D, RegisterIndex.B), (InstructionType.Fstp, FpuRegisterIndex.ST3) },
{ (RegisterIndex.D, RegisterIndex.Sp), ("fstp", "st(4)") }, { (RegisterIndex.D, RegisterIndex.Sp), (InstructionType.Fstp, FpuRegisterIndex.ST4) },
{ (RegisterIndex.D, RegisterIndex.Bp), ("fstp", "st(5)") }, { (RegisterIndex.D, RegisterIndex.Bp), (InstructionType.Fstp, FpuRegisterIndex.ST5) },
{ (RegisterIndex.D, RegisterIndex.Si), ("fstp", "st(6)") }, { (RegisterIndex.D, RegisterIndex.Si), (InstructionType.Fstp, FpuRegisterIndex.ST6) },
{ (RegisterIndex.D, RegisterIndex.Di), ("fstp", "st(7)") }, { (RegisterIndex.D, RegisterIndex.Di), (InstructionType.Fstp, FpuRegisterIndex.ST7) },
// FUCOM ST(i) // FUCOM ST(i)
{ (RegisterIndex.Si, RegisterIndex.A), ("fucom", "st(0)") }, { (RegisterIndex.Si, RegisterIndex.A), (InstructionType.Unknown, FpuRegisterIndex.ST0) },
{ (RegisterIndex.Si, RegisterIndex.C), ("fucom", "st(1)") }, { (RegisterIndex.Si, RegisterIndex.C), (InstructionType.Unknown, FpuRegisterIndex.ST1) },
{ (RegisterIndex.Si, RegisterIndex.D), ("fucom", "st(2)") }, { (RegisterIndex.Si, RegisterIndex.D), (InstructionType.Unknown, FpuRegisterIndex.ST2) },
{ (RegisterIndex.Si, RegisterIndex.B), ("fucom", "st(3)") }, { (RegisterIndex.Si, RegisterIndex.B), (InstructionType.Unknown, FpuRegisterIndex.ST3) },
{ (RegisterIndex.Si, RegisterIndex.Sp), ("fucom", "st(4)") }, { (RegisterIndex.Si, RegisterIndex.Sp), (InstructionType.Unknown, FpuRegisterIndex.ST4) },
{ (RegisterIndex.Si, RegisterIndex.Bp), ("fucom", "st(5)") }, { (RegisterIndex.Si, RegisterIndex.Bp), (InstructionType.Unknown, FpuRegisterIndex.ST5) },
{ (RegisterIndex.Si, RegisterIndex.Si), ("fucom", "st(6)") }, { (RegisterIndex.Si, RegisterIndex.Si), (InstructionType.Unknown, FpuRegisterIndex.ST6) },
{ (RegisterIndex.Si, RegisterIndex.Di), ("fucom", "st(7)") }, { (RegisterIndex.Si, RegisterIndex.Di), (InstructionType.Unknown, FpuRegisterIndex.ST7) },
// FUCOMP ST(i) // FUCOMP ST(i)
{ (RegisterIndex.Di, RegisterIndex.A), ("fucomp", "st(0)") }, { (RegisterIndex.Di, RegisterIndex.A), (InstructionType.Unknown, FpuRegisterIndex.ST0) },
{ (RegisterIndex.Di, RegisterIndex.C), ("fucomp", "st(1)") }, { (RegisterIndex.Di, RegisterIndex.C), (InstructionType.Unknown, FpuRegisterIndex.ST1) },
{ (RegisterIndex.Di, RegisterIndex.D), ("fucomp", "st(2)") }, { (RegisterIndex.Di, RegisterIndex.D), (InstructionType.Unknown, FpuRegisterIndex.ST2) },
{ (RegisterIndex.Di, RegisterIndex.B), ("fucomp", "st(3)") }, { (RegisterIndex.Di, RegisterIndex.B), (InstructionType.Unknown, FpuRegisterIndex.ST3) },
{ (RegisterIndex.Di, RegisterIndex.Sp), ("fucomp", "st(4)") }, { (RegisterIndex.Di, RegisterIndex.Sp), (InstructionType.Unknown, FpuRegisterIndex.ST4) },
{ (RegisterIndex.Di, RegisterIndex.Bp), ("fucomp", "st(5)") }, { (RegisterIndex.Di, RegisterIndex.Bp), (InstructionType.Unknown, FpuRegisterIndex.ST5) },
{ (RegisterIndex.Di, RegisterIndex.Si), ("fucomp", "st(6)") }, { (RegisterIndex.Di, RegisterIndex.Si), (InstructionType.Unknown, FpuRegisterIndex.ST6) },
{ (RegisterIndex.Di, RegisterIndex.Di), ("fucomp", "st(7)") } { (RegisterIndex.Di, RegisterIndex.Di), (InstructionType.Unknown, FpuRegisterIndex.ST7) }
}; };
/// <summary> /// <summary>
/// Initializes a new instance of the LoadStoreFloat64Handler class /// Initializes a new instance of the LoadStoreFloat64Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public LoadStoreFloat64Handler(InstructionDecoder decoder)
public LoadStoreFloat64Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -94,54 +107,75 @@ public class LoadStoreFloat64Handler : InstructionHandler
} }
/// <summary> /// <summary>
/// Decodes a floating-point instruction for load/store float64 operations /// Decodes a floating point instruction with the DD opcode
/// </summary> /// </summary>
/// <param name="opcode">The opcode of the instruction</param> /// <param name="opcode">The opcode of the instruction</param>
/// <param name="instruction">The instruction object to populate</param> /// <param name="instruction">The instruction object to populate</param>
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Check if we have enough bytes for the ModR/M byte
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
return false; return false;
} }
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, memOperand) = ModRMDecoder.ReadModRM(true); // true for 64-bit operand var (mod, reg, rm, memoryOperand) = ModRMDecoder.ReadModRM();
// Handle based on addressing mode // Set the instruction type based on the mod and reg fields
if (mod != 3) // Memory operand if (mod != 3) // Memory operand
{ {
// Set the mnemonic based on the reg field instruction.Type = MemoryInstructionTypes[(int)reg];
instruction.Mnemonic = MemoryMnemonics[(int)reg];
if (reg == RegisterIndex.A || reg == RegisterIndex.C || reg == RegisterIndex.D) // fld, fst, fstp // For memory operands, the instruction depends on the reg field
switch (reg)
{ {
// Keep the qword ptr prefix from ModRMDecoder case RegisterIndex.A: // FLD m64real
instruction.Operands = memOperand; // Set the structured operands
} memoryOperand.Size = 64; // Set size to 64 bits for double precision
else // frstor, fnsave, fnstsw instruction.StructuredOperands =
{ [
// Remove the qword ptr prefix for these operations memoryOperand
instruction.Operands = memOperand.Replace("qword ptr ", ""); ];
return true;
case RegisterIndex.C: // FST m64real
case RegisterIndex.D: // FSTP m64real
// Set the structured operands
memoryOperand.Size = 64; // Set size to 64 bits for double precision
instruction.StructuredOperands =
[
memoryOperand
];
return true;
default:
// For unsupported instructions, just set the type to Unknown
instruction.Type = InstructionType.Unknown;
return true;
} }
} }
else // Register operand (ST(i)) else // Register operand (mod == 3)
{ {
// Look up the register operation in our dictionary // Look up the instruction type in the register operations dictionary
if (RegisterOperations.TryGetValue((reg, rm), out var operation)) if (RegisterOperations.TryGetValue((reg, rm), out var operation))
{ {
instruction.Mnemonic = operation.Mnemonic; instruction.Type = operation.Type;
instruction.Operands = operation.Operands;
} // Create the FPU register operand
else var fpuRegisterOperand = OperandFactory.CreateFPURegisterOperand(operation.OperandIndex);
{
// Unknown instruction // Set the structured operands
instruction.Mnemonic = "??"; instruction.StructuredOperands =
instruction.Operands = ""; [
fpuRegisterOperand
];
return true;
} }
} }
return true; return false;
} }
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.FloatingPoint; namespace X86Disassembler.X86.Handlers.FloatingPoint;
/// <summary> /// <summary>
@ -5,66 +7,64 @@ namespace X86Disassembler.X86.Handlers.FloatingPoint;
/// </summary> /// </summary>
public class LoadStoreInt16Handler : InstructionHandler public class LoadStoreInt16Handler : InstructionHandler
{ {
// Memory operand mnemonics for DF opcode - load/store int16, misc // Memory operand instruction types for DF opcode - load/store int16, misc
private static readonly string[] MemoryMnemonics = private static readonly InstructionType[] MemoryInstructionTypes =
[ [
"fild", // 0 - 16-bit integer InstructionType.Unknown, // fild - not in enum
"??", // 1 InstructionType.Unknown, // ??
"fist", // 2 - 16-bit integer InstructionType.Unknown, // fist - not in enum
"fistp", // 3 - 16-bit integer InstructionType.Unknown, // fistp - not in enum
"fbld", // 4 - 80-bit packed BCD InstructionType.Unknown, // fbld - not in enum
"fild", // 5 - 64-bit integer InstructionType.Unknown, // fild - 64-bit integer - not in enum
"fbstp", // 6 - 80-bit packed BCD InstructionType.Unknown, // fbstp - not in enum
"fistp" // 7 - 64-bit integer InstructionType.Unknown // fistp - 64-bit integer - not in enum
]; ];
// Register-register operations mapping (mod=3) // Register-register operations mapping (mod=3)
private static readonly Dictionary<(RegisterIndex Reg, RegisterIndex Rm), (string Mnemonic, string Operands)> RegisterOperations = new() private static readonly Dictionary<(RegisterIndex Reg, RegisterIndex Rm), (InstructionType Type, FpuRegisterIndex OperandIndex, FpuRegisterIndex? SrcIndex)> RegisterOperations = new()
{ {
// FFREEP ST(i) // FFREEP ST(i)
{ (RegisterIndex.A, RegisterIndex.A), ("ffreep", "st(0)") }, { (RegisterIndex.A, RegisterIndex.A), (InstructionType.Unknown, FpuRegisterIndex.ST0, null) },
{ (RegisterIndex.A, RegisterIndex.C), ("ffreep", "st(1)") }, { (RegisterIndex.A, RegisterIndex.C), (InstructionType.Unknown, FpuRegisterIndex.ST1, null) },
{ (RegisterIndex.A, RegisterIndex.D), ("ffreep", "st(2)") }, { (RegisterIndex.A, RegisterIndex.D), (InstructionType.Unknown, FpuRegisterIndex.ST2, null) },
{ (RegisterIndex.A, RegisterIndex.B), ("ffreep", "st(3)") }, { (RegisterIndex.A, RegisterIndex.B), (InstructionType.Unknown, FpuRegisterIndex.ST3, null) },
{ (RegisterIndex.A, RegisterIndex.Sp), ("ffreep", "st(4)") }, { (RegisterIndex.A, RegisterIndex.Sp), (InstructionType.Unknown, FpuRegisterIndex.ST4, null) },
{ (RegisterIndex.A, RegisterIndex.Bp), ("ffreep", "st(5)") }, { (RegisterIndex.A, RegisterIndex.Bp), (InstructionType.Unknown, FpuRegisterIndex.ST5, null) },
{ (RegisterIndex.A, RegisterIndex.Si), ("ffreep", "st(6)") }, { (RegisterIndex.A, RegisterIndex.Si), (InstructionType.Unknown, FpuRegisterIndex.ST6, null) },
{ (RegisterIndex.A, RegisterIndex.Di), ("ffreep", "st(7)") }, { (RegisterIndex.A, RegisterIndex.Di), (InstructionType.Unknown, FpuRegisterIndex.ST7, null) },
// Special cases // Special cases
{ (RegisterIndex.B, RegisterIndex.A), ("fxch", "") }, { (RegisterIndex.B, RegisterIndex.A), (InstructionType.Fxch, FpuRegisterIndex.ST0, null) },
{ (RegisterIndex.C, RegisterIndex.A), ("fstp", "st(1)") }, { (RegisterIndex.C, RegisterIndex.A), (InstructionType.Fstp, FpuRegisterIndex.ST1, null) },
{ (RegisterIndex.D, RegisterIndex.A), ("fstp", "st(1)") }, { (RegisterIndex.D, RegisterIndex.A), (InstructionType.Fstp, FpuRegisterIndex.ST1, null) },
// FUCOMIP ST(0), ST(i) // FUCOMIP ST(0), ST(i)
{ (RegisterIndex.Di, RegisterIndex.A), ("fucomip", "st(0), st(0)") }, { (RegisterIndex.Di, RegisterIndex.A), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST0) },
{ (RegisterIndex.Di, RegisterIndex.C), ("fucomip", "st(0), st(1)") }, { (RegisterIndex.Di, RegisterIndex.C), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST1) },
{ (RegisterIndex.Di, RegisterIndex.D), ("fucomip", "st(0), st(2)") }, { (RegisterIndex.Di, RegisterIndex.D), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST2) },
{ (RegisterIndex.Di, RegisterIndex.B), ("fucomip", "st(0), st(3)") }, { (RegisterIndex.Di, RegisterIndex.B), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST3) },
{ (RegisterIndex.Di, RegisterIndex.Sp), ("fucomip", "st(0), st(4)") }, { (RegisterIndex.Di, RegisterIndex.Sp), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST4) },
{ (RegisterIndex.Di, RegisterIndex.Bp), ("fucomip", "st(0), st(5)") }, { (RegisterIndex.Di, RegisterIndex.Bp), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST5) },
{ (RegisterIndex.Di, RegisterIndex.Si), ("fucomip", "st(0), st(6)") }, { (RegisterIndex.Di, RegisterIndex.Si), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST6) },
{ (RegisterIndex.Di, RegisterIndex.Di), ("fucomip", "st(0), st(7)") }, { (RegisterIndex.Di, RegisterIndex.Di), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST7) },
// FCOMIP ST(0), ST(i) // FCOMIP ST(0), ST(i)
{ (RegisterIndex.Sp, RegisterIndex.A), ("fcomip", "st(0), st(0)") }, { (RegisterIndex.Sp, RegisterIndex.A), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST0) },
{ (RegisterIndex.Sp, RegisterIndex.C), ("fcomip", "st(0), st(1)") }, { (RegisterIndex.Sp, RegisterIndex.C), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST1) },
{ (RegisterIndex.Sp, RegisterIndex.D), ("fcomip", "st(0), st(2)") }, { (RegisterIndex.Sp, RegisterIndex.D), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST2) },
{ (RegisterIndex.Sp, RegisterIndex.B), ("fcomip", "st(0), st(3)") }, { (RegisterIndex.Sp, RegisterIndex.B), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST3) },
{ (RegisterIndex.Sp, RegisterIndex.Sp), ("fcomip", "st(0), st(4)") }, { (RegisterIndex.Sp, RegisterIndex.Sp), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST4) },
{ (RegisterIndex.Sp, RegisterIndex.Bp), ("fcomip", "st(0), st(5)") }, { (RegisterIndex.Sp, RegisterIndex.Bp), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST5) },
{ (RegisterIndex.Sp, RegisterIndex.Si), ("fcomip", "st(0), st(6)") }, { (RegisterIndex.Sp, RegisterIndex.Si), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST6) },
{ (RegisterIndex.Sp, RegisterIndex.Di), ("fcomip", "st(0), st(7)") } { (RegisterIndex.Sp, RegisterIndex.Di), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST7) }
}; };
/// <summary> /// <summary>
/// Initializes a new instance of the LoadStoreInt16Handler class /// Initializes a new instance of the LoadStoreInt16Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public LoadStoreInt16Handler(InstructionDecoder decoder)
public LoadStoreInt16Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -92,7 +92,7 @@ public class LoadStoreInt16Handler : InstructionHandler
} }
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, memOperand) = ModRMDecoder.ReadModRM(); var (mod, reg, rm, memoryOperand) = ModRMDecoder.ReadModRM();
// Check for FNSTSW AX (DF E0) // Check for FNSTSW AX (DF E0)
if (mod == 3 && reg == RegisterIndex.Bp && rm == RegisterIndex.A) if (mod == 3 && reg == RegisterIndex.Bp && rm == RegisterIndex.A)
@ -104,43 +104,65 @@ public class LoadStoreInt16Handler : InstructionHandler
// Handle based on addressing mode // Handle based on addressing mode
if (mod != 3) // Memory operand if (mod != 3) // Memory operand
{ {
// Set the mnemonic based on the reg field // Set the instruction type based on the reg field
instruction.Mnemonic = MemoryMnemonics[(int)reg]; instruction.Type = MemoryInstructionTypes[(int)reg];
// Get the base operand without size prefix // Set the size based on the operation
string baseOperand = memOperand.Replace("dword ptr ", "");
// Apply the appropriate size prefix based on the operation
if (reg == RegisterIndex.A || reg == RegisterIndex.C || reg == RegisterIndex.D) // 16-bit integer operations if (reg == RegisterIndex.A || reg == RegisterIndex.C || reg == RegisterIndex.D) // 16-bit integer operations
{ {
instruction.Operands = $"word ptr {baseOperand}"; // Set to 16-bit for integer operations
memoryOperand.Size = 16;
} }
else if (reg == RegisterIndex.Di || reg == RegisterIndex.Bp) // 64-bit integer operations else if (reg == RegisterIndex.Di || reg == RegisterIndex.Bp) // 64-bit integer operations
{ {
instruction.Operands = $"qword ptr {baseOperand}"; // Set to 64-bit for integer operations
memoryOperand.Size = 64;
} }
else if (reg == RegisterIndex.Si || reg == RegisterIndex.Sp) // 80-bit packed BCD operations else if (reg == RegisterIndex.Si || reg == RegisterIndex.Sp) // 80-bit packed BCD operations
{ {
instruction.Operands = $"tbyte ptr {baseOperand}"; // Set to 80-bit for BCD operations
} memoryOperand.Size = 80;
else // Other operations
{
instruction.Operands = memOperand;
} }
// Set the structured operands
instruction.StructuredOperands =
[
memoryOperand
];
} }
else // Register operand (ST(i)) else // Register operand (ST(i))
{ {
// Look up the register operation in our dictionary // Look up the instruction type in the register operations dictionary
if (RegisterOperations.TryGetValue((reg, rm), out var operation)) if (RegisterOperations.TryGetValue((reg, rm), out var operation))
{ {
instruction.Mnemonic = operation.Mnemonic; instruction.Type = operation.Type;
instruction.Operands = operation.Operands;
// Create the FPU register operands
var destOperand = OperandFactory.CreateFPURegisterOperand(operation.OperandIndex);
// Set the structured operands
if (operation.SrcIndex.HasValue)
{
var srcOperand = OperandFactory.CreateFPURegisterOperand(operation.SrcIndex.Value);
instruction.StructuredOperands =
[
destOperand,
srcOperand
];
}
else
{
instruction.StructuredOperands =
[
destOperand
];
}
} }
else else
{ {
// Unknown instruction // Unknown instruction
instruction.Mnemonic = "??"; instruction.Type = InstructionType.Unknown;
instruction.Operands = ""; instruction.StructuredOperands = [];
} }
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.FloatingPoint; namespace X86Disassembler.X86.Handlers.FloatingPoint;
/// <summary> /// <summary>
@ -5,95 +7,93 @@ namespace X86Disassembler.X86.Handlers.FloatingPoint;
/// </summary> /// </summary>
public class LoadStoreInt32Handler : InstructionHandler public class LoadStoreInt32Handler : InstructionHandler
{ {
// Memory operand mnemonics for DB opcode - load/store int32, misc // Memory operand instruction types for DB opcode - load/store int32, misc
private static readonly string[] MemoryMnemonics = private static readonly InstructionType[] MemoryInstructionTypes =
[ [
"fild", // 0 - 32-bit integer InstructionType.Unknown, // fild - not in enum
"??", // 1 InstructionType.Unknown, // ??
"fist", // 2 - 32-bit integer InstructionType.Unknown, // fist - not in enum
"fistp", // 3 - 32-bit integer InstructionType.Unknown, // fistp - not in enum
"??", // 4 InstructionType.Unknown, // ??
"fld", // 5 - 80-bit extended precision InstructionType.Fld, // fld - 80-bit extended precision
"??", // 6 InstructionType.Unknown, // ??
"fstp" // 7 - 80-bit extended precision InstructionType.Fstp // fstp - 80-bit extended precision
]; ];
// Register-register operations mapping (mod=3) // Register-register operations mapping (mod=3)
private static readonly Dictionary<(RegisterIndex Reg, RegisterIndex Rm), (string Mnemonic, string Operands)> RegisterOperations = new() private static readonly Dictionary<(RegisterIndex Reg, RegisterIndex Rm), (InstructionType Type, FpuRegisterIndex DestIndex, FpuRegisterIndex? SrcIndex)> RegisterOperations = new()
{ {
// FCMOVNB ST(0), ST(i) // FCMOVNB ST(0), ST(i)
{ (RegisterIndex.A, RegisterIndex.A), ("fcmovnb", "st(0), st(0)") }, { (RegisterIndex.A, RegisterIndex.A), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST0) },
{ (RegisterIndex.A, RegisterIndex.C), ("fcmovnb", "st(0), st(1)") }, { (RegisterIndex.A, RegisterIndex.C), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST1) },
{ (RegisterIndex.A, RegisterIndex.D), ("fcmovnb", "st(0), st(2)") }, { (RegisterIndex.A, RegisterIndex.D), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST2) },
{ (RegisterIndex.A, RegisterIndex.B), ("fcmovnb", "st(0), st(3)") }, { (RegisterIndex.A, RegisterIndex.B), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST3) },
{ (RegisterIndex.A, RegisterIndex.Sp), ("fcmovnb", "st(0), st(4)") }, { (RegisterIndex.A, RegisterIndex.Sp), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST4) },
{ (RegisterIndex.A, RegisterIndex.Bp), ("fcmovnb", "st(0), st(5)") }, { (RegisterIndex.A, RegisterIndex.Bp), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST5) },
{ (RegisterIndex.A, RegisterIndex.Si), ("fcmovnb", "st(0), st(6)") }, { (RegisterIndex.A, RegisterIndex.Si), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST6) },
{ (RegisterIndex.A, RegisterIndex.Di), ("fcmovnb", "st(0), st(7)") }, { (RegisterIndex.A, RegisterIndex.Di), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST7) },
// FCMOVNE ST(0), ST(i) // FCMOVNE ST(0), ST(i)
{ (RegisterIndex.B, RegisterIndex.A), ("fcmovne", "st(0), st(0)") }, { (RegisterIndex.B, RegisterIndex.A), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST0) },
{ (RegisterIndex.B, RegisterIndex.C), ("fcmovne", "st(0), st(1)") }, { (RegisterIndex.B, RegisterIndex.C), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST1) },
{ (RegisterIndex.B, RegisterIndex.D), ("fcmovne", "st(0), st(2)") }, { (RegisterIndex.B, RegisterIndex.D), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST2) },
{ (RegisterIndex.B, RegisterIndex.B), ("fcmovne", "st(0), st(3)") }, { (RegisterIndex.B, RegisterIndex.B), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST3) },
{ (RegisterIndex.B, RegisterIndex.Sp), ("fcmovne", "st(0), st(4)") }, { (RegisterIndex.B, RegisterIndex.Sp), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST4) },
{ (RegisterIndex.B, RegisterIndex.Bp), ("fcmovne", "st(0), st(5)") }, { (RegisterIndex.B, RegisterIndex.Bp), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST5) },
{ (RegisterIndex.B, RegisterIndex.Si), ("fcmovne", "st(0), st(6)") }, { (RegisterIndex.B, RegisterIndex.Si), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST6) },
{ (RegisterIndex.B, RegisterIndex.Di), ("fcmovne", "st(0), st(7)") }, { (RegisterIndex.B, RegisterIndex.Di), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST7) },
// FCMOVNBE ST(0), ST(i) // FCMOVNBE ST(0), ST(i)
{ (RegisterIndex.C, RegisterIndex.A), ("fcmovnbe", "st(0), st(0)") }, { (RegisterIndex.C, RegisterIndex.A), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST0) },
{ (RegisterIndex.C, RegisterIndex.C), ("fcmovnbe", "st(0), st(1)") }, { (RegisterIndex.C, RegisterIndex.C), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST1) },
{ (RegisterIndex.C, RegisterIndex.D), ("fcmovnbe", "st(0), st(2)") }, { (RegisterIndex.C, RegisterIndex.D), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST2) },
{ (RegisterIndex.C, RegisterIndex.B), ("fcmovnbe", "st(0), st(3)") }, { (RegisterIndex.C, RegisterIndex.B), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST3) },
{ (RegisterIndex.C, RegisterIndex.Sp), ("fcmovnbe", "st(0), st(4)") }, { (RegisterIndex.C, RegisterIndex.Sp), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST4) },
{ (RegisterIndex.C, RegisterIndex.Bp), ("fcmovnbe", "st(0), st(5)") }, { (RegisterIndex.C, RegisterIndex.Bp), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST5) },
{ (RegisterIndex.C, RegisterIndex.Si), ("fcmovnbe", "st(0), st(6)") }, { (RegisterIndex.C, RegisterIndex.Si), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST6) },
{ (RegisterIndex.C, RegisterIndex.Di), ("fcmovnbe", "st(0), st(7)") }, { (RegisterIndex.C, RegisterIndex.Di), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST7) },
// FCMOVNU ST(0), ST(i) // FCMOVNU ST(0), ST(i)
{ (RegisterIndex.D, RegisterIndex.A), ("fcmovnu", "st(0), st(0)") }, { (RegisterIndex.D, RegisterIndex.A), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST0) },
{ (RegisterIndex.D, RegisterIndex.C), ("fcmovnu", "st(0), st(1)") }, { (RegisterIndex.D, RegisterIndex.C), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST1) },
{ (RegisterIndex.D, RegisterIndex.D), ("fcmovnu", "st(0), st(2)") }, { (RegisterIndex.D, RegisterIndex.D), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST2) },
{ (RegisterIndex.D, RegisterIndex.B), ("fcmovnu", "st(0), st(3)") }, { (RegisterIndex.D, RegisterIndex.B), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST3) },
{ (RegisterIndex.D, RegisterIndex.Sp), ("fcmovnu", "st(0), st(4)") }, { (RegisterIndex.D, RegisterIndex.Sp), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST4) },
{ (RegisterIndex.D, RegisterIndex.Bp), ("fcmovnu", "st(0), st(5)") }, { (RegisterIndex.D, RegisterIndex.Bp), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST5) },
{ (RegisterIndex.D, RegisterIndex.Si), ("fcmovnu", "st(0), st(6)") }, { (RegisterIndex.D, RegisterIndex.Si), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST6) },
{ (RegisterIndex.D, RegisterIndex.Di), ("fcmovnu", "st(0), st(7)") }, { (RegisterIndex.D, RegisterIndex.Di), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST7) },
// Special cases // Special cases
{ (RegisterIndex.Si, RegisterIndex.C), ("fclex", "") }, { (RegisterIndex.Si, RegisterIndex.C), (InstructionType.Unknown, FpuRegisterIndex.ST0, null) }, // fclex
{ (RegisterIndex.Si, RegisterIndex.D), ("finit", "") }, { (RegisterIndex.Si, RegisterIndex.D), (InstructionType.Unknown, FpuRegisterIndex.ST0, null) }, // finit
// FUCOMI ST(0), ST(i) // FUCOMI ST(0), ST(i)
{ (RegisterIndex.Di, RegisterIndex.A), ("fucomi", "st(0), st(0)") }, { (RegisterIndex.Di, RegisterIndex.A), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST0) },
{ (RegisterIndex.Di, RegisterIndex.C), ("fucomi", "st(0), st(1)") }, { (RegisterIndex.Di, RegisterIndex.C), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST1) },
{ (RegisterIndex.Di, RegisterIndex.D), ("fucomi", "st(0), st(2)") }, { (RegisterIndex.Di, RegisterIndex.D), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST2) },
{ (RegisterIndex.Di, RegisterIndex.B), ("fucomi", "st(0), st(3)") }, { (RegisterIndex.Di, RegisterIndex.B), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST3) },
{ (RegisterIndex.Di, RegisterIndex.Sp), ("fucomi", "st(0), st(4)") }, { (RegisterIndex.Di, RegisterIndex.Sp), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST4) },
{ (RegisterIndex.Di, RegisterIndex.Bp), ("fucomi", "st(0), st(5)") }, { (RegisterIndex.Di, RegisterIndex.Bp), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST5) },
{ (RegisterIndex.Di, RegisterIndex.Si), ("fucomi", "st(0), st(6)") }, { (RegisterIndex.Di, RegisterIndex.Si), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST6) },
{ (RegisterIndex.Di, RegisterIndex.Di), ("fucomi", "st(0), st(7)") }, { (RegisterIndex.Di, RegisterIndex.Di), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST7) },
// FCOMI ST(0), ST(i) // FCOMI ST(0), ST(i)
{ (RegisterIndex.Sp, RegisterIndex.A), ("fcomi", "st(0), st(0)") }, { (RegisterIndex.Sp, RegisterIndex.A), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST0) },
{ (RegisterIndex.Sp, RegisterIndex.C), ("fcomi", "st(0), st(1)") }, { (RegisterIndex.Sp, RegisterIndex.C), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST1) },
{ (RegisterIndex.Sp, RegisterIndex.D), ("fcomi", "st(0), st(2)") }, { (RegisterIndex.Sp, RegisterIndex.D), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST2) },
{ (RegisterIndex.Sp, RegisterIndex.B), ("fcomi", "st(0), st(3)") }, { (RegisterIndex.Sp, RegisterIndex.B), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST3) },
{ (RegisterIndex.Sp, RegisterIndex.Sp), ("fcomi", "st(0), st(4)") }, { (RegisterIndex.Sp, RegisterIndex.Sp), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST4) },
{ (RegisterIndex.Sp, RegisterIndex.Bp), ("fcomi", "st(0), st(5)") }, { (RegisterIndex.Sp, RegisterIndex.Bp), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST5) },
{ (RegisterIndex.Sp, RegisterIndex.Si), ("fcomi", "st(0), st(6)") }, { (RegisterIndex.Sp, RegisterIndex.Si), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST6) },
{ (RegisterIndex.Sp, RegisterIndex.Di), ("fcomi", "st(0), st(7)") } { (RegisterIndex.Sp, RegisterIndex.Di), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST7) }
}; };
/// <summary> /// <summary>
/// Initializes a new instance of the LoadStoreInt32Handler class /// Initializes a new instance of the LoadStoreInt32Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public LoadStoreInt32Handler(InstructionDecoder decoder)
public LoadStoreInt32Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -121,45 +121,65 @@ public class LoadStoreInt32Handler : InstructionHandler
} }
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, memOperand) = ModRMDecoder.ReadModRM(); var (mod, reg, rm, memoryOperand) = ModRMDecoder.ReadModRM();
// Handle based on addressing mode // Handle based on addressing mode
if (mod != 3) // Memory operand if (mod != 3) // Memory operand
{ {
// Set the mnemonic based on the reg field // Set the instruction type based on the reg field
instruction.Mnemonic = MemoryMnemonics[(int)reg]; instruction.Type = MemoryInstructionTypes[(int)reg];
// Get the base operand without size prefix // Set the size based on the operation
string baseOperand = memOperand.Replace("dword ptr ", "");
// Apply the appropriate size prefix based on the operation
if (reg == RegisterIndex.A || reg == RegisterIndex.C || reg == RegisterIndex.D) // 32-bit integer operations if (reg == RegisterIndex.A || reg == RegisterIndex.C || reg == RegisterIndex.D) // 32-bit integer operations
{ {
// Keep the dword ptr prefix for integer operations // Keep the default 32-bit size
instruction.Operands = memOperand; memoryOperand.Size = 32;
} }
else if (reg == RegisterIndex.Di || reg == RegisterIndex.Bp) // 80-bit extended precision operations else if (reg == RegisterIndex.Di || reg == RegisterIndex.Bp) // 80-bit extended precision operations
{ {
instruction.Operands = $"tword ptr {baseOperand}"; // Set to 80-bit for extended precision
} memoryOperand.Size = 80;
else
{
instruction.Operands = memOperand;
} }
// Set the structured operands
instruction.StructuredOperands =
[
memoryOperand
];
} }
else // Register operand (ST(i)) else // Register operand (ST(i))
{ {
// Look up the register operation in our dictionary // Look up the instruction type in the register operations dictionary
if (RegisterOperations.TryGetValue((reg, rm), out var operation)) if (RegisterOperations.TryGetValue((reg, rm), out var operation))
{ {
instruction.Mnemonic = operation.Mnemonic; instruction.Type = operation.Type;
instruction.Operands = operation.Operands;
// 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 else
{ {
// Unknown instruction // Unknown instruction
instruction.Mnemonic = "??"; instruction.Type = InstructionType.Unknown;
instruction.Operands = ""; instruction.StructuredOperands = [];
} }
} }

View File

@ -1,5 +1,7 @@
namespace X86Disassembler.X86.Handlers.Inc; namespace X86Disassembler.X86.Handlers.Inc;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for INC r32 instructions (0x40-0x47) /// Handler for INC r32 instructions (0x40-0x47)
/// </summary> /// </summary>
@ -8,11 +10,9 @@ public class IncRegHandler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the IncRegHandler class /// Initializes a new instance of the IncRegHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public IncRegHandler(InstructionDecoder decoder)
public IncRegHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -38,11 +38,17 @@ public class IncRegHandler : InstructionHandler
// Calculate the register index (0 for EAX, 1 for ECX, etc.) // Calculate the register index (0 for EAX, 1 for ECX, etc.)
RegisterIndex reg = (RegisterIndex)(byte)(opcode - 0x40); RegisterIndex reg = (RegisterIndex)(byte)(opcode - 0x40);
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "inc"; instruction.Type = InstructionType.Inc;
// Set the operand (register name) // Create the register operand
instruction.Operands = ModRMDecoder.GetRegisterName(reg, 32); var regOperand = OperandFactory.CreateRegisterOperand(reg, 32);
// Set the structured operands
instruction.StructuredOperands =
[
regOperand
];
return true; return true;
} }

View File

@ -5,39 +5,29 @@ namespace X86Disassembler.X86.Handlers;
/// </summary> /// </summary>
public abstract class InstructionHandler : IInstructionHandler public abstract class InstructionHandler : IInstructionHandler
{ {
// Buffer containing the code to decode
protected readonly byte[] CodeBuffer;
// The instruction decoder that owns this handler // The instruction decoder that owns this handler
protected readonly InstructionDecoder Decoder; protected readonly InstructionDecoder Decoder;
// Length of the buffer
protected readonly int Length;
// ModRM decoder for handling addressing modes // ModRM decoder for handling addressing modes
protected readonly ModRMDecoder ModRMDecoder; protected readonly ModRMDecoder ModRMDecoder;
/// <summary> /// <summary>
/// Initializes a new instance of the InstructionHandler class /// Initializes a new instance of the InstructionHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> protected InstructionHandler(InstructionDecoder decoder)
protected InstructionHandler(byte[] codeBuffer, InstructionDecoder decoder, int length)
{ {
CodeBuffer = codeBuffer;
Decoder = decoder; Decoder = decoder;
Length = length; ModRMDecoder = new ModRMDecoder(decoder);
ModRMDecoder = new ModRMDecoder(codeBuffer, decoder, length);
} }
/// <summary> /// <summary>
/// Checks if this handler can decode the given opcode /// Checks if this handler can decode the given opcode
/// </summary> /// </summary>
/// <param name="opcode">The opcode to check</param> /// <param name="opcode">The opcode to check</param>
/// <returns>True if this handler can decode the opcode</returns> /// <returns>True if this handler can decode the opcode</returns>
public abstract bool CanHandle(byte opcode); public abstract bool CanHandle(byte opcode);
/// <summary> /// <summary>
/// Decodes an instruction /// Decodes an instruction
/// </summary> /// </summary>
@ -45,4 +35,4 @@ public abstract class InstructionHandler : IInstructionHandler
/// <param name="instruction">The instruction object to populate</param> /// <param name="instruction">The instruction object to populate</param>
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public abstract bool Decode(byte opcode, Instruction instruction); public abstract bool Decode(byte opcode, Instruction instruction);
} }

View File

@ -55,7 +55,7 @@ public class InstructionHandlerFactory
private void RegisterAllHandlers() private void RegisterAllHandlers()
{ {
// Register specific instruction handlers // Register specific instruction handlers
_handlers.Add(new Int3Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new Int3Handler(_decoder));
// Register handlers in order of priority (most specific first) // Register handlers in order of priority (most specific first)
RegisterArithmeticImmediateHandlers(); // Group 1 instructions (including 0x83) RegisterArithmeticImmediateHandlers(); // Group 1 instructions (including 0x83)
@ -88,22 +88,22 @@ public class InstructionHandlerFactory
private void RegisterArithmeticUnaryHandlers() private void RegisterArithmeticUnaryHandlers()
{ {
// NOT handler // NOT handler
_handlers.Add(new NotRm32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new NotRm32Handler(_decoder));
// NEG handler // NEG handler
_handlers.Add(new NegRm32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new NegRm32Handler(_decoder));
// MUL handler // MUL handler
_handlers.Add(new MulRm32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new MulRm32Handler(_decoder));
// IMUL handler // IMUL handler
_handlers.Add(new ImulRm32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new ImulRm32Handler(_decoder));
// DIV handler // DIV handler
_handlers.Add(new DivRm32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new DivRm32Handler(_decoder));
// IDIV handler // IDIV handler
_handlers.Add(new IdivRm32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new IdivRm32Handler(_decoder));
} }
/// <summary> /// <summary>
@ -112,16 +112,16 @@ public class InstructionHandlerFactory
private void RegisterArithmeticImmediateHandlers() private void RegisterArithmeticImmediateHandlers()
{ {
// ADC handlers // ADC handlers
_handlers.Add(new AdcImmToRm32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new AdcImmToRm32Handler(_decoder));
_handlers.Add(new AdcImmToRm32SignExtendedHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new AdcImmToRm32SignExtendedHandler(_decoder));
// SBB handlers // SBB handlers
_handlers.Add(new SbbImmFromRm32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new SbbImmFromRm32Handler(_decoder));
_handlers.Add(new SbbImmFromRm32SignExtendedHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new SbbImmFromRm32SignExtendedHandler(_decoder));
// SUB handlers // SUB handlers
_handlers.Add(new SubImmFromRm32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new SubImmFromRm32Handler(_decoder));
_handlers.Add(new SubImmFromRm32SignExtendedHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new SubImmFromRm32SignExtendedHandler(_decoder));
} }
/// <summary> /// <summary>
@ -130,8 +130,8 @@ public class InstructionHandlerFactory
private void RegisterReturnHandlers() private void RegisterReturnHandlers()
{ {
// Add Return handlers // Add Return handlers
_handlers.Add(new RetHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new RetHandler(_decoder));
_handlers.Add(new RetImmHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new RetImmHandler(_decoder));
} }
/// <summary> /// <summary>
@ -140,8 +140,8 @@ public class InstructionHandlerFactory
private void RegisterCallHandlers() private void RegisterCallHandlers()
{ {
// Add Call handlers // Add Call handlers
_handlers.Add(new CallRel32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new CallRel32Handler(_decoder));
_handlers.Add(new CallRm32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new CallRm32Handler(_decoder));
} }
/// <summary> /// <summary>
@ -150,11 +150,11 @@ public class InstructionHandlerFactory
private void RegisterJumpHandlers() private void RegisterJumpHandlers()
{ {
// JMP handlers // JMP handlers
_handlers.Add(new JmpRel32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new JmpRel32Handler(_decoder));
_handlers.Add(new JmpRel8Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new JmpRel8Handler(_decoder));
_handlers.Add(new JgeRel8Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new JgeRel8Handler(_decoder));
_handlers.Add(new ConditionalJumpHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new ConditionalJumpHandler(_decoder));
_handlers.Add(new TwoByteConditionalJumpHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new TwoByteConditionalJumpHandler(_decoder));
} }
/// <summary> /// <summary>
@ -163,12 +163,12 @@ public class InstructionHandlerFactory
private void RegisterTestHandlers() private void RegisterTestHandlers()
{ {
// TEST handlers // TEST handlers
_handlers.Add(new TestImmWithRm32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new TestImmWithRm32Handler(_decoder));
_handlers.Add(new TestImmWithRm8Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new TestImmWithRm8Handler(_decoder));
_handlers.Add(new TestRegMem8Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new TestRegMem8Handler(_decoder));
_handlers.Add(new TestRegMemHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new TestRegMemHandler(_decoder));
_handlers.Add(new TestAlImmHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new TestAlImmHandler(_decoder));
_handlers.Add(new TestEaxImmHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new TestEaxImmHandler(_decoder));
} }
/// <summary> /// <summary>
@ -177,27 +177,27 @@ public class InstructionHandlerFactory
private void RegisterXorHandlers() private void RegisterXorHandlers()
{ {
// 16-bit handlers // 16-bit handlers
_handlers.Add(new XorRm16R16Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new XorRm16R16Handler(_decoder));
_handlers.Add(new XorR16Rm16Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new XorR16Rm16Handler(_decoder));
_handlers.Add(new XorImmWithRm16Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new XorImmWithRm16Handler(_decoder));
_handlers.Add(new XorImmWithRm16SignExtendedHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new XorImmWithRm16SignExtendedHandler(_decoder));
// 32-bit handlers // 32-bit handlers
_handlers.Add(new XorMemRegHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new XorMemRegHandler(_decoder));
_handlers.Add(new XorRegMemHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new XorRegMemHandler(_decoder));
_handlers.Add(new XorImmWithRm32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new XorImmWithRm32Handler(_decoder));
_handlers.Add(new XorImmWithRm32SignExtendedHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new XorImmWithRm32SignExtendedHandler(_decoder));
// 8-bit handlers // 8-bit handlers
_handlers.Add(new XorRm8R8Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new XorRm8R8Handler(_decoder));
_handlers.Add(new XorR8Rm8Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new XorR8Rm8Handler(_decoder));
_handlers.Add(new XorAlImmHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new XorAlImmHandler(_decoder));
_handlers.Add(new XorImmWithRm8Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new XorImmWithRm8Handler(_decoder));
// special treatment with xor-ing eax // special treatment with xor-ing eax
// precise handlers go first // precise handlers go first
_handlers.Add(new XorAxImm16Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new XorAxImm16Handler(_decoder));
_handlers.Add(new XorEaxImmHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new XorEaxImmHandler(_decoder));
} }
/// <summary> /// <summary>
@ -206,15 +206,15 @@ public class InstructionHandlerFactory
private void RegisterOrHandlers() private void RegisterOrHandlers()
{ {
// Add OR handlers // Add OR handlers
_handlers.Add(new OrImmToRm8Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new OrImmToRm8Handler(_decoder));
_handlers.Add(new OrImmToRm32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new OrImmToRm32Handler(_decoder));
_handlers.Add(new OrImmToRm32SignExtendedHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new OrImmToRm32SignExtendedHandler(_decoder));
_handlers.Add(new OrR8Rm8Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new OrR8Rm8Handler(_decoder));
_handlers.Add(new OrRm8R8Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new OrRm8R8Handler(_decoder));
_handlers.Add(new OrR32Rm32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new OrR32Rm32Handler(_decoder));
_handlers.Add(new OrAlImmHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new OrAlImmHandler(_decoder));
_handlers.Add(new OrEaxImmHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new OrEaxImmHandler(_decoder));
} }
/// <summary> /// <summary>
@ -223,7 +223,7 @@ public class InstructionHandlerFactory
private void RegisterLeaHandlers() private void RegisterLeaHandlers()
{ {
// Add Lea handlers // Add Lea handlers
_handlers.Add(new LeaR32MHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new LeaR32MHandler(_decoder));
} }
/// <summary> /// <summary>
@ -232,14 +232,14 @@ public class InstructionHandlerFactory
private void RegisterCmpHandlers() private void RegisterCmpHandlers()
{ {
// Add Cmp handlers // Add Cmp handlers
_handlers.Add(new CmpR32Rm32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new CmpR32Rm32Handler(_decoder));
_handlers.Add(new CmpRm32R32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new CmpRm32R32Handler(_decoder));
_handlers.Add(new CmpImmWithRm8Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new CmpImmWithRm8Handler(_decoder));
_handlers.Add(new CmpAlImmHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new CmpAlImmHandler(_decoder));
// Add CMP immediate handlers from ArithmeticImmediate namespace // Add CMP immediate handlers from ArithmeticImmediate namespace
_handlers.Add(new CmpImmWithRm32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new CmpImmWithRm32Handler(_decoder));
_handlers.Add(new CmpImmWithRm32SignExtendedHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new CmpImmWithRm32SignExtendedHandler(_decoder));
} }
/// <summary> /// <summary>
@ -248,7 +248,7 @@ public class InstructionHandlerFactory
private void RegisterDecHandlers() private void RegisterDecHandlers()
{ {
// Add Dec handlers // Add Dec handlers
_handlers.Add(new DecRegHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new DecRegHandler(_decoder));
} }
/// <summary> /// <summary>
@ -257,7 +257,7 @@ public class InstructionHandlerFactory
private void RegisterIncHandlers() private void RegisterIncHandlers()
{ {
// Add Inc handlers // Add Inc handlers
_handlers.Add(new IncRegHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new IncRegHandler(_decoder));
} }
/// <summary> /// <summary>
@ -266,14 +266,14 @@ public class InstructionHandlerFactory
private void RegisterAddHandlers() private void RegisterAddHandlers()
{ {
// Add ADD handlers // Add ADD handlers
_handlers.Add(new AddR32Rm32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new AddR32Rm32Handler(_decoder));
_handlers.Add(new AddRm32R32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new AddRm32R32Handler(_decoder));
_handlers.Add(new AddEaxImmHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new AddEaxImmHandler(_decoder));
// Add ADD immediate handlers from ArithmeticImmediate namespace // Add ADD immediate handlers from ArithmeticImmediate namespace
_handlers.Add(new AddImmToRm8Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new AddImmToRm8Handler(_decoder));
_handlers.Add(new AddImmToRm32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new AddImmToRm32Handler(_decoder));
_handlers.Add(new AddImmToRm32SignExtendedHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new AddImmToRm32SignExtendedHandler(_decoder));
} }
/// <summary> /// <summary>
@ -282,25 +282,25 @@ public class InstructionHandlerFactory
private void RegisterDataTransferHandlers() private void RegisterDataTransferHandlers()
{ {
// Add MOV handlers // Add MOV handlers
_handlers.Add(new MovRegMemHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new MovRegMemHandler(_decoder));
_handlers.Add(new MovMemRegHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new MovMemRegHandler(_decoder));
_handlers.Add(new MovRegImm32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new MovRegImm32Handler(_decoder));
_handlers.Add(new MovRegImm8Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new MovRegImm8Handler(_decoder));
_handlers.Add(new MovEaxMoffsHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new MovEaxMoffsHandler(_decoder));
_handlers.Add(new MovMoffsEaxHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new MovMoffsEaxHandler(_decoder));
_handlers.Add(new MovRm32Imm32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new MovRm32Imm32Handler(_decoder));
_handlers.Add(new MovRm8Imm8Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new MovRm8Imm8Handler(_decoder));
// Add PUSH handlers // Add PUSH handlers
_handlers.Add(new PushRegHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new PushRegHandler(_decoder));
_handlers.Add(new PushImm32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new PushImm32Handler(_decoder));
_handlers.Add(new PushImm8Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new PushImm8Handler(_decoder));
// Add POP handlers // Add POP handlers
_handlers.Add(new PopRegHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new PopRegHandler(_decoder));
// Add XCHG handlers // Add XCHG handlers
_handlers.Add(new XchgEaxRegHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new XchgEaxRegHandler(_decoder));
} }
/// <summary> /// <summary>
@ -309,15 +309,15 @@ public class InstructionHandlerFactory
private void RegisterFloatingPointHandlers() private void RegisterFloatingPointHandlers()
{ {
// Add Floating Point handlers // Add Floating Point handlers
_handlers.Add(new FnstswHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new FnstswHandler(_decoder));
_handlers.Add(new Float32OperationHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new Float32OperationHandler(_decoder));
_handlers.Add(new LoadStoreControlHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new LoadStoreControlHandler(_decoder));
_handlers.Add(new Int32OperationHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new Int32OperationHandler(_decoder));
_handlers.Add(new LoadStoreInt32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new LoadStoreInt32Handler(_decoder));
_handlers.Add(new Float64OperationHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new Float64OperationHandler(_decoder));
_handlers.Add(new LoadStoreFloat64Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new LoadStoreFloat64Handler(_decoder));
_handlers.Add(new Int16OperationHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new Int16OperationHandler(_decoder));
_handlers.Add(new LoadStoreInt16Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new LoadStoreInt16Handler(_decoder));
} }
/// <summary> /// <summary>
@ -326,7 +326,7 @@ public class InstructionHandlerFactory
private void RegisterStringHandlers() private void RegisterStringHandlers()
{ {
// Add String instruction handler that handles both regular and REP/REPNE prefixed string instructions // Add String instruction handler that handles both regular and REP/REPNE prefixed string instructions
_handlers.Add(new StringInstructionHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new StringInstructionHandler(_decoder));
} }
/// <summary> /// <summary>
@ -335,14 +335,14 @@ public class InstructionHandlerFactory
private void RegisterMovHandlers() private void RegisterMovHandlers()
{ {
// Add MOV handlers // Add MOV handlers
_handlers.Add(new MovRegMemHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new MovRegMemHandler(_decoder));
_handlers.Add(new MovMemRegHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new MovMemRegHandler(_decoder));
_handlers.Add(new MovRegImm32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new MovRegImm32Handler(_decoder));
_handlers.Add(new MovRegImm8Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new MovRegImm8Handler(_decoder));
_handlers.Add(new MovEaxMoffsHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new MovEaxMoffsHandler(_decoder));
_handlers.Add(new MovMoffsEaxHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new MovMoffsEaxHandler(_decoder));
_handlers.Add(new MovRm32Imm32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new MovRm32Imm32Handler(_decoder));
_handlers.Add(new MovRm8Imm8Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new MovRm8Imm8Handler(_decoder));
} }
/// <summary> /// <summary>
@ -351,10 +351,10 @@ public class InstructionHandlerFactory
private void RegisterPushHandlers() private void RegisterPushHandlers()
{ {
// Add PUSH handlers // Add PUSH handlers
_handlers.Add(new PushRegHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new PushRegHandler(_decoder));
_handlers.Add(new PushImm32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new PushImm32Handler(_decoder));
_handlers.Add(new PushImm8Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new PushImm8Handler(_decoder));
_handlers.Add(new PushRm32Handler(_codeBuffer, _decoder, _length)); // Add handler for PUSH r/m32 (FF /6) _handlers.Add(new PushRm32Handler(_decoder)); // Add handler for PUSH r/m32 (FF /6)
} }
/// <summary> /// <summary>
@ -363,7 +363,7 @@ public class InstructionHandlerFactory
private void RegisterPopHandlers() private void RegisterPopHandlers()
{ {
// Add POP handlers // Add POP handlers
_handlers.Add(new PopRegHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new PopRegHandler(_decoder));
} }
/// <summary> /// <summary>
@ -372,17 +372,17 @@ public class InstructionHandlerFactory
private void RegisterAndHandlers() private void RegisterAndHandlers()
{ {
// Add AND handlers // Add AND handlers
_handlers.Add(new AndImmToRm8Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new AndImmToRm8Handler(_decoder));
_handlers.Add(new AndImmWithRm32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new AndImmWithRm32Handler(_decoder));
_handlers.Add(new AndImmToRm32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new AndImmToRm32Handler(_decoder));
_handlers.Add(new AndImmToRm32SignExtendedHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new AndImmToRm32SignExtendedHandler(_decoder));
_handlers.Add(new AndR8Rm8Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new AndR8Rm8Handler(_decoder));
_handlers.Add(new AndRm8R8Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new AndRm8R8Handler(_decoder));
_handlers.Add(new AndR32Rm32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new AndR32Rm32Handler(_decoder));
_handlers.Add(new AndMemRegHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new AndMemRegHandler(_decoder));
_handlers.Add(new AndAlImmHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new AndAlImmHandler(_decoder));
_handlers.Add(new AndEaxImmHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new AndEaxImmHandler(_decoder));
} }
/// <summary> /// <summary>
@ -393,23 +393,23 @@ public class InstructionHandlerFactory
// Register SUB handlers // Register SUB handlers
// 32-bit handlers // 32-bit handlers
_handlers.Add(new SubRm32R32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new SubRm32R32Handler(_decoder));
_handlers.Add(new SubR32Rm32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new SubR32Rm32Handler(_decoder));
_handlers.Add(new SubImmFromRm32Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new SubImmFromRm32Handler(_decoder));
_handlers.Add(new SubImmFromRm32SignExtendedHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new SubImmFromRm32SignExtendedHandler(_decoder));
// 16-bit handlers // 16-bit handlers
_handlers.Add(new SubRm16R16Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new SubRm16R16Handler(_decoder));
_handlers.Add(new SubR16Rm16Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new SubR16Rm16Handler(_decoder));
_handlers.Add(new SubAxImm16Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new SubAxImm16Handler(_decoder));
_handlers.Add(new SubImmFromRm16Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new SubImmFromRm16Handler(_decoder));
_handlers.Add(new SubImmFromRm16SignExtendedHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new SubImmFromRm16SignExtendedHandler(_decoder));
// 8-bit handlers // 8-bit handlers
_handlers.Add(new SubRm8R8Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new SubRm8R8Handler(_decoder));
_handlers.Add(new SubR8Rm8Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new SubR8Rm8Handler(_decoder));
_handlers.Add(new SubAlImm8Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new SubAlImm8Handler(_decoder));
_handlers.Add(new SubImmFromRm8Handler(_codeBuffer, _decoder, _length)); _handlers.Add(new SubImmFromRm8Handler(_decoder));
} }
/// <summary> /// <summary>
@ -418,9 +418,9 @@ public class InstructionHandlerFactory
private void RegisterNopHandlers() private void RegisterNopHandlers()
{ {
// Register NOP handlers // Register NOP handlers
_handlers.Add(new NopHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new NopHandler(_decoder));
_handlers.Add(new TwoByteNopHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new TwoByteNopHandler(_decoder));
_handlers.Add(new MultiByteNopHandler(_codeBuffer, _decoder, _length)); _handlers.Add(new MultiByteNopHandler(_decoder));
} }
/// <summary> /// <summary>

View File

@ -1,5 +1,7 @@
namespace X86Disassembler.X86.Handlers.Jump; namespace X86Disassembler.X86.Handlers.Jump;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for conditional jump instructions (0x70-0x7F) /// Handler for conditional jump instructions (0x70-0x7F)
/// </summary> /// </summary>
@ -11,15 +13,22 @@ public class ConditionalJumpHandler : InstructionHandler
"jo", "jno", "jb", "jnb", "jz", "jnz", "jbe", "jnbe", "jo", "jno", "jb", "jnb", "jz", "jnz", "jbe", "jnbe",
"js", "jns", "jp", "jnp", "jl", "jnl", "jle", "jnle" "js", "jns", "jp", "jnp", "jl", "jnl", "jle", "jnle"
]; ];
// Instruction types for conditional jumps
private static readonly InstructionType[] InstructionTypes =
[
InstructionType.Jo, InstructionType.Jno, InstructionType.Jb, InstructionType.Jae,
InstructionType.Jz, InstructionType.Jnz, InstructionType.Jbe, InstructionType.Ja,
InstructionType.Js, InstructionType.Jns, InstructionType.Unknown, InstructionType.Unknown,
InstructionType.Jl, InstructionType.Jge, InstructionType.Jle, InstructionType.Jg
];
/// <summary> /// <summary>
/// Initializes a new instance of the ConditionalJumpHandler class /// Initializes a new instance of the ConditionalJumpHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public ConditionalJumpHandler(InstructionDecoder decoder)
public ConditionalJumpHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -42,9 +51,11 @@ public class ConditionalJumpHandler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Get the mnemonic from the table // Get the index from the opcode
int index = opcode - 0x70; int index = opcode - 0x70;
instruction.Mnemonic = Mnemonics[index];
// Set the instruction type
instruction.Type = InstructionTypes[index];
// Check if we can read the offset byte // Check if we can read the offset byte
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
@ -57,8 +68,14 @@ public class ConditionalJumpHandler : InstructionHandler
sbyte offset = (sbyte)Decoder.ReadByte(); sbyte offset = (sbyte)Decoder.ReadByte();
int targetAddress = position + 1 + offset; int targetAddress = position + 1 + offset;
// Format the target address as a hexadecimal value // Create the target address operand
instruction.Operands = $"0x{targetAddress:X8}"; var targetOperand = OperandFactory.CreateRelativeOffsetOperand((ulong)targetAddress, 8);
// Set the structured operands
instruction.StructuredOperands =
[
targetOperand
];
return true; return true;
} }

View File

@ -1,5 +1,7 @@
namespace X86Disassembler.X86.Handlers.Jump; namespace X86Disassembler.X86.Handlers.Jump;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for JGE rel8 instruction (0x7D) /// Handler for JGE rel8 instruction (0x7D)
/// </summary> /// </summary>
@ -8,11 +10,9 @@ public class JgeRel8Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the JgeRel8Handler class /// Initializes a new instance of the JgeRel8Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public JgeRel8Handler(InstructionDecoder decoder)
public JgeRel8Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,14 +34,13 @@ public class JgeRel8Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "jge"; instruction.Type = InstructionType.Jge;
// Check if we can read the offset byte // Check if we can read the offset byte
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
instruction.Operands = "??"; return false;
return true;
} }
sbyte offset = (sbyte)Decoder.ReadByte(); sbyte offset = (sbyte)Decoder.ReadByte();
@ -49,8 +48,14 @@ public class JgeRel8Handler : InstructionHandler
// Calculate target address (instruction address + instruction length + offset) // Calculate target address (instruction address + instruction length + offset)
ulong targetAddress = instruction.Address + 2UL + (uint)offset; ulong targetAddress = instruction.Address + 2UL + (uint)offset;
// Format the target address // Create the relative offset operand
instruction.Operands = $"0x{targetAddress:X8}"; var targetOperand = OperandFactory.CreateRelativeOffsetOperand(targetAddress, 8);
// Set the structured operands
instruction.StructuredOperands =
[
targetOperand
];
return true; return true;
} }

View File

@ -1,5 +1,7 @@
namespace X86Disassembler.X86.Handlers.Jump; namespace X86Disassembler.X86.Handlers.Jump;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for JMP rel32 instruction (0xE9) /// Handler for JMP rel32 instruction (0xE9)
/// </summary> /// </summary>
@ -8,11 +10,9 @@ public class JmpRel32Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the JmpRel32Handler class /// Initializes a new instance of the JmpRel32Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public JmpRel32Handler(InstructionDecoder decoder)
public JmpRel32Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,8 +34,8 @@ public class JmpRel32Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "jmp"; instruction.Type = InstructionType.Jmp;
// Check if we have enough bytes for the offset (4 bytes) // Check if we have enough bytes for the offset (4 bytes)
if (!Decoder.CanReadUInt()) if (!Decoder.CanReadUInt())
@ -50,8 +50,14 @@ public class JmpRel32Handler : InstructionHandler
// For JMP rel32, the instruction is 5 bytes: opcode (1 byte) + offset (4 bytes) // For JMP rel32, the instruction is 5 bytes: opcode (1 byte) + offset (4 bytes)
uint targetAddress = (uint)(instruction.Address + 5 + offset); uint targetAddress = (uint)(instruction.Address + 5 + offset);
// Set the operands // Create the target address operand
instruction.Operands = $"0x{targetAddress:X8}"; var targetOperand = OperandFactory.CreateRelativeOffsetOperand(targetAddress);
// Set the structured operands
instruction.StructuredOperands =
[
targetOperand
];
return true; return true;
} }

View File

@ -1,5 +1,7 @@
namespace X86Disassembler.X86.Handlers.Jump; namespace X86Disassembler.X86.Handlers.Jump;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for JMP rel8 instruction (0xEB) /// Handler for JMP rel8 instruction (0xEB)
/// </summary> /// </summary>
@ -8,11 +10,9 @@ public class JmpRel8Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the JmpRel8Handler class /// Initializes a new instance of the JmpRel8Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public JmpRel8Handler(InstructionDecoder decoder)
public JmpRel8Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,8 +34,8 @@ public class JmpRel8Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "jmp"; instruction.Type = InstructionType.Jmp;
// Check if we can read the offset byte // Check if we can read the offset byte
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
@ -48,8 +48,14 @@ public class JmpRel8Handler : InstructionHandler
// Calculate target address (instruction address + instruction length + offset) // Calculate target address (instruction address + instruction length + offset)
ulong targetAddress = instruction.Address + 2UL + (uint)offset; ulong targetAddress = instruction.Address + 2UL + (uint)offset;
// Format the target address // Create the target address operand
instruction.Operands = $"0x{targetAddress:X8}"; var targetOperand = OperandFactory.CreateRelativeOffsetOperand(targetAddress, 8);
// Set the structured operands
instruction.StructuredOperands =
[
targetOperand
];
return true; return true;
} }

View File

@ -1,5 +1,7 @@
namespace X86Disassembler.X86.Handlers.Jump; namespace X86Disassembler.X86.Handlers.Jump;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for two-byte conditional jump instructions (0x0F 0x80-0x8F) /// Handler for two-byte conditional jump instructions (0x0F 0x80-0x8F)
/// </summary> /// </summary>
@ -12,14 +14,21 @@ public class TwoByteConditionalJumpHandler : InstructionHandler
"js", "jns", "jp", "jnp", "jl", "jnl", "jle", "jnle" "js", "jns", "jp", "jnp", "jl", "jnl", "jle", "jnle"
]; ];
// Instruction types for conditional jumps
private static readonly InstructionType[] InstructionTypes =
[
InstructionType.Jo, InstructionType.Jno, InstructionType.Jb, InstructionType.Jae,
InstructionType.Jz, InstructionType.Jnz, InstructionType.Jbe, InstructionType.Ja,
InstructionType.Js, InstructionType.Jns, InstructionType.Unknown, InstructionType.Unknown,
InstructionType.Jl, InstructionType.Jge, InstructionType.Jle, InstructionType.Jg
];
/// <summary> /// <summary>
/// Initializes a new instance of the TwoByteConditionalJumpHandler class /// Initializes a new instance of the TwoByteConditionalJumpHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public TwoByteConditionalJumpHandler(InstructionDecoder decoder)
public TwoByteConditionalJumpHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -42,7 +51,7 @@ public class TwoByteConditionalJumpHandler : InstructionHandler
return false; return false;
} }
byte secondByte = CodeBuffer[position]; byte secondByte = Decoder.PeakByte();
// Second byte must be in the range 0x80-0x8F // Second byte must be in the range 0x80-0x8F
return secondByte >= 0x80 && secondByte <= 0x8F; return secondByte >= 0x80 && secondByte <= 0x8F;
} }
@ -64,9 +73,9 @@ public class TwoByteConditionalJumpHandler : InstructionHandler
// Read the second byte of the opcode // Read the second byte of the opcode
byte secondByte = Decoder.ReadByte(); byte secondByte = Decoder.ReadByte();
// Get the mnemonic from the table // Get the instruction type from the table
int index = secondByte - 0x80; int index = secondByte - 0x80;
instruction.Mnemonic = ConditionalJumpMnemonics[index]; instruction.Type = InstructionTypes[index];
// Check if we have enough bytes for the offset // Check if we have enough bytes for the offset
if (!Decoder.CanReadUInt()) if (!Decoder.CanReadUInt())
@ -81,8 +90,14 @@ public class TwoByteConditionalJumpHandler : InstructionHandler
// For two-byte conditional jumps, the instruction is 6 bytes: first opcode (1) + second opcode (1) + offset (4) // For two-byte conditional jumps, the instruction is 6 bytes: first opcode (1) + second opcode (1) + offset (4)
uint targetAddress = (uint)(instruction.Address + 6 + offset); uint targetAddress = (uint)(instruction.Address + 6 + offset);
// Format the target address // Create the relative offset operand
instruction.Operands = $"0x{targetAddress:X8}"; var targetOperand = OperandFactory.CreateRelativeOffsetOperand(targetAddress);
// Set the structured operands
instruction.StructuredOperands =
[
targetOperand
];
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Lea; namespace X86Disassembler.X86.Handlers.Lea;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class LeaR32MHandler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the LeaR32MHandler class /// Initializes a new instance of the LeaR32MHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public LeaR32MHandler(InstructionDecoder decoder)
public LeaR32MHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -41,7 +41,7 @@ public class LeaR32MHandler : InstructionHandler
} }
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM(); var (mod, reg, rm, sourceOperand) = ModRMDecoder.ReadModRM();
// LEA only works with memory operands, not registers // LEA only works with memory operands, not registers
if (mod == 3) if (mod == 3)
@ -49,17 +49,21 @@ public class LeaR32MHandler : InstructionHandler
return false; return false;
} }
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "lea"; instruction.Type = InstructionType.Lea;
// Get the register name // Create the destination register operand
string regName = ModRMDecoder.GetRegisterName(reg, 32); var destinationOperand = OperandFactory.CreateRegisterOperand((RegisterIndex)reg, 32);
// Remove the "dword ptr" prefix for LEA instructions // For LEA, we don't care about the size of the memory operand
destOperand = destOperand.Replace("dword ptr ", ""); // as we're only interested in the effective address calculation
// Set the operands // Set the structured operands
instruction.Operands = $"{regName}, {destOperand}"; instruction.StructuredOperands =
[
destinationOperand,
sourceOperand
];
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Mov; namespace X86Disassembler.X86.Handlers.Mov;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class MovEaxMoffsHandler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the MovEaxMoffsHandler class /// Initializes a new instance of the MovEaxMoffsHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public MovEaxMoffsHandler(InstructionDecoder decoder)
public MovEaxMoffsHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,25 +34,33 @@ public class MovEaxMoffsHandler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "mov"; instruction.Type = InstructionType.Mov;
// Get the operand size and register name // Get the operand size based on the opcode
int operandSize = (opcode == 0xA0) int operandSize = (opcode == 0xA0) ? 8 : 32;
? 8
: 32;
string regName = ModRMDecoder.GetRegisterName(RegisterIndex.A, operandSize);
// Read the memory offset // Read the memory offset
uint offset = Decoder.ReadUInt32(); if (!Decoder.CanReadUInt())
if (Decoder.GetPosition() > Length)
{ {
return false; return false;
} }
// Set the operands uint offset = Decoder.ReadUInt32();
instruction.Operands = $"{regName}, [0x{offset:X}]";
// Create the destination register operand (EAX or AL)
var destinationOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.A, operandSize);
// Create the source memory operand
// For MOV EAX, moffs32 or MOV AL, moffs8, the memory operand is a direct memory reference
var sourceOperand = OperandFactory.CreateDirectMemoryOperand(offset, operandSize);
// Set the structured operands
instruction.StructuredOperands =
[
destinationOperand,
sourceOperand
];
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Mov; namespace X86Disassembler.X86.Handlers.Mov;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class MovMemRegHandler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the MovMemRegHandler class /// Initializes a new instance of the MovMemRegHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public MovMemRegHandler(InstructionDecoder decoder)
public MovMemRegHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,8 +34,8 @@ public class MovMemRegHandler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "mov"; instruction.Type = InstructionType.Mov;
// Check if we have enough bytes for the ModR/M byte // Check if we have enough bytes for the ModR/M byte
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
@ -48,21 +48,23 @@ public class MovMemRegHandler : InstructionHandler
int operandSize = operandSize32 ? 32 : 8; int operandSize = operandSize32 ? 32 : 8;
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, memOperand) = ModRMDecoder.ReadModRM(); // For MOV r/m32, r32 (0x89) or MOV r/m8, r8 (0x88):
// - The r/m field with mod specifies the destination operand (register or memory)
// - The reg field specifies the source register
var (mod, reg, rm, destinationOperand) = ModRMDecoder.ReadModRM();
// Get register name based on size // Adjust the operand size based on the opcode
string regName = ModRMDecoder.GetRegisterName(reg, operandSize); destinationOperand.Size = operandSize;
// For mod == 3, both operands are registers // Create the source register operand
if (mod == 3) var sourceOperand = OperandFactory.CreateRegisterOperand(reg, operandSize);
{
string rmRegName = ModRMDecoder.GetRegisterName(rm, operandSize); // Set the structured operands
instruction.Operands = $"{rmRegName}, {regName}"; instruction.StructuredOperands =
} [
else // Memory operand destinationOperand,
{ sourceOperand
instruction.Operands = $"{memOperand}, {regName}"; ];
}
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Mov; namespace X86Disassembler.X86.Handlers.Mov;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class MovMoffsEaxHandler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the MovMoffsEaxHandler class /// Initializes a new instance of the MovMoffsEaxHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public MovMoffsEaxHandler(InstructionDecoder decoder)
public MovMoffsEaxHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,23 +34,34 @@ public class MovMoffsEaxHandler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "mov"; instruction.Type = InstructionType.Mov;
// Get the operand size and register name // Get the operand size based on the opcode
int operandSize = opcode == 0xA2 ? 8 : 32; int operandSize = opcode == 0xA2 ? 8 : 32;
string regName = ModRMDecoder.GetRegisterName(RegisterIndex.A, operandSize);
// Read the memory offset // Read the memory offset
uint offset = Decoder.ReadUInt32(); // Fixed bug: Changed from if (Decoder.CanReadUInt()) to if (!Decoder.CanReadUInt())
if (Decoder.GetPosition() > Length) if (!Decoder.CanReadUInt())
{ {
return false; return false;
} }
// Set the operands uint offset = Decoder.ReadUInt32();
instruction.Operands = $"[0x{offset:X}], {regName}";
// Create the destination memory operand
// For MOV moffs32, EAX or MOV moffs8, AL, the memory operand is a direct memory reference
var destinationOperand = OperandFactory.CreateDirectMemoryOperand(offset, operandSize);
// Create the source register operand (EAX or AL)
var sourceOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.A, operandSize);
// Set the structured operands
instruction.StructuredOperands =
[
destinationOperand,
sourceOperand
];
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Mov; namespace X86Disassembler.X86.Handlers.Mov;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class MovRegImm32Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the MovRegImm32Handler class /// Initializes a new instance of the MovRegImm32Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public MovRegImm32Handler(InstructionDecoder decoder)
public MovRegImm32Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,22 +34,32 @@ public class MovRegImm32Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "mov"; instruction.Type = InstructionType.Mov;
// Register is encoded in the low 3 bits of the opcode // Register is encoded in the low 3 bits of the opcode
RegisterIndex reg = (RegisterIndex) (opcode & 0x07); RegisterIndex reg = (RegisterIndex)(opcode & 0x07);
string regName = ModRMDecoder.GetRegisterName(reg, 32);
// Read the immediate value // Read the immediate value
uint imm32 = Decoder.ReadUInt32(); if (!Decoder.CanReadUInt())
if (Decoder.GetPosition() > Length)
{ {
return false; return false;
} }
// Set the operands uint imm32 = Decoder.ReadUInt32();
instruction.Operands = $"{regName}, 0x{imm32:X}";
// Create the destination register operand
var destinationOperand = OperandFactory.CreateRegisterOperand(reg, 32);
// Create the source immediate operand
var sourceOperand = OperandFactory.CreateImmediateOperand(imm32, 32);
// Set the structured operands
instruction.StructuredOperands =
[
destinationOperand,
sourceOperand
];
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Mov; namespace X86Disassembler.X86.Handlers.Mov;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class MovRegImm8Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the MovRegImm8Handler class /// Initializes a new instance of the MovRegImm8Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public MovRegImm8Handler(InstructionDecoder decoder)
public MovRegImm8Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,23 +34,32 @@ public class MovRegImm8Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "mov"; instruction.Type = InstructionType.Mov;
// Register is encoded in the low 3 bits of the opcode // Register is encoded in the low 3 bits of the opcode
RegisterIndex reg = (RegisterIndex) (opcode & 0x07); RegisterIndex reg = (RegisterIndex)(opcode & 0x07);
string regName = ModRMDecoder.GetRegisterName(reg, 8);
// Read the immediate value // Read the immediate value
byte imm8 = Decoder.ReadByte(); if (!Decoder.CanReadByte())
if (Decoder.GetPosition() > Length)
{ {
return false; return false;
} }
// Set the operands byte imm8 = Decoder.ReadByte();
instruction.Operands = $"{regName}, 0x{imm8:X2}";
// Create the destination register operand
var destinationOperand = OperandFactory.CreateRegisterOperand(reg, 8);
// Create the source immediate operand
var sourceOperand = OperandFactory.CreateImmediateOperand(imm8, 8);
// Set the structured operands
instruction.StructuredOperands =
[
destinationOperand,
sourceOperand
];
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Mov; namespace X86Disassembler.X86.Handlers.Mov;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class MovRegMemHandler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the MovRegMemHandler class /// Initializes a new instance of the MovRegMemHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public MovRegMemHandler(InstructionDecoder decoder)
public MovRegMemHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,8 +34,8 @@ public class MovRegMemHandler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "mov"; instruction.Type = InstructionType.Mov;
// Check if we have enough bytes for the ModR/M byte // Check if we have enough bytes for the ModR/M byte
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
@ -47,14 +47,23 @@ public class MovRegMemHandler : InstructionHandler
int operandSize = (opcode & 0x01) != 0 ? 32 : 8; int operandSize = (opcode & 0x01) != 0 ? 32 : 8;
// Use ModRMDecoder to decode the ModR/M byte // Use ModRMDecoder to decode the ModR/M byte
var (mod, reg, rm, rmOperand) = ModRMDecoder.ReadModRM(); // For MOV r32, r/m32 (0x8B) or MOV r8, r/m8 (0x8A):
// - The reg field specifies the destination register
// - The r/m field with mod specifies the source operand (register or memory)
var (mod, reg, rm, sourceOperand) = ModRMDecoder.ReadModRM();
// Get register name based on size // Adjust the operand size based on the opcode
string regName = ModRMDecoder.GetRegisterName(reg, operandSize); sourceOperand.Size = operandSize;
// Set the operands - register is the destination, r/m is the source (for 0x8B) // Create the destination register operand
// This matches the correct x86 instruction format: MOV r32, r/m32 var destinationOperand = OperandFactory.CreateRegisterOperand(reg, operandSize);
instruction.Operands = $"{regName}, {rmOperand}";
// Set the structured operands
instruction.StructuredOperands =
[
destinationOperand,
sourceOperand
];
return true; return true;
} }

View File

@ -1,5 +1,7 @@
namespace X86Disassembler.X86.Handlers.Mov; namespace X86Disassembler.X86.Handlers.Mov;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for MOV r/m32, imm32 instruction (0xC7) /// Handler for MOV r/m32, imm32 instruction (0xC7)
/// </summary> /// </summary>
@ -8,11 +10,9 @@ public class MovRm32Imm32Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the MovRm32Imm32Handler class /// Initializes a new instance of the MovRm32Imm32Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public MovRm32Imm32Handler(InstructionDecoder decoder)
public MovRm32Imm32Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,8 +34,8 @@ public class MovRm32Imm32Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "mov"; instruction.Type = InstructionType.Mov;
// Check if we have enough bytes for the ModR/M byte // Check if we have enough bytes for the ModR/M byte
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
@ -44,7 +44,7 @@ public class MovRm32Imm32Handler : InstructionHandler
} }
// Use ModRMDecoder to decode the ModR/M byte // Use ModRMDecoder to decode the ModR/M byte
var (mod, reg, rm, operand) = ModRMDecoder.ReadModRM(false); var (mod, reg, rm, destinationOperand) = ModRMDecoder.ReadModRM(false);
// MOV r/m32, imm32 only uses reg=0 // MOV r/m32, imm32 only uses reg=0
if (reg != 0) if (reg != 0)
@ -58,9 +58,18 @@ public class MovRm32Imm32Handler : InstructionHandler
return false; return false;
} }
// Read the immediate dword and format the operands // Read the immediate dword and create the operands
uint imm32 = Decoder.ReadUInt32(); uint imm32 = Decoder.ReadUInt32();
instruction.Operands = $"{operand}, 0x{imm32:X8}";
// Create the immediate operand
var sourceOperand = OperandFactory.CreateImmediateOperand(imm32, 32);
// Set the structured operands
instruction.StructuredOperands =
[
destinationOperand,
sourceOperand
];
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Mov; namespace X86Disassembler.X86.Handlers.Mov;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class MovRm8Imm8Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the MovRm8Imm8Handler class /// Initializes a new instance of the MovRm8Imm8Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public MovRm8Imm8Handler(InstructionDecoder decoder)
public MovRm8Imm8Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,8 +34,8 @@ public class MovRm8Imm8Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "mov"; instruction.Type = InstructionType.Mov;
// Check if we have enough bytes for the ModR/M byte // Check if we have enough bytes for the ModR/M byte
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
@ -44,7 +44,10 @@ public class MovRm8Imm8Handler : InstructionHandler
} }
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM(); // For MOV r/m8, imm8 (0xC6):
// - The r/m field with mod specifies the destination operand (register or memory)
// - The immediate value is the source operand
var (mod, reg, rm, destinationOperand) = ModRMDecoder.ReadModRM();
// MOV r/m8, imm8 only uses reg=0 // MOV r/m8, imm8 only uses reg=0
if (reg != 0) if (reg != 0)
@ -52,17 +55,8 @@ public class MovRm8Imm8Handler : InstructionHandler
return false; return false;
} }
// For direct register addressing (mod == 3), use 8-bit register names // Adjust the operand size to 8-bit
if (mod == 3) destinationOperand.Size = 8;
{
// Use 8-bit register names for direct register addressing
destOperand = ModRMDecoder.GetRegisterName(rm, 8);
}
else
{
// Replace the size prefix with "byte ptr" for memory operands
destOperand = destOperand.Replace("dword ptr", "byte ptr");
}
// Read the immediate value // Read the immediate value
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
@ -72,8 +66,15 @@ public class MovRm8Imm8Handler : InstructionHandler
byte imm8 = Decoder.ReadByte(); byte imm8 = Decoder.ReadByte();
// Set the operands // Create the source immediate operand
instruction.Operands = $"{destOperand}, 0x{imm8:X2}"; var sourceOperand = OperandFactory.CreateImmediateOperand(imm8, 8);
// Set the structured operands
instruction.StructuredOperands =
[
destinationOperand,
sourceOperand
];
return true; return true;
} }

View File

@ -1,5 +1,7 @@
namespace X86Disassembler.X86.Handlers.Nop; namespace X86Disassembler.X86.Handlers.Nop;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for INT3 instruction (0xCC) /// Handler for INT3 instruction (0xCC)
/// </summary> /// </summary>
@ -8,11 +10,9 @@ public class Int3Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the Int3Handler class /// Initializes a new instance of the Int3Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public Int3Handler(InstructionDecoder decoder)
public Int3Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,11 +34,11 @@ public class Int3Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "int3"; instruction.Type = InstructionType.Int;
// Set the operands // INT3 has no operands
instruction.Operands = ""; instruction.StructuredOperands = [];
return true; return true;
} }

View File

@ -1,41 +1,41 @@
namespace X86Disassembler.X86.Handlers.Nop; namespace X86Disassembler.X86.Handlers.Nop;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for multi-byte NOP instructions (0x0F 0x1F ...) /// Handler for multi-byte NOP instructions (0x0F 0x1F ...)
/// These are used for alignment and are encoded as NOP operations with specific memory operands /// These are used for alignment and are encoded as NOP operations with specific memory operands
/// </summary> /// </summary>
public class MultiByteNopHandler : InstructionHandler public class MultiByteNopHandler : InstructionHandler
{ {
// NOP variant information (ModR/M byte, memory operand, and expected bytes pattern) // NOP variant information (ModR/M byte, expected bytes pattern, and operand creation info)
private static readonly (byte ModRm, string MemOperand, byte[] ExpectedBytes)[] NopVariants = private static readonly (byte ModRm, byte[] ExpectedBytes, RegisterIndex BaseReg, RegisterIndex? IndexReg, int Scale)[] NopVariants =
{ {
// 8-byte NOP: 0F 1F 84 00 00 00 00 00 (check longest patterns first) // 8-byte NOP: 0F 1F 84 00 00 00 00 00 (check longest patterns first)
(0x84, "[eax+eax*1]", new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00 }), (0x84, new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00 }, RegisterIndex.A, RegisterIndex.A, 1),
// 7-byte NOP: 0F 1F 80 00 00 00 00 // 7-byte NOP: 0F 1F 80 00 00 00 00
(0x80, "[eax]", new byte[] { 0x00, 0x00, 0x00, 0x00 }), (0x80, new byte[] { 0x00, 0x00, 0x00, 0x00 }, RegisterIndex.A, null, 0),
// 6-byte NOP: 0F 1F 44 00 00 00 // 6-byte NOP: 0F 1F 44 00 00 00
(0x44, "[eax+eax*1]", new byte[] { 0x00, 0x00, 0x00 }), (0x44, new byte[] { 0x00, 0x00, 0x00 }, RegisterIndex.A, RegisterIndex.A, 1),
// 5-byte NOP: 0F 1F 44 00 00 // 5-byte NOP: 0F 1F 44 00 00
(0x44, "[eax+eax*1]", new byte[] { 0x00, 0x00 }), (0x44, new byte[] { 0x00, 0x00 }, RegisterIndex.A, RegisterIndex.A, 1),
// 4-byte NOP: 0F 1F 40 00 // 4-byte NOP: 0F 1F 40 00
(0x40, "[eax]", new byte[] { 0x00 }), (0x40, new byte[] { 0x00 }, RegisterIndex.A, null, 0),
// 3-byte NOP: 0F 1F 00 // 3-byte NOP: 0F 1F 00
(0x00, "[eax]", Array.Empty<byte>()) (0x00, Array.Empty<byte>(), RegisterIndex.A, null, 0)
}; };
/// <summary> /// <summary>
/// Initializes a new instance of the MultiByteNopHandler class /// Initializes a new instance of the MultiByteNopHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public MultiByteNopHandler(InstructionDecoder decoder)
public MultiByteNopHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -59,7 +59,7 @@ public class MultiByteNopHandler : InstructionHandler
} }
// Check if the second byte is 0x1F (part of the multi-byte NOP encoding) // Check if the second byte is 0x1F (part of the multi-byte NOP encoding)
byte secondByte = CodeBuffer[Decoder.GetPosition()]; byte secondByte = Decoder.PeakByte();
return secondByte == 0x1F; return secondByte == 0x1F;
} }
@ -71,8 +71,8 @@ public class MultiByteNopHandler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "nop"; instruction.Type = InstructionType.Nop;
// Skip the second byte (0x1F) // Skip the second byte (0x1F)
Decoder.ReadByte(); Decoder.ReadByte();
@ -87,27 +87,28 @@ public class MultiByteNopHandler : InstructionHandler
bool hasOperandSizePrefix = Decoder.HasOperandSizeOverridePrefix(); bool hasOperandSizePrefix = Decoder.HasOperandSizeOverridePrefix();
// Determine the size of the operand // Determine the size of the operand
string ptrType = hasOperandSizePrefix ? "word ptr" : "dword ptr"; int operandSize = hasOperandSizePrefix ? 16 : 32;
// Read the ModR/M byte but don't advance the position yet // Read the ModR/M byte but don't advance the position yet
int position = Decoder.GetPosition(); byte modRm = Decoder.PeakByte();
byte modRm = CodeBuffer[position];
// Default memory operand if no specific variant is matched // Default memory operand parameters
string memOperand = "[eax]"; RegisterIndex baseReg = RegisterIndex.A;
RegisterIndex? indexReg = null;
int scale = 0;
int bytesToSkip = 1; // Skip at least the ModR/M byte int bytesToSkip = 1; // Skip at least the ModR/M byte
// Try to find a matching NOP variant (we check longest patterns first) // Try to find a matching NOP variant (we check longest patterns first)
foreach (var (variantModRm, operand, expectedBytes) in NopVariants) foreach (var (variantModRm, expectedBytes, variantBaseReg, variantIndexReg, variantScale) in NopVariants)
{ {
// Skip if ModR/M doesn't match // Skip if ModR/M doesn't match
if (variantModRm != modRm) if (variantModRm != modRm)
{ {
continue; continue;
} }
// Check if we have enough bytes for this pattern // Check if we have enough bytes for this pattern
if (position + expectedBytes.Length >= Length) if (!Decoder.CanRead(expectedBytes.Length + 1)) // +1 for ModR/M byte
{ {
continue; continue;
} }
@ -116,7 +117,9 @@ public class MultiByteNopHandler : InstructionHandler
bool isMatch = true; bool isMatch = true;
for (int i = 0; i < expectedBytes.Length; i++) for (int i = 0; i < expectedBytes.Length; i++)
{ {
if (position + i + 1 >= Length || CodeBuffer[position + i + 1] != expectedBytes[i]) // Check the byte at position
byte actualByte = Decoder.PeakByte();
if (actualByte != expectedBytes[i])
{ {
isMatch = false; isMatch = false;
break; break;
@ -126,17 +129,41 @@ public class MultiByteNopHandler : InstructionHandler
// If we found a match, use it and stop checking // If we found a match, use it and stop checking
if (isMatch) if (isMatch)
{ {
memOperand = operand; baseReg = variantBaseReg;
indexReg = variantIndexReg;
scale = variantScale;
bytesToSkip = 1 + expectedBytes.Length; // ModR/M byte + additional bytes bytesToSkip = 1 + expectedBytes.Length; // ModR/M byte + additional bytes
break; break;
} }
} }
// Skip the bytes we've processed // Skip the bytes we've processed
Decoder.SetPosition(position + bytesToSkip); Decoder.SetPosition(Decoder.GetPosition() + bytesToSkip);
// Set the operands with the appropriate size prefix // Create the appropriate structured operand based on the NOP variant
instruction.Operands = $"{ptrType} {memOperand}"; if (indexReg.HasValue && scale > 0)
{
// Create a scaled index memory operand (e.g., [eax+eax*1])
instruction.StructuredOperands =
[
OperandFactory.CreateScaledIndexMemoryOperand(
indexReg.Value,
scale,
baseReg,
0,
operandSize)
];
}
else
{
// Create a simple base register memory operand (e.g., [eax])
instruction.StructuredOperands =
[
OperandFactory.CreateBaseRegisterMemoryOperand(
baseReg,
operandSize)
];
}
return true; return true;
} }

View File

@ -1,5 +1,7 @@
namespace X86Disassembler.X86.Handlers.Nop; namespace X86Disassembler.X86.Handlers.Nop;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for the NOP instruction (opcode 0x90) /// Handler for the NOP instruction (opcode 0x90)
/// </summary> /// </summary>
@ -8,11 +10,9 @@ public class NopHandler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the NopHandler class /// Initializes a new instance of the NopHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public NopHandler(InstructionDecoder decoder)
public NopHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -35,11 +35,11 @@ public class NopHandler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "nop"; instruction.Type = InstructionType.Nop;
// NOP has no operands // NOP has no operands
instruction.Operands = ""; instruction.StructuredOperands = [];
return true; return true;
} }

View File

@ -1,5 +1,7 @@
namespace X86Disassembler.X86.Handlers.Nop; namespace X86Disassembler.X86.Handlers.Nop;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for the 2-byte NOP instruction (0x66 0x90) /// Handler for the 2-byte NOP instruction (0x66 0x90)
/// This is actually XCHG AX, AX with an operand size prefix /// This is actually XCHG AX, AX with an operand size prefix
@ -9,11 +11,9 @@ public class TwoByteNopHandler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the TwoByteNopHandler class /// Initializes a new instance of the TwoByteNopHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public TwoByteNopHandler(InstructionDecoder decoder)
public TwoByteNopHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -38,10 +38,10 @@ public class TwoByteNopHandler : InstructionHandler
{ {
// Although this is actually XCHG AX, AX, it's treated as NOP in the x86 architecture // Although this is actually XCHG AX, AX, it's treated as NOP in the x86 architecture
// and is commonly disassembled as such // and is commonly disassembled as such
instruction.Mnemonic = "nop"; instruction.Type = InstructionType.Nop;
// NOP has no operands, even with the operand size prefix // NOP has no operands, even with the operand size prefix
instruction.Operands = ""; instruction.StructuredOperands = [];
return true; return true;
} }

View File

@ -1,5 +1,7 @@
namespace X86Disassembler.X86.Handlers.Or; namespace X86Disassembler.X86.Handlers.Or;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for OR AL, imm8 instruction (0x0C) /// Handler for OR AL, imm8 instruction (0x0C)
/// </summary> /// </summary>
@ -8,11 +10,9 @@ public class OrAlImmHandler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the OrAlImmHandler class /// Initializes a new instance of the OrAlImmHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public OrAlImmHandler(InstructionDecoder decoder)
public OrAlImmHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,6 +34,9 @@ public class OrAlImmHandler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the instruction type
instruction.Type = InstructionType.Or;
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
return false; return false;
@ -42,11 +45,18 @@ public class OrAlImmHandler : InstructionHandler
// Read the immediate byte // Read the immediate byte
byte imm8 = Decoder.ReadByte(); byte imm8 = Decoder.ReadByte();
// Set the mnemonic // Create the register operand for AL
instruction.Mnemonic = "or"; var alOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.A, 8);
// Set the operands // Create the immediate operand
instruction.Operands = $"al, 0x{imm8:X2}"; var immOperand = OperandFactory.CreateImmediateOperand(imm8, 8);
// Set the structured operands
instruction.StructuredOperands =
[
alOperand,
immOperand
];
return true; return true;
} }

View File

@ -1,5 +1,7 @@
namespace X86Disassembler.X86.Handlers.Or; namespace X86Disassembler.X86.Handlers.Or;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for OR EAX, imm32 instruction (0x0D) /// Handler for OR EAX, imm32 instruction (0x0D)
/// </summary> /// </summary>
@ -8,11 +10,9 @@ public class OrEaxImmHandler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the OrEaxImmHandler class /// Initializes a new instance of the OrEaxImmHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public OrEaxImmHandler(InstructionDecoder decoder)
public OrEaxImmHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,20 +34,29 @@ public class OrEaxImmHandler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
if (!Decoder.CanReadByte()) // Set the instruction type
instruction.Type = InstructionType.Or;
if (!Decoder.CanReadUInt())
{ {
return false; return false;
} }
// Read the immediate dword (little-endian) // Read the immediate dword (little-endian)
uint imm32 = Decoder.ReadUInt32(); uint imm32 = Decoder.ReadUInt32();
// Set the mnemonic // Create the register operand for EAX
instruction.Mnemonic = "or"; var eaxOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.A);
// Set the operands // Create the immediate operand
instruction.Operands = $"eax, 0x{imm32:X8}"; var immOperand = OperandFactory.CreateImmediateOperand(imm32);
// Set the structured operands
instruction.StructuredOperands =
[
eaxOperand,
immOperand
];
return true; return true;
} }

View File

@ -1,5 +1,7 @@
namespace X86Disassembler.X86.Handlers.Or; namespace X86Disassembler.X86.Handlers.Or;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for OR r/m32, imm32 instruction (0x81 /1) /// Handler for OR r/m32, imm32 instruction (0x81 /1)
/// </summary> /// </summary>
@ -8,11 +10,9 @@ public class OrImmToRm32Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the OrImmToRm32Handler class /// Initializes a new instance of the OrImmToRm32Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public OrImmToRm32Handler(InstructionDecoder decoder)
public OrImmToRm32Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -30,7 +30,7 @@ public class OrImmToRm32Handler : InstructionHandler
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
return false; return false;
byte modRM = CodeBuffer[Decoder.GetPosition()]; byte modRM = Decoder.PeakByte();
byte reg = (byte) ((modRM & 0x38) >> 3); byte reg = (byte) ((modRM & 0x38) >> 3);
return reg == 1; // 1 = OR return reg == 1; // 1 = OR
@ -44,8 +44,8 @@ public class OrImmToRm32Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "or"; instruction.Type = InstructionType.Or;
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
@ -55,15 +55,24 @@ public class OrImmToRm32Handler : InstructionHandler
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM(); var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM();
if (!Decoder.CanReadByte()) // Check if we can read the immediate value
if (!Decoder.CanReadUInt())
{ {
return false; return false;
} }
// Read the immediate value
uint imm32 = Decoder.ReadUInt32(); uint imm32 = Decoder.ReadUInt32();
// Set the operands // Create the immediate operand
instruction.Operands = $"{destOperand}, 0x{imm32:X8}"; var immOperand = OperandFactory.CreateImmediateOperand(imm32);
// Set the structured operands
instruction.StructuredOperands =
[
destOperand,
immOperand
];
return true; return true;
} }

View File

@ -1,5 +1,7 @@
namespace X86Disassembler.X86.Handlers.Or; namespace X86Disassembler.X86.Handlers.Or;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for OR r/m32, imm8 (sign-extended) instruction (0x83 /1) /// Handler for OR r/m32, imm8 (sign-extended) instruction (0x83 /1)
/// </summary> /// </summary>
@ -8,11 +10,9 @@ public class OrImmToRm32SignExtendedHandler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the OrImmToRm32SignExtendedHandler class /// Initializes a new instance of the OrImmToRm32SignExtendedHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public OrImmToRm32SignExtendedHandler(InstructionDecoder decoder)
public OrImmToRm32SignExtendedHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -30,7 +30,7 @@ public class OrImmToRm32SignExtendedHandler : InstructionHandler
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
return false; return false;
byte modRM = CodeBuffer[Decoder.GetPosition()]; byte modRM = Decoder.PeakByte();
byte reg = (byte) ((modRM & 0x38) >> 3); byte reg = (byte) ((modRM & 0x38) >> 3);
return reg == 1; // 1 = OR return reg == 1; // 1 = OR
@ -44,12 +44,10 @@ public class OrImmToRm32SignExtendedHandler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "or"; instruction.Type = InstructionType.Or;
int position = Decoder.GetPosition(); if (!Decoder.CanReadByte())
if (position >= Length)
{ {
return false; return false;
} }
@ -58,16 +56,23 @@ public class OrImmToRm32SignExtendedHandler : InstructionHandler
var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM(); var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM();
// Read the immediate value (sign-extended from 8 to 32 bits) // Read the immediate value (sign-extended from 8 to 32 bits)
if (position >= Length) if (!Decoder.CanReadByte())
{ {
return false; return false;
} }
// Sign-extend to 32 bits // Sign-extend to 32 bits
int imm32 = (sbyte) Decoder.ReadByte(); sbyte imm8 = (sbyte) Decoder.ReadByte();
// Set the operands // Create the immediate operand with sign extension
instruction.Operands = $"{destOperand}, 0x{imm32:X8}"; var immOperand = OperandFactory.CreateImmediateOperand(imm8);
// Set the structured operands
instruction.StructuredOperands =
[
destOperand,
immOperand
];
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Or; namespace X86Disassembler.X86.Handlers.Or;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class OrImmToRm8Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the OrImmToRm8Handler class /// Initializes a new instance of the OrImmToRm8Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public OrImmToRm8Handler(InstructionDecoder decoder)
public OrImmToRm8Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -30,7 +30,7 @@ public class OrImmToRm8Handler : InstructionHandler
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
return false; return false;
byte modRM = CodeBuffer[Decoder.GetPosition()]; byte modRM = Decoder.PeakByte();
byte reg = (byte) ((modRM & 0x38) >> 3); byte reg = (byte) ((modRM & 0x38) >> 3);
return reg == 1; // 1 = OR return reg == 1; // 1 = OR
@ -44,8 +44,8 @@ public class OrImmToRm8Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "or"; instruction.Type = InstructionType.Or;
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
@ -53,14 +53,13 @@ public class OrImmToRm8Handler : InstructionHandler
} }
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM(); // For OR r/m8, imm8 (0x80 /1):
// - The r/m field with mod specifies the destination operand (register or memory)
// For direct register addressing (mod == 3), use 8-bit register names // - The immediate value is the source operand
if (mod == 3) var (mod, reg, rm, destinationOperand) = ModRMDecoder.ReadModRM();
{
// Use 8-bit register names for direct register addressing // Adjust the operand size to 8-bit
destOperand = ModRMDecoder.GetRegisterName(rm, 8); destinationOperand.Size = 8;
}
// Read the immediate value // Read the immediate value
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
@ -70,9 +69,16 @@ public class OrImmToRm8Handler : InstructionHandler
// Read the immediate value // Read the immediate value
byte imm8 = Decoder.ReadByte(); byte imm8 = Decoder.ReadByte();
// Set the operands // Create the source immediate operand
instruction.Operands = $"{destOperand}, 0x{imm8:X2}"; var sourceOperand = OperandFactory.CreateImmediateOperand(imm8, 8);
// Set the structured operands
instruction.StructuredOperands =
[
destinationOperand,
sourceOperand
];
return true; return true;
} }

View File

@ -1,5 +1,7 @@
namespace X86Disassembler.X86.Handlers.Or; namespace X86Disassembler.X86.Handlers.Or;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for OR r32, r/m32 instruction (0x0B) /// Handler for OR r32, r/m32 instruction (0x0B)
/// </summary> /// </summary>
@ -8,11 +10,9 @@ public class OrR32Rm32Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the OrR32Rm32Handler class /// Initializes a new instance of the OrR32Rm32Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public OrR32Rm32Handler(InstructionDecoder decoder)
public OrR32Rm32Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,6 +34,9 @@ public class OrR32Rm32Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the instruction type
instruction.Type = InstructionType.Or;
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
return false; return false;
@ -42,21 +45,30 @@ public class OrR32Rm32Handler : InstructionHandler
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM(); var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM();
// Set the mnemonic // Create the register operand for the reg field
instruction.Mnemonic = "or"; var regOperand = OperandFactory.CreateRegisterOperand(reg);
// Get the register name // Set the structured operands based on addressing mode
string regName = ModRMDecoder.GetRegisterName(reg, 32); if (mod == 3) // Direct register addressing
// For memory operands, set the operand
if (mod != 3) // Memory operand
{ {
instruction.Operands = $"{regName}, {destOperand}"; // Create the register operand for the r/m field
var rmOperand = OperandFactory.CreateRegisterOperand(rm);
// Set the structured operands
instruction.StructuredOperands =
[
regOperand,
rmOperand
];
} }
else // Register operand else // Memory addressing
{ {
string rmName = ModRMDecoder.GetRegisterName(rm, 32); // Set the structured operands
instruction.Operands = $"{regName}, {rmName}"; instruction.StructuredOperands =
[
regOperand,
destOperand
];
} }
return true; return true;

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Or; namespace X86Disassembler.X86.Handlers.Or;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class OrR8Rm8Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the OrR8Rm8Handler class /// Initializes a new instance of the OrR8Rm8Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public OrR8Rm8Handler(InstructionDecoder decoder)
public OrR8Rm8Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,32 +34,32 @@ public class OrR8Rm8Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the instruction type
instruction.Type = InstructionType.Or;
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
return false; return false;
} }
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM(); // For OR r8, r/m8 (0x0A):
// - The reg field specifies the destination register
// - The r/m field with mod specifies the source operand (register or memory)
var (mod, reg, rm, sourceOperand) = ModRMDecoder.ReadModRM();
// Set the mnemonic // Adjust the operand size to 8-bit
instruction.Mnemonic = "or"; sourceOperand.Size = 8;
// Get the register name // Create the destination register operand
string regName = ModRMDecoder.GetRegisterName(reg, 8); var destinationOperand = OperandFactory.CreateRegisterOperand(reg, 8);
// For memory operands, set the operand // Set the structured operands
if (mod != 3) // Memory operand instruction.StructuredOperands =
{ [
// Replace dword ptr with byte ptr for 8-bit operations destinationOperand,
destOperand = destOperand.Replace("dword ptr", "byte ptr"); sourceOperand
instruction.Operands = $"{regName}, {destOperand}"; ];
}
else // Register operand
{
string rmName = ModRMDecoder.GetRegisterName(rm, 8);
instruction.Operands = $"{regName}, {rmName}";
}
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Or; namespace X86Disassembler.X86.Handlers.Or;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class OrRm8R8Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the OrRm8R8Handler class /// Initializes a new instance of the OrRm8R8Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public OrRm8R8Handler(InstructionDecoder decoder)
public OrRm8R8Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,8 +34,8 @@ public class OrRm8R8Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "or"; instruction.Type = InstructionType.Or;
// Check if we have enough bytes for the ModR/M byte // Check if we have enough bytes for the ModR/M byte
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
@ -43,28 +43,24 @@ public class OrRm8R8Handler : InstructionHandler
return false; return false;
} }
// Read the ModR/M byte and decode the operands // Read the ModR/M byte
var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM(); // For OR r/m8, r8 (0x08):
// - The r/m field with mod specifies the destination operand (register or memory)
// - The reg field specifies the source register
var (mod, reg, rm, destinationOperand) = ModRMDecoder.ReadModRM();
// The register operand is in the reg field (8-bit register) // Adjust the operand size to 8-bit
string regOperand = ModRMDecoder.GetRegisterName(reg, 8); destinationOperand.Size = 8;
// Handle the r/m operand based on mod field // Create the source register operand
string rmOperand; var sourceOperand = OperandFactory.CreateRegisterOperand(reg, 8);
if (mod == 3) // Register-to-register // Set the structured operands
{ instruction.StructuredOperands =
// Direct register addressing [
rmOperand = ModRMDecoder.GetRegisterName(rm, 8); destinationOperand,
} sourceOperand
else // Memory addressing ];
{
// Replace "dword ptr" with "byte ptr" for 8-bit operands
rmOperand = destOperand.Replace("dword ptr", "byte ptr");
}
// Set the operands (r/m8, r8 format)
instruction.Operands = $"{rmOperand}, {regOperand}";
return true; return true;
} }

View File

@ -1,5 +1,7 @@
namespace X86Disassembler.X86.Handlers.Pop; namespace X86Disassembler.X86.Handlers.Pop;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for POP r32 instruction (0x58-0x5F) /// Handler for POP r32 instruction (0x58-0x5F)
/// </summary> /// </summary>
@ -8,11 +10,9 @@ public class PopRegHandler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the PopRegHandler class /// Initializes a new instance of the PopRegHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public PopRegHandler(InstructionDecoder decoder)
public PopRegHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,15 +34,20 @@ public class PopRegHandler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "pop"; instruction.Type = InstructionType.Pop;
// Register is encoded in the low 3 bits of the opcode // Register is encoded in the low 3 bits of the opcode
RegisterIndex reg = (RegisterIndex)(opcode & 0x07); RegisterIndex reg = (RegisterIndex)(opcode & 0x07);
string regName = ModRMDecoder.GetRegisterName(reg, 32);
// Set the operands // Create the register operand
instruction.Operands = regName; var regOperand = OperandFactory.CreateRegisterOperand(reg);
// Set the structured operands
instruction.StructuredOperands =
[
regOperand
];
return true; return true;
} }

View File

@ -1,5 +1,7 @@
namespace X86Disassembler.X86.Handlers.Push; namespace X86Disassembler.X86.Handlers.Push;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for PUSH imm32 instruction (0x68) /// Handler for PUSH imm32 instruction (0x68)
/// </summary> /// </summary>
@ -8,11 +10,9 @@ public class PushImm32Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the PushImm32Handler class /// Initializes a new instance of the PushImm32Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public PushImm32Handler(InstructionDecoder decoder)
public PushImm32Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,8 +34,8 @@ public class PushImm32Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "push"; instruction.Type = InstructionType.Push;
if(!Decoder.CanReadUInt()) if(!Decoder.CanReadUInt())
{ {
@ -45,8 +45,14 @@ public class PushImm32Handler : InstructionHandler
// Read the immediate value // Read the immediate value
uint imm32 = Decoder.ReadUInt32(); uint imm32 = Decoder.ReadUInt32();
// Set the operands with 8-digit padding to match test expectations // Create the immediate operand
instruction.Operands = $"0x{imm32:X8}"; var immOperand = OperandFactory.CreateImmediateOperand(imm32);
// Set the structured operands
instruction.StructuredOperands =
[
immOperand
];
return true; return true;
} }

View File

@ -1,5 +1,7 @@
namespace X86Disassembler.X86.Handlers.Push; namespace X86Disassembler.X86.Handlers.Push;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for PUSH imm8 instruction (0x6A) /// Handler for PUSH imm8 instruction (0x6A)
/// </summary> /// </summary>
@ -8,11 +10,9 @@ public class PushImm8Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the PushImm8Handler class /// Initializes a new instance of the PushImm8Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public PushImm8Handler(InstructionDecoder decoder)
public PushImm8Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,8 +34,8 @@ public class PushImm8Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "push"; instruction.Type = InstructionType.Push;
if(!Decoder.CanReadByte()) if(!Decoder.CanReadByte())
{ {
@ -45,8 +45,15 @@ public class PushImm8Handler : InstructionHandler
// Read the immediate value // Read the immediate value
byte imm8 = Decoder.ReadByte(); byte imm8 = Decoder.ReadByte();
// Set the operands // Create the immediate operand
instruction.Operands = $"0x{imm8:X2}"; // Sign-extend the 8-bit value to 32-bit for proper stack alignment
var immOperand = OperandFactory.CreateImmediateOperand((sbyte)imm8);
// Set the structured operands
instruction.StructuredOperands =
[
immOperand
];
return true; return true;
} }

View File

@ -1,5 +1,7 @@
namespace X86Disassembler.X86.Handlers.Push; namespace X86Disassembler.X86.Handlers.Push;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for PUSH r32 instruction (0x50-0x57) /// Handler for PUSH r32 instruction (0x50-0x57)
/// </summary> /// </summary>
@ -8,11 +10,9 @@ public class PushRegHandler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the PushRegHandler class /// Initializes a new instance of the PushRegHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public PushRegHandler(InstructionDecoder decoder)
public PushRegHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,15 +34,20 @@ public class PushRegHandler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "push"; instruction.Type = InstructionType.Push;
// Register is encoded in the low 3 bits of the opcode // Register is encoded in the low 3 bits of the opcode
RegisterIndex reg = (RegisterIndex) (opcode & 0x07); RegisterIndex reg = (RegisterIndex)(opcode & 0x07);
string regName = ModRMDecoder.GetRegisterName(reg, 32);
// Create the register operand
var regOperand = OperandFactory.CreateRegisterOperand(reg, 32);
// Set the operands // Set the structured operands
instruction.Operands = regName; instruction.StructuredOperands =
[
regOperand
];
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Push; namespace X86Disassembler.X86.Handlers.Push;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class PushRm32Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the PushRm32Handler class /// Initializes a new instance of the PushRm32Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public PushRm32Handler(InstructionDecoder decoder)
public PushRm32Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -36,7 +36,7 @@ public class PushRm32Handler : InstructionHandler
} }
// Peek at the ModR/M byte without advancing the position // Peek at the ModR/M byte without advancing the position
byte modRM = CodeBuffer[Decoder.GetPosition()]; byte modRM = Decoder.PeakByte();
// Extract the reg field (bits 3-5) // Extract the reg field (bits 3-5)
byte reg = (byte)((modRM & 0x38) >> 3); byte reg = (byte)((modRM & 0x38) >> 3);
@ -53,8 +53,8 @@ public class PushRm32Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "push"; instruction.Type = InstructionType.Push;
// Check if we have enough bytes for the ModR/M byte // Check if we have enough bytes for the ModR/M byte
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
@ -63,18 +63,16 @@ public class PushRm32Handler : InstructionHandler
} }
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM(); // For PUSH r/m32 (FF /6):
// - The r/m field with mod specifies the operand (register or memory)
var (mod, reg, rm, operand) = ModRMDecoder.ReadModRM();
// For memory operands, set the operand // Set the structured operands
if (mod != 3) // Memory operand // PUSH has only one operand
{ instruction.StructuredOperands =
instruction.Operands = destOperand; [
} operand
else // Register operand ];
{
string rmName = ModRMDecoder.GetRegisterName(rm, 32);
instruction.Operands = rmName;
}
return true; return true;
} }

View File

@ -1,5 +1,7 @@
namespace X86Disassembler.X86.Handlers.Ret; namespace X86Disassembler.X86.Handlers.Ret;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for RET instruction (0xC3) /// Handler for RET instruction (0xC3)
/// </summary> /// </summary>
@ -8,11 +10,9 @@ public class RetHandler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the RetHandler class /// Initializes a new instance of the RetHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public RetHandler(InstructionDecoder decoder)
public RetHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,11 +34,11 @@ public class RetHandler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "ret"; instruction.Type = InstructionType.Ret;
// No operands for RET // No operands for RET
instruction.Operands = string.Empty; instruction.StructuredOperands = [];
return true; return true;
} }

View File

@ -1,5 +1,7 @@
namespace X86Disassembler.X86.Handlers.Ret; namespace X86Disassembler.X86.Handlers.Ret;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for RET instruction with immediate operand (0xC2) /// Handler for RET instruction with immediate operand (0xC2)
/// </summary> /// </summary>
@ -8,11 +10,9 @@ public class RetImmHandler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the RetImmHandler class /// Initializes a new instance of the RetImmHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public RetImmHandler(InstructionDecoder decoder)
public RetImmHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,8 +34,8 @@ public class RetImmHandler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "ret"; instruction.Type = InstructionType.Ret;
if (!Decoder.CanReadUShort()) if (!Decoder.CanReadUShort())
{ {
@ -45,8 +45,14 @@ public class RetImmHandler : InstructionHandler
// Read the immediate value // Read the immediate value
ushort imm16 = Decoder.ReadUInt16(); ushort imm16 = Decoder.ReadUInt16();
// Set the operands // Create the immediate operand
instruction.Operands = $"0x{imm16:X4}"; var immOperand = OperandFactory.CreateImmediateOperand(imm16, 16);
// Set the structured operands
instruction.StructuredOperands =
[
immOperand
];
return true; return true;
} }

View File

@ -1,5 +1,7 @@
namespace X86Disassembler.X86.Handlers.Sbb; namespace X86Disassembler.X86.Handlers.Sbb;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for SBB r/m32, imm32 instruction (0x81 /3) /// Handler for SBB r/m32, imm32 instruction (0x81 /3)
/// </summary> /// </summary>
@ -8,11 +10,9 @@ public class SbbImmFromRm32Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the SbbImmFromRm32Handler class /// Initializes a new instance of the SbbImmFromRm32Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public SbbImmFromRm32Handler(InstructionDecoder decoder)
public SbbImmFromRm32Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -30,7 +30,7 @@ public class SbbImmFromRm32Handler : InstructionHandler
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
return false; return false;
byte modRM = CodeBuffer[Decoder.GetPosition()]; byte modRM = Decoder.PeakByte();
byte reg = (byte) ((modRM & 0x38) >> 3); byte reg = (byte) ((modRM & 0x38) >> 3);
return reg == 3; // 3 = SBB return reg == 3; // 3 = SBB
@ -44,8 +44,8 @@ public class SbbImmFromRm32Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "sbb"; instruction.Type = InstructionType.Sbb;
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
@ -63,13 +63,16 @@ public class SbbImmFromRm32Handler : InstructionHandler
// Read the immediate value in little-endian format // Read the immediate value in little-endian format
var imm32 = Decoder.ReadUInt32(); var imm32 = Decoder.ReadUInt32();
// Format the immediate value as expected by the tests (0x12345678) // Create the immediate operand
// Note: The bytes are reversed to match the expected format in the tests var immOperand = OperandFactory.CreateImmediateOperand(imm32);
string immStr = $"0x{imm32:X8}";
// Set the structured operands
// Set the operands instruction.StructuredOperands =
instruction.Operands = $"{destOperand}, {immStr}"; [
destOperand,
immOperand
];
return true; return true;
} }

View File

@ -1,5 +1,7 @@
namespace X86Disassembler.X86.Handlers.Sbb; namespace X86Disassembler.X86.Handlers.Sbb;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for SBB r/m32, imm8 (sign-extended) instruction (0x83 /3) /// Handler for SBB r/m32, imm8 (sign-extended) instruction (0x83 /3)
/// </summary> /// </summary>
@ -8,11 +10,9 @@ public class SbbImmFromRm32SignExtendedHandler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the SbbImmFromRm32SignExtendedHandler class /// Initializes a new instance of the SbbImmFromRm32SignExtendedHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public SbbImmFromRm32SignExtendedHandler(InstructionDecoder decoder)
public SbbImmFromRm32SignExtendedHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -30,7 +30,7 @@ public class SbbImmFromRm32SignExtendedHandler : InstructionHandler
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
return false; return false;
byte modRM = CodeBuffer[Decoder.GetPosition()]; byte modRM = Decoder.PeakByte();
byte reg = (byte) ((modRM & 0x38) >> 3); byte reg = (byte) ((modRM & 0x38) >> 3);
return reg == 3; // 3 = SBB return reg == 3; // 3 = SBB
@ -44,8 +44,8 @@ public class SbbImmFromRm32SignExtendedHandler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "sbb"; instruction.Type = InstructionType.Sbb;
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
@ -62,10 +62,17 @@ public class SbbImmFromRm32SignExtendedHandler : InstructionHandler
} }
// Sign-extend to 32 bits // Sign-extend to 32 bits
int imm32 = (sbyte) Decoder.ReadByte(); sbyte imm8 = (sbyte) Decoder.ReadByte();
// Set the operands // Create the immediate operand with sign extension
instruction.Operands = $"{destOperand}, 0x{imm32:X8}"; var immOperand = OperandFactory.CreateImmediateOperand(imm8);
// Set the structured operands
instruction.StructuredOperands =
[
destOperand,
immOperand
];
return true; return true;
} }

View File

@ -1,35 +1,59 @@
namespace X86Disassembler.X86.Handlers.String; namespace X86Disassembler.X86.Handlers.String;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for string instructions (MOVS, STOS, LODS, SCAS) with and without REP/REPNE prefixes /// Handler for string instructions (MOVS, STOS, LODS, SCAS) with and without REP/REPNE prefixes
/// </summary> /// </summary>
public class StringInstructionHandler : InstructionHandler public class StringInstructionHandler : InstructionHandler
{ {
// Dictionary mapping opcodes to their mnemonics and operands // Dictionary mapping opcodes to their instruction types and operand factories
private static readonly Dictionary<byte, (string Mnemonic, string Operands)> StringInstructions = new() private static readonly Dictionary<byte, (InstructionType Type, Func<Operand[]> CreateOperands)> StringInstructions = new()
{ {
{ 0xA4, ("movs", "byte ptr [edi], byte ptr [esi]") }, // MOVSB { 0xA4, (InstructionType.MovsB, () => new Operand[] {
{ 0xA5, ("movs", "dword ptr [edi], dword ptr [esi]") }, // MOVSD OperandFactory.CreateDirectMemoryOperand(0, 8, "edi"),
{ 0xAA, ("stos", "byte ptr [edi], al") }, // STOSB OperandFactory.CreateDirectMemoryOperand(0, 8, "esi")
{ 0xAB, ("stos", "dword ptr [edi], eax") }, // STOSD }) }, // MOVSB
{ 0xAC, ("lods", "al, byte ptr [esi]") }, // LODSB { 0xA5, (InstructionType.MovsD, () => new Operand[] {
{ 0xAD, ("lods", "eax, dword ptr [esi]") }, // LODSD OperandFactory.CreateDirectMemoryOperand(0, 32, "edi"),
{ 0xAE, ("scas", "al, byte ptr [edi]") }, // SCASB OperandFactory.CreateDirectMemoryOperand(0, 32, "esi")
{ 0xAF, ("scas", "eax, dword ptr [edi]") } // SCASD }) }, // MOVSD
{ 0xAA, (InstructionType.StosB, () => new Operand[] {
OperandFactory.CreateDirectMemoryOperand(0, 8, "edi"),
OperandFactory.CreateRegisterOperand(RegisterIndex.A, 8)
}) }, // STOSB
{ 0xAB, (InstructionType.StosD, () => new Operand[] {
OperandFactory.CreateDirectMemoryOperand(0, 32, "edi"),
OperandFactory.CreateRegisterOperand(RegisterIndex.A, 32)
}) }, // STOSD
{ 0xAC, (InstructionType.LodsB, () => new Operand[] {
OperandFactory.CreateRegisterOperand(RegisterIndex.A, 8),
OperandFactory.CreateDirectMemoryOperand(0, 8, "esi")
}) }, // LODSB
{ 0xAD, (InstructionType.LodsD, () => new Operand[] {
OperandFactory.CreateRegisterOperand(RegisterIndex.A, 32),
OperandFactory.CreateDirectMemoryOperand(0, 32, "esi")
}) }, // LODSD
{ 0xAE, (InstructionType.ScasB, () => new Operand[] {
OperandFactory.CreateRegisterOperand(RegisterIndex.A, 8),
OperandFactory.CreateDirectMemoryOperand(0, 8, "edi")
}) }, // SCASB
{ 0xAF, (InstructionType.ScasD, () => new Operand[] {
OperandFactory.CreateRegisterOperand(RegisterIndex.A, 32),
OperandFactory.CreateDirectMemoryOperand(0, 32, "edi")
}) } // SCASD
}; };
// REP/REPNE prefix opcodes // REP/REPNE prefix opcodes
private const byte REP_PREFIX = 0xF3; private const byte REP_PREFIX = 0xF3;
private const byte REPNE_PREFIX = 0xF2; private const byte REPNE_PREFIX = 0xF2;
/// <summary> /// <summary>
/// Initializes a new instance of the StringInstructionHandler class /// Initializes a new instance of the StringInstructionHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public StringInstructionHandler(InstructionDecoder decoder)
public StringInstructionHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -57,7 +81,7 @@ public class StringInstructionHandler : InstructionHandler
return false; return false;
} }
byte nextByte = CodeBuffer[Decoder.GetPosition()]; byte nextByte = Decoder.PeakByte();
return StringInstructions.ContainsKey(nextByte); return StringInstructions.ContainsKey(nextByte);
} }
@ -71,16 +95,12 @@ public class StringInstructionHandler : InstructionHandler
{ {
// Check if this is a REP/REPNE prefix // Check if this is a REP/REPNE prefix
bool hasRepPrefix = opcode == REP_PREFIX || opcode == REPNE_PREFIX; bool hasRepPrefix = opcode == REP_PREFIX || opcode == REPNE_PREFIX;
string prefixString = "";
// If this is a REP/REPNE prefix, get the actual string instruction opcode // If this is a REP/REPNE prefix, get the actual string instruction opcode
byte stringOpcode = opcode; byte stringOpcode = opcode;
if (hasRepPrefix) if (hasRepPrefix)
{ {
// Set the prefix string based on the prefix opcode
prefixString = opcode == REP_PREFIX ? "rep " : "repne ";
// Read the next byte (the actual string instruction opcode) // Read the next byte (the actual string instruction opcode)
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
@ -95,14 +115,14 @@ public class StringInstructionHandler : InstructionHandler
} }
} }
// Get the mnemonic and operands for the string instruction // Get the instruction type and operands for the string instruction
if (StringInstructions.TryGetValue(stringOpcode, out var instructionInfo)) if (StringInstructions.TryGetValue(stringOpcode, out var instructionInfo))
{ {
// Set the mnemonic with the prefix if present // Set the instruction type
instruction.Mnemonic = prefixString + instructionInfo.Mnemonic; instruction.Type = instructionInfo.Type;
// Set the operands // Create and set the structured operands
instruction.Operands = instructionInfo.Operands; instruction.StructuredOperands = instructionInfo.CreateOperands().ToList();
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Sub; namespace X86Disassembler.X86.Handlers.Sub;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class SubAlImm8Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the SubAlImm8Handler class /// Initializes a new instance of the SubAlImm8Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public SubAlImm8Handler(InstructionDecoder decoder)
public SubAlImm8Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -42,9 +42,21 @@ public class SubAlImm8Handler : InstructionHandler
// Read the immediate byte // Read the immediate byte
byte imm8 = Decoder.ReadByte(); byte imm8 = Decoder.ReadByte();
// Set the instruction information // Set the instruction type
instruction.Mnemonic = "sub"; instruction.Type = InstructionType.Sub;
instruction.Operands = $"al, 0x{imm8:X2}";
// Create the destination register operand (AL)
var destinationOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.A, 8);
// Create the source immediate operand
var sourceOperand = OperandFactory.CreateImmediateOperand(imm8, 8);
// Set the structured operands
instruction.StructuredOperands =
[
destinationOperand,
sourceOperand
];
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Sub; namespace X86Disassembler.X86.Handlers.Sub;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class SubAxImm16Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the SubAxImm16Handler class /// Initializes a new instance of the SubAxImm16Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public SubAxImm16Handler(InstructionDecoder decoder)
public SubAxImm16Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -35,8 +35,8 @@ public class SubAxImm16Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "sub"; instruction.Type = InstructionType.Sub;
if (!Decoder.CanReadUShort()) if (!Decoder.CanReadUShort())
{ {
@ -45,9 +45,19 @@ public class SubAxImm16Handler : InstructionHandler
// Read the immediate value (16-bit) // Read the immediate value (16-bit)
var immediate = Decoder.ReadUInt16(); var immediate = Decoder.ReadUInt16();
// Set the operands (note: we use "eax" instead of "ax" to match the disassembler's output) // Create the destination register operand (AX)
instruction.Operands = $"eax, 0x{immediate:X4}"; var destinationOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.A, 16);
// Create the source immediate operand
var sourceOperand = OperandFactory.CreateImmediateOperand(immediate, 16);
// Set the structured operands
instruction.StructuredOperands =
[
destinationOperand,
sourceOperand
];
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Sub; namespace X86Disassembler.X86.Handlers.Sub;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class SubImmFromRm16Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the SubImmFromRm16Handler class /// Initializes a new instance of the SubImmFromRm16Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public SubImmFromRm16Handler(InstructionDecoder decoder)
public SubImmFromRm16Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -36,7 +36,7 @@ public class SubImmFromRm16Handler : InstructionHandler
} }
// Check if the reg field is 5 (SUB) // Check if the reg field is 5 (SUB)
byte modRM = CodeBuffer[Decoder.GetPosition()]; byte modRM = Decoder.PeakByte();
byte reg = (byte)((modRM & 0x38) >> 3); byte reg = (byte)((modRM & 0x38) >> 3);
return reg == 5; // 5 = SUB return reg == 5; // 5 = SUB
@ -50,8 +50,8 @@ public class SubImmFromRm16Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "sub"; instruction.Type = InstructionType.Sub;
// Check if we have enough bytes for the ModR/M byte // Check if we have enough bytes for the ModR/M byte
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
@ -59,15 +59,14 @@ public class SubImmFromRm16Handler : InstructionHandler
return false; return false;
} }
// Extract the fields from the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM(); // For SUB r/m16, imm16 (0x81 /5 with 0x66 prefix):
// - The r/m field with mod specifies the destination operand (register or memory)
// - The immediate value is the source operand
var (mod, reg, rm, destinationOperand) = ModRMDecoder.ReadModRM();
// For memory operands, replace "dword" with "word" // Adjust the operand size to 16-bit
string destination = destOperand; destinationOperand.Size = 16;
if (mod != 3) // Memory operand
{
destination = destOperand.Replace("dword", "word");
}
// Check if we have enough bytes for the immediate value // Check if we have enough bytes for the immediate value
if (!Decoder.CanReadUShort()) if (!Decoder.CanReadUShort())
@ -78,8 +77,15 @@ public class SubImmFromRm16Handler : InstructionHandler
// Read the immediate value (16-bit) // Read the immediate value (16-bit)
ushort immediate = Decoder.ReadUInt16(); ushort immediate = Decoder.ReadUInt16();
// Set the operands // Create the source immediate operand
instruction.Operands = $"{destination}, 0x{immediate:X4}"; var sourceOperand = OperandFactory.CreateImmediateOperand(immediate, 16);
// Set the structured operands
instruction.StructuredOperands =
[
destinationOperand,
sourceOperand
];
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Sub; namespace X86Disassembler.X86.Handlers.Sub;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class SubImmFromRm16SignExtendedHandler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the SubImmFromRm16SignExtendedHandler class /// Initializes a new instance of the SubImmFromRm16SignExtendedHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public SubImmFromRm16SignExtendedHandler(InstructionDecoder decoder)
public SubImmFromRm16SignExtendedHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -36,7 +36,7 @@ public class SubImmFromRm16SignExtendedHandler : InstructionHandler
} }
// Check if the reg field is 5 (SUB) // Check if the reg field is 5 (SUB)
byte modRM = CodeBuffer[Decoder.GetPosition()]; byte modRM = Decoder.PeakByte();
byte reg = (byte)((modRM & 0x38) >> 3); byte reg = (byte)((modRM & 0x38) >> 3);
return reg == 5; // 5 = SUB return reg == 5; // 5 = SUB
@ -50,8 +50,8 @@ public class SubImmFromRm16SignExtendedHandler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "sub"; instruction.Type = InstructionType.Sub;
// Check if we have enough bytes for the ModR/M byte // Check if we have enough bytes for the ModR/M byte
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
@ -59,15 +59,14 @@ public class SubImmFromRm16SignExtendedHandler : InstructionHandler
return false; return false;
} }
// Extract the fields from the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM(); // For SUB r/m16, imm8 (0x83 /5 with 0x66 prefix and sign extension):
// - The r/m field with mod specifies the destination operand (register or memory)
// - The immediate value is the source operand (sign-extended from 8 to 16 bits)
var (mod, reg, rm, destinationOperand) = ModRMDecoder.ReadModRM();
// For memory operands, replace "dword" with "word" // Adjust the operand size to 16-bit
string destination = destOperand; destinationOperand.Size = 16;
if (mod != 3) // Memory operand
{
destination = destOperand.Replace("dword", "word");
}
// Check if we have enough bytes for the immediate value // Check if we have enough bytes for the immediate value
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
@ -75,11 +74,18 @@ public class SubImmFromRm16SignExtendedHandler : InstructionHandler
return false; return false;
} }
// Read the immediate value (8-bit) // Read the immediate value as a signed byte and automatically sign-extend it to short
byte immediate = Decoder.ReadByte(); short imm16 = (sbyte)Decoder.ReadByte();
// Set the operands // Create the source immediate operand with the sign-extended value
instruction.Operands = $"{destination}, 0x{immediate:X2}"; var sourceOperand = OperandFactory.CreateImmediateOperand(imm16, 16);
// Set the structured operands
instruction.StructuredOperands =
[
destinationOperand,
sourceOperand
];
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Sub; namespace X86Disassembler.X86.Handlers.Sub;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class SubImmFromRm32Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the SubImmFromRm32Handler class /// Initializes a new instance of the SubImmFromRm32Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public SubImmFromRm32Handler(InstructionDecoder decoder)
public SubImmFromRm32Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -30,7 +30,7 @@ public class SubImmFromRm32Handler : InstructionHandler
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
return false; return false;
byte modRM = CodeBuffer[Decoder.GetPosition()]; byte modRM = Decoder.PeakByte();
byte reg = (byte) ((modRM & 0x38) >> 3); byte reg = (byte) ((modRM & 0x38) >> 3);
return reg == 5; // 5 = SUB return reg == 5; // 5 = SUB
@ -44,8 +44,8 @@ public class SubImmFromRm32Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "sub"; instruction.Type = InstructionType.Sub;
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
@ -53,7 +53,7 @@ public class SubImmFromRm32Handler : InstructionHandler
} }
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM(); var (mod, reg, rm, destinationOperand) = ModRMDecoder.ReadModRM();
// Read the immediate value // Read the immediate value
if (!Decoder.CanReadUInt()) if (!Decoder.CanReadUInt())
@ -63,12 +63,16 @@ public class SubImmFromRm32Handler : InstructionHandler
// Read the immediate value in little-endian format // Read the immediate value in little-endian format
var imm = Decoder.ReadUInt32(); var imm = Decoder.ReadUInt32();
// Format the immediate value // Create the source immediate operand
string immStr = $"0x{imm:X8}"; var sourceOperand = OperandFactory.CreateImmediateOperand(imm, 32);
// Set the operands // Set the structured operands
instruction.Operands = $"{destOperand}, {immStr}"; instruction.StructuredOperands =
[
destinationOperand,
sourceOperand
];
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Sub; namespace X86Disassembler.X86.Handlers.Sub;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class SubImmFromRm32SignExtendedHandler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the SubImmFromRm32SignExtendedHandler class /// Initializes a new instance of the SubImmFromRm32SignExtendedHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public SubImmFromRm32SignExtendedHandler(InstructionDecoder decoder)
public SubImmFromRm32SignExtendedHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -30,7 +30,7 @@ public class SubImmFromRm32SignExtendedHandler : InstructionHandler
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
return false; return false;
byte modRM = CodeBuffer[Decoder.GetPosition()]; byte modRM = Decoder.PeakByte();
byte reg = (byte) ((modRM & 0x38) >> 3); byte reg = (byte) ((modRM & 0x38) >> 3);
return reg == 5; // 5 = SUB return reg == 5; // 5 = SUB
@ -44,8 +44,8 @@ public class SubImmFromRm32SignExtendedHandler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "sub"; instruction.Type = InstructionType.Sub;
// Check if we have enough bytes for the ModR/M byte // Check if we have enough bytes for the ModR/M byte
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
@ -54,7 +54,7 @@ public class SubImmFromRm32SignExtendedHandler : InstructionHandler
} }
// Extract the fields from the ModR/M byte // Extract the fields from the ModR/M byte
var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM(); var (mod, reg, rm, destinationOperand) = ModRMDecoder.ReadModRM();
// Check if we have enough bytes for the immediate value // Check if we have enough bytes for the immediate value
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
@ -65,14 +65,15 @@ public class SubImmFromRm32SignExtendedHandler : InstructionHandler
// Read the immediate value as a signed byte and sign-extend it to 32 bits // Read the immediate value as a signed byte and sign-extend it to 32 bits
int imm32 = (sbyte) Decoder.ReadByte(); int imm32 = (sbyte) Decoder.ReadByte();
// Format the immediate value - use a consistent approach for all operands // Create the source immediate operand with the sign-extended value
// For negative values, show the full 32-bit representation var sourceOperand = OperandFactory.CreateImmediateOperand(imm32, 32);
string immStr = imm32 < 0
? $"0x{(uint)imm32:X8}" // Set the structured operands
: $"0x{(byte)imm32:X2}"; instruction.StructuredOperands =
[
// Set the operands destinationOperand,
instruction.Operands = $"{destOperand}, {immStr}"; sourceOperand
];
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Sub; namespace X86Disassembler.X86.Handlers.Sub;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class SubImmFromRm8Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the SubImmFromRm8Handler class /// Initializes a new instance of the SubImmFromRm8Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public SubImmFromRm8Handler(InstructionDecoder decoder)
public SubImmFromRm8Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -30,7 +30,7 @@ public class SubImmFromRm8Handler : InstructionHandler
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
return false; return false;
byte modRM = CodeBuffer[Decoder.GetPosition()]; byte modRM = Decoder.PeakByte();
byte reg = (byte) ((modRM & 0x38) >> 3); byte reg = (byte) ((modRM & 0x38) >> 3);
return reg == 5; // 5 = SUB return reg == 5; // 5 = SUB
@ -44,11 +44,14 @@ public class SubImmFromRm8Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "sub"; instruction.Type = InstructionType.Sub;
// Extract the fields from the ModR/M byte // Extract the fields from the ModR/M byte
var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM(); var (mod, reg, rm, destinationOperand) = ModRMDecoder.ReadModRM();
// Ensure the destination operand has the correct size (8-bit)
destinationOperand.Size = 8;
// Read the immediate byte // Read the immediate byte
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
@ -57,19 +60,16 @@ public class SubImmFromRm8Handler : InstructionHandler
} }
byte imm8 = Decoder.ReadByte(); byte imm8 = Decoder.ReadByte();
// Set the instruction information // Create the source immediate operand
// For mod == 3, the operand is a register var sourceOperand = OperandFactory.CreateImmediateOperand(imm8, 8);
if (mod == 3)
{ // Set the structured operands
string rmRegName = ModRMDecoder.GetRegisterName(rm, 8); instruction.StructuredOperands =
instruction.Operands = $"{rmRegName}, 0x{imm8:X2}"; [
} destinationOperand,
else // Memory operand sourceOperand
{ ];
// Get the memory operand string
instruction.Operands = $"byte ptr {destOperand}, 0x{imm8:X2}";
}
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Sub; namespace X86Disassembler.X86.Handlers.Sub;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class SubR16Rm16Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the SubR16Rm16Handler class /// Initializes a new instance of the SubR16Rm16Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public SubR16Rm16Handler(InstructionDecoder decoder)
public SubR16Rm16Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -35,8 +35,8 @@ public class SubR16Rm16Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "sub"; instruction.Type = InstructionType.Sub;
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
@ -44,24 +44,20 @@ public class SubR16Rm16Handler : InstructionHandler
} }
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM(); var (mod, reg, rm, sourceOperand) = ModRMDecoder.ReadModRM();
// Get register name (16-bit) // Ensure the source operand has the correct size (16-bit)
string regName = ModRMDecoder.GetRegisterName(reg, 16); sourceOperand.Size = 16;
// For mod == 3, both operands are registers // Create the destination register operand (16-bit)
if (mod == 3) var destinationOperand = OperandFactory.CreateRegisterOperand((RegisterIndex)reg, 16);
{
string rmRegName = ModRMDecoder.GetRegisterName(rm, 16); // Set the structured operands
instruction.Operands = $"{regName}, {rmRegName}"; instruction.StructuredOperands =
} [
else // Memory operand destinationOperand,
{ sourceOperand
// Replace "dword" with "word" in the memory operand ];
destOperand = destOperand.Replace("dword", "word");
instruction.Operands = $"{regName}, {destOperand}";
}
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Sub; namespace X86Disassembler.X86.Handlers.Sub;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class SubR32Rm32Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the SubR32Rm32Handler class /// Initializes a new instance of the SubR32Rm32Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public SubR32Rm32Handler(InstructionDecoder decoder)
public SubR32Rm32Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -40,24 +40,20 @@ public class SubR32Rm32Handler : InstructionHandler
} }
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM(); var (mod, reg, rm, sourceOperand) = ModRMDecoder.ReadModRM();
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "sub"; instruction.Type = InstructionType.Sub;
// Get the register name // Create the destination register operand (32-bit)
string regName = ModRMDecoder.GetRegisterName(reg, 32); var destinationOperand = OperandFactory.CreateRegisterOperand((RegisterIndex)reg, 32);
// For memory operands, set the operand // Set the structured operands
if (mod != 3) // Memory operand instruction.StructuredOperands =
{ [
instruction.Operands = $"{regName}, {destOperand}"; destinationOperand,
} sourceOperand
else // Register operand ];
{
string rmName = ModRMDecoder.GetRegisterName(rm, 32);
instruction.Operands = $"{regName}, {rmName}";
}
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Sub; namespace X86Disassembler.X86.Handlers.Sub;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class SubR8Rm8Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the SubR8Rm8Handler class /// Initializes a new instance of the SubR8Rm8Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public SubR8Rm8Handler(InstructionDecoder decoder)
public SubR8Rm8Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,8 +34,8 @@ public class SubR8Rm8Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "sub"; instruction.Type = InstructionType.Sub;
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
@ -43,21 +43,20 @@ public class SubR8Rm8Handler : InstructionHandler
} }
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM(); var (mod, reg, rm, sourceOperand) = ModRMDecoder.ReadModRM();
// Get register name // Ensure the source operand has the correct size (8-bit)
string regName = ModRMDecoder.GetRegisterName(reg, 8); sourceOperand.Size = 8;
// For mod == 3, both operands are registers // Create the destination register operand
if (mod == 3) var destinationOperand = OperandFactory.CreateRegisterOperand((RegisterIndex)reg, 8);
{
string rmRegName = ModRMDecoder.GetRegisterName(rm, 8); // Set the structured operands
instruction.Operands = $"{regName}, {rmRegName}"; instruction.StructuredOperands =
} [
else // Memory operand destinationOperand,
{ sourceOperand
instruction.Operands = $"{regName}, byte ptr {destOperand}"; ];
}
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Sub; namespace X86Disassembler.X86.Handlers.Sub;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class SubRm16R16Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the SubRm16R16Handler class /// Initializes a new instance of the SubRm16R16Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public SubRm16R16Handler(InstructionDecoder decoder)
public SubRm16R16Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -35,8 +35,8 @@ public class SubRm16R16Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "sub"; instruction.Type = InstructionType.Sub;
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
@ -44,23 +44,20 @@ public class SubRm16R16Handler : InstructionHandler
} }
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM(); var (mod, reg, rm, destinationOperand) = ModRMDecoder.ReadModRM();
// Get register name (16-bit) // Ensure the destination operand has the correct size (16-bit)
string regName = ModRMDecoder.GetRegisterName(reg, 16); destinationOperand.Size = 16;
// For mod == 3, both operands are registers // Create the source register operand (16-bit)
if (mod == 3) var sourceOperand = OperandFactory.CreateRegisterOperand((RegisterIndex)reg, 16);
{
string rmRegName = ModRMDecoder.GetRegisterName(rm, 16); // Set the structured operands
instruction.Operands = $"{rmRegName}, {regName}"; instruction.StructuredOperands =
} [
else // Memory operand destinationOperand,
{ sourceOperand
destOperand = destOperand.Replace("dword", "word"); ];
instruction.Operands = $"{destOperand}, {regName}";
}
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Sub; namespace X86Disassembler.X86.Handlers.Sub;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class SubRm32R32Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the SubRm32R32Handler class /// Initializes a new instance of the SubRm32R32Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public SubRm32R32Handler(InstructionDecoder decoder)
public SubRm32R32Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -39,27 +39,21 @@ public class SubRm32R32Handler : InstructionHandler
return false; return false;
} }
// Set the instruction type
instruction.Type = InstructionType.Sub;
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, destinationOperand) = ModRMDecoder.ReadModRM();
// Extract the fields from the ModR/M byte
var (mod, reg, rm, operand) = ModRMDecoder.ReadModRM(); // Create the source register operand (32-bit)
var sourceOperand = OperandFactory.CreateRegisterOperand((RegisterIndex)reg, 32);
// Set the mnemonic
instruction.Mnemonic = "sub"; // Set the structured operands
instruction.StructuredOperands =
// Get the register name [
string regName = ModRMDecoder.GetRegisterName(reg, 32); destinationOperand,
sourceOperand
// For memory operands, set the operand ];
if (mod != 3) // Memory operand
{
instruction.Operands = $"{operand}, {regName}";
}
else // Register operand
{
string rmName = ModRMDecoder.GetRegisterName(rm, 32);
instruction.Operands = $"{rmName}, {regName}";
}
return true; return true;
} }

View File

@ -1,3 +1,5 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Sub; namespace X86Disassembler.X86.Handlers.Sub;
/// <summary> /// <summary>
@ -8,11 +10,9 @@ public class SubRm8R8Handler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the SubRm8R8Handler class /// Initializes a new instance of the SubRm8R8Handler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public SubRm8R8Handler(InstructionDecoder decoder)
public SubRm8R8Handler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,8 +34,8 @@ public class SubRm8R8Handler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "sub"; instruction.Type = InstructionType.Sub;
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
@ -43,21 +43,20 @@ public class SubRm8R8Handler : InstructionHandler
} }
// Read the ModR/M byte // Read the ModR/M byte
var (mod, reg, rm, destOperand) = ModRMDecoder.ReadModRM(); var (mod, reg, rm, destinationOperand) = ModRMDecoder.ReadModRM();
// Get register name // Ensure the destination operand has the correct size (8-bit)
string regName = ModRMDecoder.GetRegisterName(reg, 8); destinationOperand.Size = 8;
// For mod == 3, both operands are registers // Create the source register operand (8-bit)
if (mod == 3) var sourceOperand = OperandFactory.CreateRegisterOperand((RegisterIndex)reg, 8);
{
string rmRegName = ModRMDecoder.GetRegisterName(rm, 8); // Set the structured operands
instruction.Operands = $"{rmRegName}, {regName}"; instruction.StructuredOperands =
} [
else // Memory operand destinationOperand,
{ sourceOperand
instruction.Operands = $"byte ptr {destOperand}, {regName}"; ];
}
return true; return true;
} }

View File

@ -1,5 +1,7 @@
namespace X86Disassembler.X86.Handlers.Test; namespace X86Disassembler.X86.Handlers.Test;
using X86Disassembler.X86.Operands;
/// <summary> /// <summary>
/// Handler for TEST AL, imm8 instruction (0xA8) /// Handler for TEST AL, imm8 instruction (0xA8)
/// </summary> /// </summary>
@ -8,11 +10,9 @@ public class TestAlImmHandler : InstructionHandler
/// <summary> /// <summary>
/// Initializes a new instance of the TestAlImmHandler class /// Initializes a new instance of the TestAlImmHandler class
/// </summary> /// </summary>
/// <param name="codeBuffer">The buffer containing the code to decode</param>
/// <param name="decoder">The instruction decoder that owns this handler</param> /// <param name="decoder">The instruction decoder that owns this handler</param>
/// <param name="length">The length of the buffer</param> public TestAlImmHandler(InstructionDecoder decoder)
public TestAlImmHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) : base(decoder)
: base(codeBuffer, decoder, length)
{ {
} }
@ -34,8 +34,8 @@ public class TestAlImmHandler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Set the mnemonic // Set the instruction type
instruction.Mnemonic = "test"; instruction.Type = InstructionType.Test;
if (!Decoder.CanReadByte()) if (!Decoder.CanReadByte())
{ {
@ -45,8 +45,18 @@ public class TestAlImmHandler : InstructionHandler
// Read the immediate value // Read the immediate value
byte imm8 = Decoder.ReadByte(); byte imm8 = Decoder.ReadByte();
// Set the operands // Create the register operand for AL
instruction.Operands = $"al, 0x{imm8:X2}"; var alOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.A, 8);
// Create the immediate operand
var immOperand = OperandFactory.CreateImmediateOperand(imm8, 8);
// Set the structured operands
instruction.StructuredOperands =
[
alOperand,
immOperand
];
return true; return true;
} }

Some files were not shown because too many files have changed in this diff Show More