diff --git a/X86Disassembler/X86/Disassembler.cs b/X86Disassembler/X86/Disassembler.cs
index a20e01b..0f3e70d 100644
--- a/X86Disassembler/X86/Disassembler.cs
+++ b/X86Disassembler/X86/Disassembler.cs
@@ -85,13 +85,16 @@ public class Disassembler
break;
}
- // If no special case applies, decode normally
+ // Store the position before decoding to handle prefixes properly
+ int startPosition = position;
+
+ // Decode the instruction
Instruction? instruction = decoder.DecodeInstruction();
if (instruction != null)
{
// Adjust the instruction address to include the base address
- instruction.Address += _baseAddress;
+ instruction.Address = _baseAddress + (uint)startPosition;
// Add the instruction to the list
instructions.Add(instruction);
@@ -103,7 +106,7 @@ public class Disassembler
Instruction dummyInstruction = new Instruction
{
- Address = _baseAddress + (uint) position,
+ Address = _baseAddress + (uint)position,
Type = InstructionType.Unknown,
StructuredOperands = [OperandFactory.CreateImmediateOperand(unknownByte, 8),]
};
diff --git a/X86Disassembler/X86/Handlers/Adc/AdcAccumulatorImmHandler.cs b/X86Disassembler/X86/Handlers/Adc/AdcAccumulatorImmHandler.cs
new file mode 100644
index 0000000..48dcc74
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Adc/AdcAccumulatorImmHandler.cs
@@ -0,0 +1,71 @@
+namespace X86Disassembler.X86.Handlers.Adc;
+
+using Operands;
+
+///
+/// Handler for ADC AX/EAX, imm16/32 instruction (opcode 0x15)
+///
+public class AdcAccumulatorImmHandler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the AdcAccumulatorImmHandler class
+ ///
+ /// The instruction decoder that owns this handler
+ public AdcAccumulatorImmHandler(InstructionDecoder decoder)
+ : base(decoder)
+ {
+ }
+
+ ///
+ /// Checks if this handler can decode the given opcode
+ ///
+ /// The opcode to check
+ /// True if this handler can decode the opcode
+ public override bool CanHandle(byte opcode)
+ {
+ // ADC AX/EAX, imm16/32 is encoded as 0x15
+ return opcode == 0x15;
+ }
+
+ ///
+ /// Decodes a ADC AX/EAX, imm16/32 instruction
+ ///
+ /// The opcode of the instruction
+ /// The instruction object to populate
+ /// True if the instruction was successfully decoded
+ public override bool Decode(byte opcode, Instruction instruction)
+ {
+ // Set the instruction type
+ instruction.Type = InstructionType.Adc;
+
+ // Determine operand size based on prefix
+ int operandSize = Decoder.HasOperandSizePrefix() ? 16 : 32;
+
+ // Check if we have enough bytes for the immediate value
+ if (operandSize == 16 && !Decoder.CanReadUShort())
+ {
+ return false;
+ }
+ else if (operandSize == 32 && !Decoder.CanReadUInt())
+ {
+ return false;
+ }
+
+ // Create the accumulator register operand (AX or EAX)
+ var accumulatorOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.A, operandSize);
+
+ // Read and create the immediate operand based on operand size
+ var immOperand = operandSize == 16
+ ? OperandFactory.CreateImmediateOperand(Decoder.ReadUInt16(), operandSize)
+ : OperandFactory.CreateImmediateOperand(Decoder.ReadUInt32(), operandSize);
+
+ // Set the structured operands
+ instruction.StructuredOperands =
+ [
+ accumulatorOperand,
+ immOperand
+ ];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Adc/AdcAlImmHandler.cs b/X86Disassembler/X86/Handlers/Adc/AdcAlImmHandler.cs
new file mode 100644
index 0000000..dd5ae19
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Adc/AdcAlImmHandler.cs
@@ -0,0 +1,64 @@
+using X86Disassembler.X86.Operands;
+
+namespace X86Disassembler.X86.Handlers.Adc;
+
+///
+/// Handler for ADC AL, imm8 instruction (0x14)
+///
+public class AdcAlImmHandler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the AdcAlImmHandler class
+ ///
+ /// The instruction decoder that owns this handler
+ public AdcAlImmHandler(InstructionDecoder decoder)
+ : base(decoder)
+ {
+ }
+
+ ///
+ /// Checks if this handler can decode the given opcode
+ ///
+ /// The opcode to check
+ /// True if this handler can decode the opcode
+ public override bool CanHandle(byte opcode)
+ {
+ return opcode == 0x14;
+ }
+
+ ///
+ /// Decodes an ADC AL, imm8 instruction
+ ///
+ /// The opcode of the instruction
+ /// The instruction object to populate
+ /// True if the instruction was successfully decoded
+ public override bool Decode(byte opcode, Instruction instruction)
+ {
+ // Set the instruction type
+ instruction.Type = InstructionType.Adc;
+
+ // Check if we have enough bytes for the immediate value
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Read the immediate byte
+ var imm8 = Decoder.ReadByte();
+
+ // Create the AL register operand
+ var destinationOperand = OperandFactory.CreateRegisterOperand8(RegisterIndex8.AL);
+
+ // Create the immediate operand
+ var sourceOperand = OperandFactory.CreateImmediateOperand(imm8);
+
+ // Set the structured operands
+ instruction.StructuredOperands =
+ [
+ destinationOperand,
+ sourceOperand
+ ];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Adc/AdcImmToRm16Handler.cs b/X86Disassembler/X86/Handlers/Adc/AdcImmToRm16Handler.cs
new file mode 100644
index 0000000..5696960
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Adc/AdcImmToRm16Handler.cs
@@ -0,0 +1,82 @@
+namespace X86Disassembler.X86.Handlers.Adc;
+
+using Operands;
+
+///
+/// Handler for ADC r/m16, imm16 instruction (0x81 /2 with 0x66 prefix)
+///
+public class AdcImmToRm16Handler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the AdcImmToRm16Handler class
+ ///
+ /// The instruction decoder that owns this handler
+ public AdcImmToRm16Handler(InstructionDecoder decoder)
+ : base(decoder)
+ {
+ }
+
+ ///
+ /// Checks if this handler can decode the given opcode
+ ///
+ /// The opcode to check
+ /// True if this handler can decode the opcode
+ public override bool CanHandle(byte opcode)
+ {
+ // ADC r/m16, imm16 is encoded as 0x81 /2 with 0x66 prefix
+ if (opcode != 0x81)
+ {
+ return false;
+ }
+
+ // Check if we have enough bytes to read the ModR/M byte
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Check if the reg field of the ModR/M byte is 2 (ADC)
+ var reg = ModRMDecoder.PeakModRMReg();
+
+ // Only handle when the operand size prefix is present
+ return reg == 2 && Decoder.HasOperandSizePrefix();
+ }
+
+ ///
+ /// Decodes a ADC r/m16, imm16 instruction
+ ///
+ /// The opcode of the instruction
+ /// The instruction object to populate
+ /// True if the instruction was successfully decoded
+ public override bool Decode(byte opcode, Instruction instruction)
+ {
+ // Set the instruction type
+ instruction.Type = InstructionType.Adc;
+
+ // Read the ModR/M byte, specifying that we're dealing with 16-bit operands
+ var (_, _, _, destinationOperand) = ModRMDecoder.ReadModRM16();
+
+ // Note: The operand size is already set to 16-bit by the ReadModRM16 method
+
+ // Check if we have enough bytes for the immediate value
+ if (!Decoder.CanReadUShort())
+ {
+ return false;
+ }
+
+ // Read the immediate value
+ ushort imm16 = Decoder.ReadUInt16();
+
+ // Create the immediate operand
+ var sourceOperand = OperandFactory.CreateImmediateOperand(imm16, 16);
+
+ // Set the structured operands
+ instruction.StructuredOperands =
+ [
+ destinationOperand,
+ sourceOperand
+ ];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Adc/AdcImmToRm16SignExtendedHandler.cs b/X86Disassembler/X86/Handlers/Adc/AdcImmToRm16SignExtendedHandler.cs
new file mode 100644
index 0000000..49b031f
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Adc/AdcImmToRm16SignExtendedHandler.cs
@@ -0,0 +1,84 @@
+namespace X86Disassembler.X86.Handlers.Adc;
+
+using Operands;
+
+///
+/// Handler for ADC r/m16, imm8 (sign-extended) instruction (0x83 /2 with 0x66 prefix)
+///
+public class AdcImmToRm16SignExtendedHandler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the AdcImmToRm16SignExtendedHandler class
+ ///
+ /// The instruction decoder that owns this handler
+ public AdcImmToRm16SignExtendedHandler(InstructionDecoder decoder)
+ : base(decoder)
+ {
+ }
+
+ ///
+ /// Checks if this handler can decode the given opcode
+ ///
+ /// The opcode to check
+ /// True if this handler can decode the opcode
+ public override bool CanHandle(byte opcode)
+ {
+ // ADC r/m16, imm8 (sign-extended) is encoded as 0x83 /2 with 0x66 prefix
+ if (opcode != 0x83)
+ {
+ return false;
+ }
+
+ // Check if we have enough bytes to read the ModR/M byte
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Check if the reg field of the ModR/M byte is 2 (ADC)
+ var reg = ModRMDecoder.PeakModRMReg();
+
+ // Only handle when the operand size prefix is present
+ return reg == 2 && Decoder.HasOperandSizePrefix();
+ }
+
+ ///
+ /// Decodes a ADC r/m16, imm8 (sign-extended) instruction
+ ///
+ /// The opcode of the instruction
+ /// The instruction object to populate
+ /// True if the instruction was successfully decoded
+ public override bool Decode(byte opcode, Instruction instruction)
+ {
+ // Set the instruction type
+ instruction.Type = InstructionType.Adc;
+
+ // For ADC r/m16, imm8 (sign-extended) (0x83 /2 with 0x66 prefix):
+ // - 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 (_, _, _, destinationOperand) = ModRMDecoder.ReadModRM16();
+
+ // Note: The operand size is already set to 16-bit by the ReadModRM16 method
+
+ // Check if we have enough bytes for the immediate value
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Read the immediate value (sign-extended from 8 to 16 bits)
+ short imm16 = (sbyte)Decoder.ReadByte();
+
+ // Create the immediate operand
+ var sourceOperand = OperandFactory.CreateImmediateOperand((ushort)imm16, 16);
+
+ // Set the structured operands
+ instruction.StructuredOperands =
+ [
+ destinationOperand,
+ sourceOperand
+ ];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Adc/AdcImmToRm8Handler.cs b/X86Disassembler/X86/Handlers/Adc/AdcImmToRm8Handler.cs
new file mode 100644
index 0000000..281bf82
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Adc/AdcImmToRm8Handler.cs
@@ -0,0 +1,81 @@
+namespace X86Disassembler.X86.Handlers.Adc;
+
+using Operands;
+
+///
+/// Handler for ADC r/m8, imm8 instruction (0x80 /2)
+///
+public class AdcImmToRm8Handler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the AdcImmToRm8Handler class
+ ///
+ /// The instruction decoder that owns this handler
+ public AdcImmToRm8Handler(InstructionDecoder decoder)
+ : base(decoder)
+ {
+ }
+
+ ///
+ /// Checks if this handler can decode the given opcode
+ ///
+ /// The opcode to check
+ /// True if this handler can decode the opcode
+ public override bool CanHandle(byte opcode)
+ {
+ if (opcode != 0x80)
+ return false;
+
+ // Check if the reg field of the ModR/M byte is 2 (ADC)
+ if (!Decoder.CanReadByte())
+ return false;
+
+ var reg = ModRMDecoder.PeakModRMReg();
+
+ return reg == 2; // 2 = ADC
+ }
+
+ ///
+ /// Decodes an ADC r/m8, imm8 instruction
+ ///
+ /// The opcode of the instruction
+ /// The instruction object to populate
+ /// True if the instruction was successfully decoded
+ public override bool Decode(byte opcode, Instruction instruction)
+ {
+ // Set the instruction type
+ instruction.Type = InstructionType.Adc;
+
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Read the ModR/M byte
+ // For ADC r/m8, imm8 (0x80 /2):
+ // - The r/m field with mod specifies the destination operand (register or memory)
+ // - The immediate value is the source operand
+ var (_, _, _, destinationOperand) = ModRMDecoder.ReadModRM8();
+
+ // Check if we have enough bytes for the immediate value
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Read the immediate value
+ byte imm8 = Decoder.ReadByte();
+
+ // Create the immediate operand
+ var sourceOperand = OperandFactory.CreateImmediateOperand(imm8, 8);
+
+ // Set the structured operands
+ instruction.StructuredOperands =
+ [
+ destinationOperand,
+ sourceOperand
+ ];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Adc/AdcR16Rm16Handler.cs b/X86Disassembler/X86/Handlers/Adc/AdcR16Rm16Handler.cs
new file mode 100644
index 0000000..fbacedd
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Adc/AdcR16Rm16Handler.cs
@@ -0,0 +1,72 @@
+namespace X86Disassembler.X86.Handlers.Adc;
+
+using Operands;
+
+///
+/// Handler for ADC r16, r/m16 instruction (0x13 with 0x66 prefix)
+///
+public class AdcR16Rm16Handler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the AdcR16Rm16Handler class
+ ///
+ /// The instruction decoder that owns this handler
+ public AdcR16Rm16Handler(InstructionDecoder decoder)
+ : base(decoder)
+ {
+ }
+
+ ///
+ /// Checks if this handler can decode the given opcode
+ ///
+ /// The opcode to check
+ /// True if this handler can decode the opcode
+ public override bool CanHandle(byte opcode)
+ {
+ // ADC r16, r/m16 is encoded as 0x13 with 0x66 prefix
+ if (opcode != 0x13)
+ {
+ return false;
+ }
+
+ // Only handle when the operand size prefix is present
+ return Decoder.HasOperandSizePrefix();
+ }
+
+ ///
+ /// Decodes a ADC r16, r/m16 instruction
+ ///
+ /// The opcode of the instruction
+ /// The instruction object to populate
+ /// True if the instruction was successfully decoded
+ public override bool Decode(byte opcode, Instruction instruction)
+ {
+ // Set the instruction type
+ instruction.Type = InstructionType.Adc;
+
+ // Check if we have enough bytes for the ModR/M byte
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // For ADC r16, r/m16 (0x13 with 0x66 prefix):
+ // - The reg field of the ModR/M byte specifies the destination register
+ // - The r/m field with mod specifies the source operand (register or memory)
+ var (_, reg, _, sourceOperand) = ModRMDecoder.ReadModRM16();
+
+ // Note: The operand size is already set to 16-bit by the ReadModRM16 method
+
+ // Create the destination register operand with 16-bit size
+ var destinationOperand = OperandFactory.CreateRegisterOperand(reg, 16);
+
+ // Set the structured operands
+ instruction.StructuredOperands =
+ [
+ destinationOperand,
+ sourceOperand
+ ];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Adc/AdcR32Rm32Handler.cs b/X86Disassembler/X86/Handlers/Adc/AdcR32Rm32Handler.cs
new file mode 100644
index 0000000..8759f7f
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Adc/AdcR32Rm32Handler.cs
@@ -0,0 +1,66 @@
+using X86Disassembler.X86.Operands;
+
+namespace X86Disassembler.X86.Handlers.Adc;
+
+///
+/// Handler for ADC r32, r/m32 instruction (0x13)
+///
+public class AdcR32Rm32Handler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the AdcR32Rm32Handler class
+ ///
+ /// The instruction decoder that owns this handler
+ public AdcR32Rm32Handler(InstructionDecoder decoder)
+ : base(decoder)
+ {
+ }
+
+ ///
+ /// Checks if this handler can decode the given opcode
+ ///
+ /// The opcode to check
+ /// True if this handler can decode the opcode
+ public override bool CanHandle(byte opcode)
+ {
+ // Only handle opcode 0x13 when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return opcode == 0x13 && !Decoder.HasOperandSizePrefix();
+ }
+
+ ///
+ /// Decodes an ADC r32, r/m32 instruction
+ ///
+ /// The opcode of the instruction
+ /// The instruction object to populate
+ /// True if the instruction was successfully decoded
+ public override bool Decode(byte opcode, Instruction instruction)
+ {
+ // Set the instruction type
+ instruction.Type = InstructionType.Adc;
+
+ // Check if we have enough bytes for the ModR/M byte
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Read the ModR/M byte
+ // For ADC r32, r/m32 (0x13):
+ // - The reg field specifies the destination register
+ // - The r/m field with mod specifies the source operand (register or memory)
+ var (_, reg, _, sourceOperand) = ModRMDecoder.ReadModRM();
+
+ // Create the register operand for the reg field
+ var destinationOperand = OperandFactory.CreateRegisterOperand(reg);
+
+ // Set the structured operands
+ instruction.StructuredOperands =
+ [
+ destinationOperand,
+ sourceOperand
+ ];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Adc/AdcR8Rm8Handler.cs b/X86Disassembler/X86/Handlers/Adc/AdcR8Rm8Handler.cs
new file mode 100644
index 0000000..0005c83
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Adc/AdcR8Rm8Handler.cs
@@ -0,0 +1,64 @@
+using X86Disassembler.X86.Operands;
+
+namespace X86Disassembler.X86.Handlers.Adc;
+
+///
+/// Handler for ADC r8, r/m8 instruction (0x12)
+///
+public class AdcR8Rm8Handler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the AdcR8Rm8Handler class
+ ///
+ /// The instruction decoder that owns this handler
+ public AdcR8Rm8Handler(InstructionDecoder decoder)
+ : base(decoder)
+ {
+ }
+
+ ///
+ /// Checks if this handler can decode the given opcode
+ ///
+ /// The opcode to check
+ /// True if this handler can decode the opcode
+ public override bool CanHandle(byte opcode)
+ {
+ return opcode == 0x12;
+ }
+
+ ///
+ /// Decodes an ADC r8, r/m8 instruction
+ ///
+ /// The opcode of the instruction
+ /// The instruction object to populate
+ /// True if the instruction was successfully decoded
+ public override bool Decode(byte opcode, Instruction instruction)
+ {
+ // Set the instruction type
+ instruction.Type = InstructionType.Adc;
+
+ // Check if we have enough bytes for the ModR/M byte
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Read the ModR/M byte
+ // For ADC r8, r/m8 (0x12):
+ // - The reg field specifies the destination register
+ // - The r/m field with mod specifies the source operand (register or memory)
+ var (_, reg, _, sourceOperand) = ModRMDecoder.ReadModRM8();
+
+ // Create the register operand for the reg field
+ var destinationOperand = OperandFactory.CreateRegisterOperand8(reg);
+
+ // Set the structured operands
+ instruction.StructuredOperands =
+ [
+ destinationOperand,
+ sourceOperand
+ ];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Adc/AdcRm16R16Handler.cs b/X86Disassembler/X86/Handlers/Adc/AdcRm16R16Handler.cs
new file mode 100644
index 0000000..7a361b9
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Adc/AdcRm16R16Handler.cs
@@ -0,0 +1,72 @@
+namespace X86Disassembler.X86.Handlers.Adc;
+
+using Operands;
+
+///
+/// Handler for ADC r/m16, r16 instruction (0x11 with 0x66 prefix)
+///
+public class AdcRm16R16Handler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the AdcRm16R16Handler class
+ ///
+ /// The instruction decoder that owns this handler
+ public AdcRm16R16Handler(InstructionDecoder decoder)
+ : base(decoder)
+ {
+ }
+
+ ///
+ /// Checks if this handler can decode the given opcode
+ ///
+ /// The opcode to check
+ /// True if this handler can decode the opcode
+ public override bool CanHandle(byte opcode)
+ {
+ // ADC r/m16, r16 is encoded as 0x11 with 0x66 prefix
+ if (opcode != 0x11)
+ {
+ return false;
+ }
+
+ // Only handle when the operand size prefix is present
+ return Decoder.HasOperandSizePrefix();
+ }
+
+ ///
+ /// Decodes a ADC r/m16, r16 instruction
+ ///
+ /// The opcode of the instruction
+ /// The instruction object to populate
+ /// True if the instruction was successfully decoded
+ public override bool Decode(byte opcode, Instruction instruction)
+ {
+ // Set the instruction type
+ instruction.Type = InstructionType.Adc;
+
+ // Check if we have enough bytes for the ModR/M byte
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // For ADC r/m16, r16 (0x11 with 0x66 prefix):
+ // - The reg field of the ModR/M byte specifies the source register
+ // - The r/m field with mod specifies the destination operand (register or memory)
+ var (_, reg, _, destinationOperand) = ModRMDecoder.ReadModRM16();
+
+ // Note: The operand size is already set to 16-bit by the ReadModRM16 method
+
+ // Create the source register operand with 16-bit size
+ var sourceOperand = OperandFactory.CreateRegisterOperand(reg, 16);
+
+ // Set the structured operands
+ instruction.StructuredOperands =
+ [
+ destinationOperand,
+ sourceOperand
+ ];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Adc/AdcRm32R32Handler.cs b/X86Disassembler/X86/Handlers/Adc/AdcRm32R32Handler.cs
new file mode 100644
index 0000000..077f57e
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Adc/AdcRm32R32Handler.cs
@@ -0,0 +1,66 @@
+using X86Disassembler.X86.Operands;
+
+namespace X86Disassembler.X86.Handlers.Adc;
+
+///
+/// Handler for ADC r/m32, r32 instruction (0x11)
+///
+public class AdcRm32R32Handler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the AdcRm32R32Handler class
+ ///
+ /// The instruction decoder that owns this handler
+ public AdcRm32R32Handler(InstructionDecoder decoder)
+ : base(decoder)
+ {
+ }
+
+ ///
+ /// Checks if this handler can decode the given opcode
+ ///
+ /// The opcode to check
+ /// True if this handler can decode the opcode
+ public override bool CanHandle(byte opcode)
+ {
+ // Only handle opcode 0x11 when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return opcode == 0x11 && !Decoder.HasOperandSizePrefix();
+ }
+
+ ///
+ /// Decodes an ADC r/m32, r32 instruction
+ ///
+ /// The opcode of the instruction
+ /// The instruction object to populate
+ /// True if the instruction was successfully decoded
+ public override bool Decode(byte opcode, Instruction instruction)
+ {
+ // Set the instruction type
+ instruction.Type = InstructionType.Adc;
+
+ // Check if we have enough bytes for the ModR/M byte
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Read the ModR/M byte
+ // For ADC r/m32, r32 (0x11):
+ // - The r/m field with mod specifies the destination operand (register or memory)
+ // - The reg field specifies the source register
+ var (_, reg, _, destinationOperand) = ModRMDecoder.ReadModRM();
+
+ // Create the register operand for the reg field
+ var sourceOperand = OperandFactory.CreateRegisterOperand(reg);
+
+ // Set the structured operands
+ instruction.StructuredOperands =
+ [
+ destinationOperand,
+ sourceOperand
+ ];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Adc/AdcRm8R8Handler.cs b/X86Disassembler/X86/Handlers/Adc/AdcRm8R8Handler.cs
new file mode 100644
index 0000000..e65ebc9
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Adc/AdcRm8R8Handler.cs
@@ -0,0 +1,64 @@
+using X86Disassembler.X86.Operands;
+
+namespace X86Disassembler.X86.Handlers.Adc;
+
+///
+/// Handler for ADC r/m8, r8 instruction (0x10)
+///
+public class AdcRm8R8Handler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the AdcRm8R8Handler class
+ ///
+ /// The instruction decoder that owns this handler
+ public AdcRm8R8Handler(InstructionDecoder decoder)
+ : base(decoder)
+ {
+ }
+
+ ///
+ /// Checks if this handler can decode the given opcode
+ ///
+ /// The opcode to check
+ /// True if this handler can decode the opcode
+ public override bool CanHandle(byte opcode)
+ {
+ return opcode == 0x10;
+ }
+
+ ///
+ /// Decodes an ADC r/m8, r8 instruction
+ ///
+ /// The opcode of the instruction
+ /// The instruction object to populate
+ /// True if the instruction was successfully decoded
+ public override bool Decode(byte opcode, Instruction instruction)
+ {
+ // Set the instruction type
+ instruction.Type = InstructionType.Adc;
+
+ // Check if we have enough bytes for the ModR/M byte
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Read the ModR/M byte
+ // For ADC r/m8, r8 (0x10):
+ // - The r/m field with mod specifies the destination operand (register or memory)
+ // - The reg field specifies the source register
+ var (_, reg, _, destinationOperand) = ModRMDecoder.ReadModRM8();
+
+ // Create the register operand for the reg field
+ var sourceOperand = OperandFactory.CreateRegisterOperand8(reg);
+
+ // Set the structured operands
+ instruction.StructuredOperands =
+ [
+ destinationOperand,
+ sourceOperand
+ ];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Add/AddR32Rm32Handler.cs b/X86Disassembler/X86/Handlers/Add/AddR32Rm32Handler.cs
index 9b90a31..93a2ebe 100644
--- a/X86Disassembler/X86/Handlers/Add/AddR32Rm32Handler.cs
+++ b/X86Disassembler/X86/Handlers/Add/AddR32Rm32Handler.cs
@@ -23,7 +23,9 @@ public class AddR32Rm32Handler : InstructionHandler
/// True if this handler can decode the opcode
public override bool CanHandle(byte opcode)
{
- return opcode == 0x03;
+ // Only handle opcode 0x03 when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return opcode == 0x03 && !Decoder.HasOperandSizePrefix();
}
///
diff --git a/X86Disassembler/X86/Handlers/Add/AddRm32R32Handler.cs b/X86Disassembler/X86/Handlers/Add/AddRm32R32Handler.cs
index 4b3274f..dafdbd7 100644
--- a/X86Disassembler/X86/Handlers/Add/AddRm32R32Handler.cs
+++ b/X86Disassembler/X86/Handlers/Add/AddRm32R32Handler.cs
@@ -23,7 +23,9 @@ public class AddRm32R32Handler : InstructionHandler
/// True if this handler can decode the opcode
public override bool CanHandle(byte opcode)
{
- return opcode == 0x01;
+ // Only handle opcode 0x01 when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return opcode == 0x01 && !Decoder.HasOperandSizePrefix();
}
///
diff --git a/X86Disassembler/X86/Handlers/And/AndMemRegHandler.cs b/X86Disassembler/X86/Handlers/And/AndMemRegHandler.cs
index c721469..e950995 100644
--- a/X86Disassembler/X86/Handlers/And/AndMemRegHandler.cs
+++ b/X86Disassembler/X86/Handlers/And/AndMemRegHandler.cs
@@ -23,7 +23,9 @@ public class AndMemRegHandler : InstructionHandler
/// True if this handler can decode the opcode
public override bool CanHandle(byte opcode)
{
- return opcode == 0x21;
+ // Only handle opcode 0x21 when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return opcode == 0x21 && !Decoder.HasOperandSizePrefix();
}
///
diff --git a/X86Disassembler/X86/Handlers/And/AndR32Rm32Handler.cs b/X86Disassembler/X86/Handlers/And/AndR32Rm32Handler.cs
index 017fc21..3ce53f7 100644
--- a/X86Disassembler/X86/Handlers/And/AndR32Rm32Handler.cs
+++ b/X86Disassembler/X86/Handlers/And/AndR32Rm32Handler.cs
@@ -23,7 +23,9 @@ public class AndR32Rm32Handler : InstructionHandler
/// True if this handler can decode the opcode
public override bool CanHandle(byte opcode)
{
- return opcode == 0x23;
+ // Only handle opcode 0x23 when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return opcode == 0x23 && !Decoder.HasOperandSizePrefix();
}
///
diff --git a/X86Disassembler/X86/Handlers/Bit/BsfR32Rm32Handler.cs b/X86Disassembler/X86/Handlers/Bit/BsfR32Rm32Handler.cs
new file mode 100644
index 0000000..c0d7f7b
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Bit/BsfR32Rm32Handler.cs
@@ -0,0 +1,84 @@
+namespace X86Disassembler.X86.Handlers.Bit;
+
+using Operands;
+
+///
+/// Handler for BSF r32, r/m32 instruction (0F BC)
+///
+public class BsfR32Rm32Handler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the BsfR32Rm32Handler class
+ ///
+ /// The instruction decoder that owns this handler
+ public BsfR32Rm32Handler(InstructionDecoder decoder)
+ : base(decoder)
+ {
+ }
+
+ ///
+ /// Checks if this handler can decode the given opcode
+ ///
+ /// The opcode to check
+ /// True if this handler can decode the opcode
+ public override bool CanHandle(byte opcode)
+ {
+ // BSF r32, r/m32 is a two-byte opcode: 0F BC
+ if (opcode != 0x0F)
+ {
+ return false;
+ }
+
+ // Check if we have enough bytes to read the second opcode byte
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Check if the second byte is BC
+ var secondByte = Decoder.PeakByte();
+
+ // Only handle when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return secondByte == 0xBC && !Decoder.HasOperandSizePrefix();
+ }
+
+ ///
+ /// Decodes a BSF r32, r/m32 instruction
+ ///
+ /// The opcode of the instruction
+ /// The instruction object to populate
+ /// True if the instruction was successfully decoded
+ public override bool Decode(byte opcode, Instruction instruction)
+ {
+ // Set the instruction type
+ instruction.Type = InstructionType.Bsf;
+
+ // Read the second opcode byte (BC)
+ Decoder.ReadByte();
+
+ // Check if we have enough bytes for the ModR/M byte
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Read the ModR/M byte
+ // For BSF r32, r/m32 (0F BC):
+ // - The reg field specifies the destination register
+ // - The r/m field with mod specifies the source operand (register or memory)
+ var (_, reg, _, sourceOperand) = ModRMDecoder.ReadModRM();
+
+ // Create the register operand for the reg field
+ var destinationOperand = OperandFactory.CreateRegisterOperand(reg);
+
+ // Set the structured operands
+ instruction.StructuredOperands =
+ [
+ destinationOperand,
+ sourceOperand
+ ];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Bit/BsrR32Rm32Handler.cs b/X86Disassembler/X86/Handlers/Bit/BsrR32Rm32Handler.cs
new file mode 100644
index 0000000..5e54bd3
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Bit/BsrR32Rm32Handler.cs
@@ -0,0 +1,84 @@
+namespace X86Disassembler.X86.Handlers.Bit;
+
+using Operands;
+
+///
+/// Handler for BSR r32, r/m32 instruction (0F BD)
+///
+public class BsrR32Rm32Handler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the BsrR32Rm32Handler class
+ ///
+ /// The instruction decoder that owns this handler
+ public BsrR32Rm32Handler(InstructionDecoder decoder)
+ : base(decoder)
+ {
+ }
+
+ ///
+ /// Checks if this handler can decode the given opcode
+ ///
+ /// The opcode to check
+ /// True if this handler can decode the opcode
+ public override bool CanHandle(byte opcode)
+ {
+ // BSR r32, r/m32 is a two-byte opcode: 0F BD
+ if (opcode != 0x0F)
+ {
+ return false;
+ }
+
+ // Check if we have enough bytes to read the second opcode byte
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Check if the second byte is BD
+ var secondByte = Decoder.PeakByte();
+
+ // Only handle when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return secondByte == 0xBD && !Decoder.HasOperandSizePrefix();
+ }
+
+ ///
+ /// Decodes a BSR r32, r/m32 instruction
+ ///
+ /// The opcode of the instruction
+ /// The instruction object to populate
+ /// True if the instruction was successfully decoded
+ public override bool Decode(byte opcode, Instruction instruction)
+ {
+ // Set the instruction type
+ instruction.Type = InstructionType.Bsr;
+
+ // Read the second opcode byte (BD)
+ Decoder.ReadByte();
+
+ // Check if we have enough bytes for the ModR/M byte
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Read the ModR/M byte
+ // For BSR r32, r/m32 (0F BD):
+ // - The reg field specifies the destination register
+ // - The r/m field with mod specifies the source operand (register or memory)
+ var (_, reg, _, sourceOperand) = ModRMDecoder.ReadModRM();
+
+ // Create the register operand for the reg field
+ var destinationOperand = OperandFactory.CreateRegisterOperand(reg);
+
+ // Set the structured operands
+ instruction.StructuredOperands =
+ [
+ destinationOperand,
+ sourceOperand
+ ];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Bit/BtR32Rm32Handler.cs b/X86Disassembler/X86/Handlers/Bit/BtR32Rm32Handler.cs
new file mode 100644
index 0000000..3248713
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Bit/BtR32Rm32Handler.cs
@@ -0,0 +1,84 @@
+namespace X86Disassembler.X86.Handlers.Bit;
+
+using Operands;
+
+///
+/// Handler for BT r32, r/m32 instruction (0F A3)
+///
+public class BtR32Rm32Handler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the BtR32Rm32Handler class
+ ///
+ /// The instruction decoder that owns this handler
+ public BtR32Rm32Handler(InstructionDecoder decoder)
+ : base(decoder)
+ {
+ }
+
+ ///
+ /// Checks if this handler can decode the given opcode
+ ///
+ /// The opcode to check
+ /// True if this handler can decode the opcode
+ public override bool CanHandle(byte opcode)
+ {
+ // BT r32, r/m32 is a two-byte opcode: 0F A3
+ if (opcode != 0x0F)
+ {
+ return false;
+ }
+
+ // Check if we have enough bytes to read the second opcode byte
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Check if the second byte is A3
+ var secondByte = Decoder.PeakByte();
+
+ // Only handle when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return secondByte == 0xA3 && !Decoder.HasOperandSizePrefix();
+ }
+
+ ///
+ /// Decodes a BT r32, r/m32 instruction
+ ///
+ /// The opcode of the instruction
+ /// The instruction object to populate
+ /// True if the instruction was successfully decoded
+ public override bool Decode(byte opcode, Instruction instruction)
+ {
+ // Set the instruction type
+ instruction.Type = InstructionType.Bt;
+
+ // Read the second opcode byte (A3)
+ Decoder.ReadByte();
+
+ // Check if we have enough bytes for the ModR/M byte
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Read the ModR/M byte
+ // For BT r/m32, r32 (0F A3):
+ // - The r/m field with mod specifies the destination operand (register or memory)
+ // - The reg field specifies the bit index register
+ var (_, reg, _, destinationOperand) = ModRMDecoder.ReadModRM();
+
+ // Create the register operand for the reg field
+ var bitIndexOperand = OperandFactory.CreateRegisterOperand(reg);
+
+ // Set the structured operands
+ instruction.StructuredOperands =
+ [
+ destinationOperand,
+ bitIndexOperand
+ ];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Bit/BtRm32ImmHandler.cs b/X86Disassembler/X86/Handlers/Bit/BtRm32ImmHandler.cs
new file mode 100644
index 0000000..cd9562f
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Bit/BtRm32ImmHandler.cs
@@ -0,0 +1,101 @@
+namespace X86Disassembler.X86.Handlers.Bit;
+
+using Operands;
+
+///
+/// Handler for BT r/m32, imm8 instruction (0F BA /4)
+///
+public class BtRm32ImmHandler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the BtRm32ImmHandler class
+ ///
+ /// The instruction decoder that owns this handler
+ public BtRm32ImmHandler(InstructionDecoder decoder)
+ : base(decoder)
+ {
+ }
+
+ ///
+ /// Checks if this handler can decode the given opcode
+ ///
+ /// The opcode to check
+ /// True if this handler can decode the opcode
+ public override bool CanHandle(byte opcode)
+ {
+ // BT r/m32, imm8 is encoded as 0F BA /4
+ if (opcode != 0x0F)
+ {
+ return false;
+ }
+
+ // Check if we have enough bytes to read the second opcode byte
+ if (!Decoder.CanRead(2))
+ {
+ return false;
+ }
+
+ var (secondByte, modRm) = Decoder.PeakTwoBytes();
+
+ // Check if the second byte is BA
+ if (secondByte != 0xBA)
+ {
+ return false;
+ }
+
+ // Check if the reg field of the ModR/M byte is 4 (BT)
+ var reg = ModRMDecoder.GetRegFromModRM(modRm);
+
+ // Only handle when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return reg == 4 && !Decoder.HasOperandSizePrefix();
+ }
+
+ ///
+ /// Decodes a BT r/m32, imm8 instruction
+ ///
+ /// The opcode of the instruction
+ /// The instruction object to populate
+ /// True if the instruction was successfully decoded
+ public override bool Decode(byte opcode, Instruction instruction)
+ {
+ // Set the instruction type
+ instruction.Type = InstructionType.Bt;
+
+ // Read the second opcode byte (BA)
+ Decoder.ReadByte();
+
+ // Check if we have enough bytes for the ModR/M byte
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Read the ModR/M byte
+ // For BT r/m32, imm8 (0F BA /4):
+ // - The r/m field with mod specifies the destination operand (register or memory)
+ // - The immediate value specifies the bit index
+ var (_, _, _, destinationOperand) = ModRMDecoder.ReadModRM();
+
+ // Check if we have enough bytes for the immediate value
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Read the immediate byte for the bit position
+ byte imm8 = Decoder.ReadByte();
+
+ // Create the immediate operand
+ var bitIndexOperand = OperandFactory.CreateImmediateOperand(imm8, 8);
+
+ // Set the structured operands
+ instruction.StructuredOperands =
+ [
+ destinationOperand,
+ bitIndexOperand
+ ];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Bit/BtcR32Rm32Handler.cs b/X86Disassembler/X86/Handlers/Bit/BtcR32Rm32Handler.cs
new file mode 100644
index 0000000..27a2fd2
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Bit/BtcR32Rm32Handler.cs
@@ -0,0 +1,84 @@
+namespace X86Disassembler.X86.Handlers.Bit;
+
+using Operands;
+
+///
+/// Handler for BTC r32, r/m32 instruction (0F BB)
+///
+public class BtcR32Rm32Handler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the BtcR32Rm32Handler class
+ ///
+ /// The instruction decoder that owns this handler
+ public BtcR32Rm32Handler(InstructionDecoder decoder)
+ : base(decoder)
+ {
+ }
+
+ ///
+ /// Checks if this handler can decode the given opcode
+ ///
+ /// The opcode to check
+ /// True if this handler can decode the opcode
+ public override bool CanHandle(byte opcode)
+ {
+ // BTC r32, r/m32 is a two-byte opcode: 0F BB
+ if (opcode != 0x0F)
+ {
+ return false;
+ }
+
+ // Check if we have enough bytes to read the second opcode byte
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Check if the second byte is BB
+ var secondByte = Decoder.PeakByte();
+
+ // Only handle when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return secondByte == 0xBB && !Decoder.HasOperandSizePrefix();
+ }
+
+ ///
+ /// Decodes a BTC r32, r/m32 instruction
+ ///
+ /// The opcode of the instruction
+ /// The instruction object to populate
+ /// True if the instruction was successfully decoded
+ public override bool Decode(byte opcode, Instruction instruction)
+ {
+ // Set the instruction type
+ instruction.Type = InstructionType.Btc;
+
+ // Read the second opcode byte (BB)
+ Decoder.ReadByte();
+
+ // Check if we have enough bytes for the ModR/M byte
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Read the ModR/M byte
+ // For BTC r/m32, r32 (0F BB):
+ // - The r/m field with mod specifies the destination operand (register or memory)
+ // - The reg field specifies the bit index register
+ var (_, reg, _, destinationOperand) = ModRMDecoder.ReadModRM();
+
+ // Create the register operand for the reg field
+ var bitIndexOperand = OperandFactory.CreateRegisterOperand(reg);
+
+ // Set the structured operands
+ instruction.StructuredOperands =
+ [
+ destinationOperand,
+ bitIndexOperand
+ ];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Bit/BtcRm32ImmHandler.cs b/X86Disassembler/X86/Handlers/Bit/BtcRm32ImmHandler.cs
new file mode 100644
index 0000000..964f56b
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Bit/BtcRm32ImmHandler.cs
@@ -0,0 +1,101 @@
+namespace X86Disassembler.X86.Handlers.Bit;
+
+using Operands;
+
+///
+/// Handler for BTC r/m32, imm8 instruction (0F BA /7)
+///
+public class BtcRm32ImmHandler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the BtcRm32ImmHandler class
+ ///
+ /// The instruction decoder that owns this handler
+ public BtcRm32ImmHandler(InstructionDecoder decoder)
+ : base(decoder)
+ {
+ }
+
+ ///
+ /// Checks if this handler can decode the given opcode
+ ///
+ /// The opcode to check
+ /// True if this handler can decode the opcode
+ public override bool CanHandle(byte opcode)
+ {
+ // BTC r/m32, imm8 is encoded as 0F BA /7
+ if (opcode != 0x0F)
+ {
+ return false;
+ }
+
+ // Check if we have enough bytes to read the second opcode byte
+ if (!Decoder.CanRead(2))
+ {
+ return false;
+ }
+
+ var (secondByte, modRm) = Decoder.PeakTwoBytes();
+
+ // Check if the second byte is BA
+ if (secondByte != 0xBA)
+ {
+ return false;
+ }
+
+ // Check if the reg field of the ModR/M byte is 7 (BTC)
+ var reg = ModRMDecoder.GetRegFromModRM(modRm);
+
+ // Only handle when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return reg == 7 && !Decoder.HasOperandSizePrefix();
+ }
+
+ ///
+ /// Decodes a BTC r/m32, imm8 instruction
+ ///
+ /// The opcode of the instruction
+ /// The instruction object to populate
+ /// True if the instruction was successfully decoded
+ public override bool Decode(byte opcode, Instruction instruction)
+ {
+ // Set the instruction type
+ instruction.Type = InstructionType.Btc;
+
+ // Read the second opcode byte (BA)
+ Decoder.ReadByte();
+
+ // Check if we have enough bytes for the ModR/M byte
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Read the ModR/M byte
+ // For BTC r/m32, imm8 (0F BA /7):
+ // - The r/m field with mod specifies the destination operand (register or memory)
+ // - The immediate value specifies the bit index
+ var (_, _, _, destinationOperand) = ModRMDecoder.ReadModRM();
+
+ // Check if we have enough bytes for the immediate value
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Read the immediate byte for the bit position
+ byte imm8 = Decoder.ReadByte();
+
+ // Create the immediate operand
+ var bitIndexOperand = OperandFactory.CreateImmediateOperand(imm8, 8);
+
+ // Set the structured operands
+ instruction.StructuredOperands =
+ [
+ destinationOperand,
+ bitIndexOperand
+ ];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Bit/BtrR32Rm32Handler.cs b/X86Disassembler/X86/Handlers/Bit/BtrR32Rm32Handler.cs
new file mode 100644
index 0000000..4775caa
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Bit/BtrR32Rm32Handler.cs
@@ -0,0 +1,84 @@
+namespace X86Disassembler.X86.Handlers.Bit;
+
+using Operands;
+
+///
+/// Handler for BTR r32, r/m32 instruction (0F B3)
+///
+public class BtrR32Rm32Handler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the BtrR32Rm32Handler class
+ ///
+ /// The instruction decoder that owns this handler
+ public BtrR32Rm32Handler(InstructionDecoder decoder)
+ : base(decoder)
+ {
+ }
+
+ ///
+ /// Checks if this handler can decode the given opcode
+ ///
+ /// The opcode to check
+ /// True if this handler can decode the opcode
+ public override bool CanHandle(byte opcode)
+ {
+ // BTR r32, r/m32 is a two-byte opcode: 0F B3
+ if (opcode != 0x0F)
+ {
+ return false;
+ }
+
+ // Check if we have enough bytes to read the second opcode byte
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Check if the second byte is B3
+ var secondByte = Decoder.PeakByte();
+
+ // Only handle when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return secondByte == 0xB3 && !Decoder.HasOperandSizePrefix();
+ }
+
+ ///
+ /// Decodes a BTR r32, r/m32 instruction
+ ///
+ /// The opcode of the instruction
+ /// The instruction object to populate
+ /// True if the instruction was successfully decoded
+ public override bool Decode(byte opcode, Instruction instruction)
+ {
+ // Set the instruction type
+ instruction.Type = InstructionType.Btr;
+
+ // Read the second opcode byte (B3)
+ Decoder.ReadByte();
+
+ // Check if we have enough bytes for the ModR/M byte
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Read the ModR/M byte
+ // For BTR r/m32, r32 (0F B3):
+ // - The r/m field with mod specifies the destination operand (register or memory)
+ // - The reg field specifies the bit index register
+ var (_, reg, _, destinationOperand) = ModRMDecoder.ReadModRM();
+
+ // Create the register operand for the reg field
+ var bitIndexOperand = OperandFactory.CreateRegisterOperand(reg);
+
+ // Set the structured operands
+ instruction.StructuredOperands =
+ [
+ destinationOperand,
+ bitIndexOperand
+ ];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Bit/BtrRm32ImmHandler.cs b/X86Disassembler/X86/Handlers/Bit/BtrRm32ImmHandler.cs
new file mode 100644
index 0000000..eeeece1
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Bit/BtrRm32ImmHandler.cs
@@ -0,0 +1,102 @@
+namespace X86Disassembler.X86.Handlers.Bit;
+
+using Operands;
+
+///
+/// Handler for BTR r/m32, imm8 instruction (0F BA /6)
+///
+public class BtrRm32ImmHandler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the BtrRm32ImmHandler class
+ ///
+ /// The instruction decoder that owns this handler
+ public BtrRm32ImmHandler(InstructionDecoder decoder)
+ : base(decoder)
+ {
+ }
+
+ ///
+ /// Checks if this handler can decode the given opcode
+ ///
+ /// The opcode to check
+ /// True if this handler can decode the opcode
+ public override bool CanHandle(byte opcode)
+ {
+ // BTR r/m32, imm8 is encoded as 0F BA /6
+ if (opcode != 0x0F)
+ {
+ return false;
+ }
+
+
+ // Check if we have enough bytes to read the second opcode byte
+ if (!Decoder.CanRead(2))
+ {
+ return false;
+ }
+
+ var (secondByte, modRm) = Decoder.PeakTwoBytes();
+
+ // Check if the second byte is BA
+ if (secondByte != 0xBA)
+ {
+ return false;
+ }
+
+ // Check if the reg field of the ModR/M byte is 6 (BTR)
+ var reg = ModRMDecoder.GetRegFromModRM(modRm);
+
+ // Only handle when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return reg == 6 && !Decoder.HasOperandSizePrefix();
+ }
+
+ ///
+ /// Decodes a BTR r/m32, imm8 instruction
+ ///
+ /// The opcode of the instruction
+ /// The instruction object to populate
+ /// True if the instruction was successfully decoded
+ public override bool Decode(byte opcode, Instruction instruction)
+ {
+ // Set the instruction type
+ instruction.Type = InstructionType.Btr;
+
+ // Read the second opcode byte (BA)
+ Decoder.ReadByte();
+
+ // Check if we have enough bytes for the ModR/M byte
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Read the ModR/M byte
+ // For BTR r/m32, imm8 (0F BA /6):
+ // - The r/m field with mod specifies the destination operand (register or memory)
+ // - The immediate value specifies the bit index
+ var (_, _, _, destinationOperand) = ModRMDecoder.ReadModRM();
+
+ // Check if we have enough bytes for the immediate value
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Read the immediate byte for the bit position
+ byte imm8 = Decoder.ReadByte();
+
+ // Create the immediate operand
+ var bitIndexOperand = OperandFactory.CreateImmediateOperand(imm8, 8);
+
+ // Set the structured operands
+ instruction.StructuredOperands =
+ [
+ destinationOperand,
+ bitIndexOperand
+ ];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Bit/BtsR32Rm32Handler.cs b/X86Disassembler/X86/Handlers/Bit/BtsR32Rm32Handler.cs
new file mode 100644
index 0000000..66aad22
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Bit/BtsR32Rm32Handler.cs
@@ -0,0 +1,84 @@
+namespace X86Disassembler.X86.Handlers.Bit;
+
+using Operands;
+
+///
+/// Handler for BTS r32, r/m32 instruction (0F AB)
+///
+public class BtsR32Rm32Handler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the BtsR32Rm32Handler class
+ ///
+ /// The instruction decoder that owns this handler
+ public BtsR32Rm32Handler(InstructionDecoder decoder)
+ : base(decoder)
+ {
+ }
+
+ ///
+ /// Checks if this handler can decode the given opcode
+ ///
+ /// The opcode to check
+ /// True if this handler can decode the opcode
+ public override bool CanHandle(byte opcode)
+ {
+ // BTS r32, r/m32 is a two-byte opcode: 0F AB
+ if (opcode != 0x0F)
+ {
+ return false;
+ }
+
+ // Check if we have enough bytes to read the second opcode byte
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Check if the second byte is AB
+ var secondByte = Decoder.PeakByte();
+
+ // Only handle when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return secondByte == 0xAB && !Decoder.HasOperandSizePrefix();
+ }
+
+ ///
+ /// Decodes a BTS r32, r/m32 instruction
+ ///
+ /// The opcode of the instruction
+ /// The instruction object to populate
+ /// True if the instruction was successfully decoded
+ public override bool Decode(byte opcode, Instruction instruction)
+ {
+ // Set the instruction type
+ instruction.Type = InstructionType.Bts;
+
+ // Read the second opcode byte (AB)
+ Decoder.ReadByte();
+
+ // Check if we have enough bytes for the ModR/M byte
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Read the ModR/M byte
+ // For BTS r/m32, r32 (0F AB):
+ // - The r/m field with mod specifies the destination operand (register or memory)
+ // - The reg field specifies the bit index register
+ var (_, reg, _, destinationOperand) = ModRMDecoder.ReadModRM();
+
+ // Create the register operand for the reg field
+ var bitIndexOperand = OperandFactory.CreateRegisterOperand(reg);
+
+ // Set the structured operands
+ instruction.StructuredOperands =
+ [
+ destinationOperand,
+ bitIndexOperand
+ ];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Bit/BtsRm32ImmHandler.cs b/X86Disassembler/X86/Handlers/Bit/BtsRm32ImmHandler.cs
new file mode 100644
index 0000000..b1f08f7
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Bit/BtsRm32ImmHandler.cs
@@ -0,0 +1,101 @@
+namespace X86Disassembler.X86.Handlers.Bit;
+
+using Operands;
+
+///
+/// Handler for BTS r/m32, imm8 instruction (0F BA /5)
+///
+public class BtsRm32ImmHandler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the BtsRm32ImmHandler class
+ ///
+ /// The instruction decoder that owns this handler
+ public BtsRm32ImmHandler(InstructionDecoder decoder)
+ : base(decoder)
+ {
+ }
+
+ ///
+ /// Checks if this handler can decode the given opcode
+ ///
+ /// The opcode to check
+ /// True if this handler can decode the opcode
+ public override bool CanHandle(byte opcode)
+ {
+ // BTS r/m32, imm8 is encoded as 0F BA /5
+ if (opcode != 0x0F)
+ {
+ return false;
+ }
+
+ // Check if we have enough bytes to read the second opcode byte
+ if (!Decoder.CanRead(2))
+ {
+ return false;
+ }
+
+ var (secondByte, modRm) = Decoder.PeakTwoBytes();
+
+ // Check if the second byte is BA
+ if (secondByte != 0xBA)
+ {
+ return false;
+ }
+
+ // Check if the reg field of the ModR/M byte is 5 (BTS)
+ var reg = ModRMDecoder.GetRegFromModRM(modRm);
+
+ // Only handle when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return reg == 5 && !Decoder.HasOperandSizePrefix();
+ }
+
+ ///
+ /// Decodes a BTS r/m32, imm8 instruction
+ ///
+ /// The opcode of the instruction
+ /// The instruction object to populate
+ /// True if the instruction was successfully decoded
+ public override bool Decode(byte opcode, Instruction instruction)
+ {
+ // Set the instruction type
+ instruction.Type = InstructionType.Bts;
+
+ // Read the second opcode byte (BA)
+ Decoder.ReadByte();
+
+ // Check if we have enough bytes for the ModR/M byte
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Read the ModR/M byte
+ // For BTS r/m32, imm8 (0F BA /5):
+ // - The r/m field with mod specifies the destination operand (register or memory)
+ // - The immediate value specifies the bit index
+ var (_, _, _, destinationOperand) = ModRMDecoder.ReadModRM();
+
+ // Check if we have enough bytes for the immediate value
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Read the immediate byte for the bit position
+ byte imm8 = Decoder.ReadByte();
+
+ // Create the immediate operand
+ var bitIndexOperand = OperandFactory.CreateImmediateOperand(imm8, 8);
+
+ // Set the structured operands
+ instruction.StructuredOperands =
+ [
+ destinationOperand,
+ bitIndexOperand
+ ];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Call/CallFarPtrHandler.cs b/X86Disassembler/X86/Handlers/Call/CallFarPtrHandler.cs
new file mode 100644
index 0000000..da4af0b
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Call/CallFarPtrHandler.cs
@@ -0,0 +1,94 @@
+using X86Disassembler.X86.Operands;
+
+namespace X86Disassembler.X86.Handlers.Call;
+
+///
+/// Handler for CALL m16:32 instruction (FF /3) - Far call with memory operand
+///
+public class CallFarPtrHandler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the CallFarPtrHandler class
+ ///
+ /// The instruction decoder that owns this handler
+ public CallFarPtrHandler(InstructionDecoder decoder)
+ : base(decoder)
+ {
+ }
+
+ ///
+ /// Checks if this handler can decode the given opcode
+ ///
+ /// The opcode to check
+ /// True if this handler can decode the opcode
+ public override bool CanHandle(byte opcode)
+ {
+ // CALL m16:32 is encoded as FF /3
+ if (opcode != 0xFF)
+ {
+ return false;
+ }
+
+ // Check if we have enough bytes to read the ModR/M byte
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Extract the reg field (bits 3-5)
+ var reg = ModRMDecoder.PeakModRMReg();
+
+ // CALL m16:32 is encoded as FF /3 (reg field = 3)
+ return reg == 3;
+ }
+
+ ///
+ /// Decodes a CALL m16:32 instruction (far call)
+ ///
+ /// The opcode of the instruction
+ /// The instruction object to populate
+ /// True if the instruction was successfully decoded
+ public override bool Decode(byte opcode, Instruction instruction)
+ {
+ // Set the instruction type
+ instruction.Type = InstructionType.Call;
+
+ // Check if we have enough bytes for the ModR/M byte
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Read the ModR/M byte
+ // For CALL m16:32 (FF /3):
+ // - The r/m field with mod specifies the memory operand
+ // - This instruction can only reference memory, not registers
+ var (mod, reg, rm, operand) = ModRMDecoder.ReadModRM();
+
+ // For far calls, we need to ensure this is a memory operand, not a register
+ // If mod == 3, then it's a register operand, which is invalid for far calls
+ if (mod == 3)
+ {
+ return false;
+ }
+
+ // Create a special far pointer operand by modifying the memory operand
+ // to indicate it's a far pointer (fword ptr)
+ // We need to ensure the operand is a memory operand before converting it
+ if (!(operand is MemoryOperand memOperand))
+ {
+ return false;
+ }
+
+ var farPtrOperand = OperandFactory.CreateFarPointerOperand(memOperand);
+
+ // Set the structured operands
+ // CALL has only one operand
+ instruction.StructuredOperands =
+ [
+ farPtrOperand
+ ];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Call/CallRm32Handler.cs b/X86Disassembler/X86/Handlers/Call/CallRm32Handler.cs
index 95f04f3..4c9ad74 100644
--- a/X86Disassembler/X86/Handlers/Call/CallRm32Handler.cs
+++ b/X86Disassembler/X86/Handlers/Call/CallRm32Handler.cs
@@ -39,7 +39,9 @@ public class CallRm32Handler : InstructionHandler
var reg = ModRMDecoder.PeakModRMReg();
// CALL r/m32 is encoded as FF /2 (reg field = 2)
- return reg == 2;
+ // Only handle when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return reg == 2 && !Decoder.HasOperandSizePrefix();
}
///
diff --git a/X86Disassembler/X86/Handlers/Cmp/CmpR32Rm32Handler.cs b/X86Disassembler/X86/Handlers/Cmp/CmpR32Rm32Handler.cs
index cf1fa3d..0fc4527 100644
--- a/X86Disassembler/X86/Handlers/Cmp/CmpR32Rm32Handler.cs
+++ b/X86Disassembler/X86/Handlers/Cmp/CmpR32Rm32Handler.cs
@@ -23,7 +23,9 @@ public class CmpR32Rm32Handler : InstructionHandler
/// True if this handler can decode the opcode
public override bool CanHandle(byte opcode)
{
- return opcode == 0x3B;
+ // Only handle opcode 0x3B when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return opcode == 0x3B && !Decoder.HasOperandSizePrefix();
}
///
diff --git a/X86Disassembler/X86/Handlers/Cmp/CmpRm32R32Handler.cs b/X86Disassembler/X86/Handlers/Cmp/CmpRm32R32Handler.cs
index 99905c9..9ba37eb 100644
--- a/X86Disassembler/X86/Handlers/Cmp/CmpRm32R32Handler.cs
+++ b/X86Disassembler/X86/Handlers/Cmp/CmpRm32R32Handler.cs
@@ -23,7 +23,9 @@ public class CmpRm32R32Handler : InstructionHandler
/// True if this handler can decode the opcode
public override bool CanHandle(byte opcode)
{
- return opcode == 0x39;
+ // Only handle opcode 0x39 when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return opcode == 0x39 && !Decoder.HasOperandSizePrefix();
}
///
diff --git a/X86Disassembler/X86/Handlers/Dec/DecRegHandler.cs b/X86Disassembler/X86/Handlers/Dec/DecRegHandler.cs
index 085db94..28012ba 100644
--- a/X86Disassembler/X86/Handlers/Dec/DecRegHandler.cs
+++ b/X86Disassembler/X86/Handlers/Dec/DecRegHandler.cs
@@ -24,7 +24,9 @@ public class DecRegHandler : InstructionHandler
public override bool CanHandle(byte opcode)
{
// DEC EAX = 0x48, DEC ECX = 0x49, ..., DEC EDI = 0x4F
- return opcode >= 0x48 && opcode <= 0x4F;
+ // Only handle when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return opcode >= 0x48 && opcode <= 0x4F && !Decoder.HasOperandSizePrefix();
}
///
diff --git a/X86Disassembler/X86/Handlers/Imul/ImulR32Rm32Handler.cs b/X86Disassembler/X86/Handlers/Imul/ImulR32Rm32Handler.cs
new file mode 100644
index 0000000..aa99da3
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Imul/ImulR32Rm32Handler.cs
@@ -0,0 +1,77 @@
+using X86Disassembler.X86.Operands;
+
+namespace X86Disassembler.X86.Handlers.Imul;
+
+///
+/// Handler for IMUL r32, r/m32 instruction (0x0F 0xAF /r)
+///
+public class ImulR32Rm32Handler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the ImulR32Rm32Handler class
+ ///
+ /// The instruction decoder that owns this handler
+ public ImulR32Rm32Handler(InstructionDecoder decoder)
+ : base(decoder)
+ {
+ }
+
+ ///
+ /// Checks if this handler can decode the given opcode sequence
+ ///
+ /// The opcode to check
+ /// True if this handler can decode the opcode
+ public override bool CanHandle(byte opcode)
+ {
+ // IMUL r32, r/m32: opcode 0F AF /r
+ if (opcode != 0x0F)
+ return false;
+
+ // Check if we can read the second byte
+ if (!Decoder.CanReadByte())
+ return false;
+
+ // Check if the second byte is 0xAF
+ byte secondByte = Decoder.PeakByte();
+
+ // Only handle when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return secondByte == 0xAF && !Decoder.HasOperandSizePrefix();
+ }
+
+ ///
+ /// Decodes an IMUL r32, r/m32 instruction
+ ///
+ /// The opcode of the instruction
+ /// The instruction object to populate
+ /// True if the instruction was successfully decoded
+ public override bool Decode(byte opcode, Instruction instruction)
+ {
+ instruction.Type = InstructionType.IMul;
+
+ // Read the second byte of the opcode (0xAF)
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+ byte secondByte = Decoder.ReadByte();
+ if (secondByte != 0xAF)
+ {
+ return false;
+ }
+
+ // Read ModR/M: reg = destination, r/m = source
+ var (_, reg, _, operand) = ModRMDecoder.ReadModRM();
+
+ // Create the destination register operand (32-bit)
+ var destOperand = OperandFactory.CreateRegisterOperand(reg);
+
+ // Source operand is already an Operand
+ instruction.StructuredOperands =
+ [
+ destOperand,
+ operand
+ ];
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Imul/ImulR32Rm32Imm32Handler.cs b/X86Disassembler/X86/Handlers/Imul/ImulR32Rm32Imm32Handler.cs
new file mode 100644
index 0000000..57a13c1
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Imul/ImulR32Rm32Imm32Handler.cs
@@ -0,0 +1,57 @@
+using X86Disassembler.X86.Operands;
+
+namespace X86Disassembler.X86.Handlers.Imul;
+
+///
+/// Handler for IMUL r32, r/m32, imm32 instruction (0x69 /r id)
+///
+public class ImulR32Rm32Imm32Handler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the ImulR32Rm32Imm32Handler class
+ ///
+ /// The instruction decoder that owns this handler
+ public ImulR32Rm32Imm32Handler(InstructionDecoder decoder)
+ : base(decoder)
+ {
+ }
+
+ ///
+ /// Checks if this handler can decode the given opcode
+ ///
+ /// The opcode to check
+ /// True if this handler can decode the opcode
+ public override bool CanHandle(byte opcode)
+ {
+ // IMUL r32, r/m32, imm32: opcode 69 /r id
+ return opcode == 0x69;
+ }
+
+ ///
+ /// Decodes an IMUL r32, r/m32, imm32 instruction
+ ///
+ /// The opcode of the instruction
+ /// The instruction object to populate
+ /// True if the instruction was successfully decoded
+ public override bool Decode(byte opcode, Instruction instruction)
+ {
+ instruction.Type = InstructionType.IMul;
+
+ // Read ModR/M: reg = destination, r/m = source
+ var (_, reg, _, operand) = ModRMDecoder.ReadModRM();
+
+ var destOperand = OperandFactory.CreateRegisterOperand(reg);
+
+ // Read imm32 (4 bytes)
+ uint imm32 = Decoder.ReadUInt32();
+ var immOperand = OperandFactory.CreateImmediateOperand(imm32);
+
+ instruction.StructuredOperands =
+ [
+ destOperand,
+ operand,
+ immOperand
+ ];
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Imul/ImulR32Rm32Imm8Handler.cs b/X86Disassembler/X86/Handlers/Imul/ImulR32Rm32Imm8Handler.cs
new file mode 100644
index 0000000..158a1fd
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Imul/ImulR32Rm32Imm8Handler.cs
@@ -0,0 +1,57 @@
+using X86Disassembler.X86.Operands;
+
+namespace X86Disassembler.X86.Handlers.Imul;
+
+///
+/// Handler for IMUL r32, r/m32, imm8 instruction (0x6B /r ib)
+///
+public class ImulR32Rm32Imm8Handler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the ImulR32Rm32Imm8Handler class
+ ///
+ /// The instruction decoder that owns this handler
+ public ImulR32Rm32Imm8Handler(InstructionDecoder decoder)
+ : base(decoder)
+ {
+ }
+
+ ///
+ /// Checks if this handler can decode the given opcode
+ ///
+ /// The opcode to check
+ /// True if this handler can decode the opcode
+ public override bool CanHandle(byte opcode)
+ {
+ // IMUL r32, r/m32, imm8: opcode 6B /r ib
+ return opcode == 0x6B;
+ }
+
+ ///
+ /// Decodes an IMUL r32, r/m32, imm8 instruction
+ ///
+ /// The opcode of the instruction
+ /// The instruction object to populate
+ /// True if the instruction was successfully decoded
+ public override bool Decode(byte opcode, Instruction instruction)
+ {
+ instruction.Type = InstructionType.IMul;
+
+ // Read ModR/M: reg = destination, r/m = source
+ var (_, reg, _, operand) = ModRMDecoder.ReadModRM();
+
+ var destOperand = OperandFactory.CreateRegisterOperand(reg);
+
+ // Read imm8 and sign-extend to int32
+ sbyte imm8 = (sbyte)Decoder.ReadByte();
+ var immOperand = OperandFactory.CreateImmediateOperand((uint)imm8, 8); // 8-bit immediate, sign-extended
+
+ instruction.StructuredOperands =
+ [
+ destOperand,
+ operand,
+ immOperand
+ ];
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Inc/IncRegHandler.cs b/X86Disassembler/X86/Handlers/Inc/IncRegHandler.cs
index 1bee3f2..1227fe3 100644
--- a/X86Disassembler/X86/Handlers/Inc/IncRegHandler.cs
+++ b/X86Disassembler/X86/Handlers/Inc/IncRegHandler.cs
@@ -24,7 +24,9 @@ public class IncRegHandler : InstructionHandler
public override bool CanHandle(byte opcode)
{
// INC EAX = 0x40, INC ECX = 0x41, ..., INC EDI = 0x47
- return opcode >= 0x40 && opcode <= 0x47;
+ // Only handle when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return opcode >= 0x40 && opcode <= 0x47 && !Decoder.HasOperandSizePrefix();
}
///
diff --git a/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs b/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs
index 2993b97..2fca9b4 100644
--- a/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs
+++ b/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs
@@ -1,6 +1,7 @@
using X86Disassembler.X86.Handlers.Adc;
using X86Disassembler.X86.Handlers.Add;
using X86Disassembler.X86.Handlers.And;
+using X86Disassembler.X86.Handlers.Bit;
using X86Disassembler.X86.Handlers.Call;
using X86Disassembler.X86.Handlers.Cmp;
using X86Disassembler.X86.Handlers.Dec;
@@ -63,7 +64,8 @@ public class InstructionHandlerFactory
_handlers.Add(new Int3Handler(_decoder));
// Register handlers in order of priority (most specific first)
- RegisterArithmeticImmediateHandlers(); // Group 1 instructions (including 0x83)
+ RegisterSbbHandlers(); // SBB instructions
+ RegisterAdcHandlers(); // ADC instructions
RegisterAddHandlers(); // ADD instructions
RegisterAndHandlers(); // AND instructions
RegisterOrHandlers(); // OR instructions
@@ -72,7 +74,6 @@ public class InstructionHandlerFactory
RegisterTestHandlers(); // TEST instructions
// Register arithmetic unary instructions
- RegisterArithmeticUnaryHandlers(); // Empty, kept for consistency
RegisterNotHandlers(); // NOT instructions
RegisterNegHandlers(); // NEG instructions
RegisterMulHandlers(); // MUL instructions
@@ -93,32 +94,44 @@ public class InstructionHandlerFactory
RegisterMovHandlers();
RegisterSubHandlers(); // Register SUB handlers
RegisterNopHandlers(); // Register NOP handlers
+ RegisterBitHandlers(); // Register bit manipulation handlers
}
///
- /// Registers all ArithmeticUnary instruction handlers
+ /// Registers all SBB instruction handlers
///
- private void RegisterArithmeticUnaryHandlers()
+ private void RegisterSbbHandlers()
{
- // This method is kept for consistency, but all handlers have been moved to their own namespaces
- }
-
- ///
- /// Registers all ArithmeticImmediate instruction handlers
- ///
- private void RegisterArithmeticImmediateHandlers()
- {
- // ADC handlers
- _handlers.Add(new AdcImmToRm32Handler(_decoder)); // ADC r/m32, imm32 (opcode 81 /2)
- _handlers.Add(new AdcImmToRm32SignExtendedHandler(_decoder)); // ADC r/m32, imm8 (opcode 83 /2)
-
- // SBB handlers
+ // SBB immediate handlers
_handlers.Add(new SbbImmFromRm32Handler(_decoder)); // SBB r/m32, imm32 (opcode 81 /3)
_handlers.Add(new SbbImmFromRm32SignExtendedHandler(_decoder)); // SBB r/m32, imm8 (opcode 83 /3)
+ }
+
+ ///
+ /// Registers all ADC instruction handlers
+ ///
+ private void RegisterAdcHandlers()
+ {
+ // ADC immediate handlers
+ _handlers.Add(new AdcImmToRm8Handler(_decoder)); // ADC r/m8, imm8 (opcode 80 /2)
+ _handlers.Add(new AdcImmToRm16Handler(_decoder)); // ADC r/m16, imm16 (opcode 81 /2 with 0x66 prefix)
+ _handlers.Add(new AdcImmToRm16SignExtendedHandler(_decoder)); // ADC r/m16, imm8 (opcode 83 /2 with 0x66 prefix)
+ _handlers.Add(new AdcImmToRm32Handler(_decoder)); // ADC r/m32, imm32 (opcode 81 /2)
+ _handlers.Add(new AdcImmToRm32SignExtendedHandler(_decoder)); // ADC r/m32, imm8 (opcode 83 /2)
+ _handlers.Add(new AdcAlImmHandler(_decoder)); // ADC AL, imm8 (opcode 14)
+ _handlers.Add(new AdcAccumulatorImmHandler(_decoder)); // ADC AX/EAX, imm16/32 (opcode 15)
- // SUB handlers
- _handlers.Add(new SubImmFromRm32Handler(_decoder)); // SUB r/m32, imm32 (opcode 81 /5)
- _handlers.Add(new SubImmFromRm32SignExtendedHandler(_decoder)); // SUB r/m32, imm8 (opcode 83 /5)
+ // Register-to-register ADC handlers (8-bit)
+ _handlers.Add(new AdcR8Rm8Handler(_decoder)); // ADC r8, r/m8 (opcode 12)
+ _handlers.Add(new AdcRm8R8Handler(_decoder)); // ADC r/m8, r8 (opcode 10)
+
+ // Register-to-register ADC handlers (16-bit)
+ _handlers.Add(new AdcR16Rm16Handler(_decoder)); // ADC r16, r/m16 (opcode 13 with 0x66 prefix)
+ _handlers.Add(new AdcRm16R16Handler(_decoder)); // ADC r/m16, r16 (opcode 11 with 0x66 prefix)
+
+ // Register-to-register ADC handlers (32-bit)
+ _handlers.Add(new AdcR32Rm32Handler(_decoder)); // ADC r32, r/m32 (opcode 13)
+ _handlers.Add(new AdcRm32R32Handler(_decoder)); // ADC r/m32, r32 (opcode 11)
}
///
@@ -310,14 +323,6 @@ public class InstructionHandlerFactory
_handlers.Add(new MovRm32Imm32Handler(_decoder));
_handlers.Add(new MovRm8Imm8Handler(_decoder));
- // Add PUSH handlers
- _handlers.Add(new PushRegHandler(_decoder));
- _handlers.Add(new PushImm32Handler(_decoder));
- _handlers.Add(new PushImm8Handler(_decoder));
-
- // Add POP handlers
- _handlers.Add(new PopRegHandler(_decoder));
-
// Add XCHG handlers
_handlers.Add(new XchgEaxRegHandler(_decoder));
}
@@ -392,6 +397,7 @@ public class InstructionHandlerFactory
{
// Add POP register handlers
_handlers.Add(new PopRegHandler(_decoder)); // POP r32 (opcode 58+r)
+ _handlers.Add(new PopRm32Handler(_decoder)); // POP r/m32 (opcode 8F /0)
}
///
@@ -421,20 +427,20 @@ public class InstructionHandlerFactory
private void RegisterSubHandlers()
{
// Register SUB handlers
-
+
+ // 16-bit handlers with operand size prefix (must come first)
+ _handlers.Add(new SubAxImm16Handler(_decoder));
+ _handlers.Add(new SubImmFromRm16Handler(_decoder));
+ _handlers.Add(new SubImmFromRm16SignExtendedHandler(_decoder));
+ _handlers.Add(new SubRm16R16Handler(_decoder));
+ _handlers.Add(new SubR16Rm16Handler(_decoder));
+
// 32-bit handlers
_handlers.Add(new SubRm32R32Handler(_decoder));
_handlers.Add(new SubR32Rm32Handler(_decoder));
_handlers.Add(new SubImmFromRm32Handler(_decoder));
_handlers.Add(new SubImmFromRm32SignExtendedHandler(_decoder));
- // 16-bit handlers
- _handlers.Add(new SubRm16R16Handler(_decoder));
- _handlers.Add(new SubR16Rm16Handler(_decoder));
- _handlers.Add(new SubAxImm16Handler(_decoder));
- _handlers.Add(new SubImmFromRm16Handler(_decoder));
- _handlers.Add(new SubImmFromRm16SignExtendedHandler(_decoder));
-
// 8-bit handlers
_handlers.Add(new SubRm8R8Handler(_decoder));
_handlers.Add(new SubR8Rm8Handler(_decoder));
@@ -453,6 +459,32 @@ public class InstructionHandlerFactory
_handlers.Add(new MultiByteNopHandler(_decoder));
}
+ ///
+ /// Registers all bit manipulation instruction handlers
+ ///
+ private void RegisterBitHandlers()
+ {
+ // BT (Bit Test) handlers
+ _handlers.Add(new BtR32Rm32Handler(_decoder)); // BT r32, r/m32 (0F A3)
+ _handlers.Add(new BtRm32ImmHandler(_decoder)); // BT r/m32, imm8 (0F BA /4)
+
+ // BTS (Bit Test and Set) handlers
+ _handlers.Add(new BtsR32Rm32Handler(_decoder)); // BTS r32, r/m32 (0F AB)
+ _handlers.Add(new BtsRm32ImmHandler(_decoder)); // BTS r/m32, imm8 (0F BA /5)
+
+ // BTR (Bit Test and Reset) handlers
+ _handlers.Add(new BtrR32Rm32Handler(_decoder)); // BTR r32, r/m32 (0F B3)
+ _handlers.Add(new BtrRm32ImmHandler(_decoder)); // BTR r/m32, imm8 (0F BA /6)
+
+ // BTC (Bit Test and Complement) handlers
+ _handlers.Add(new BtcR32Rm32Handler(_decoder)); // BTC r32, r/m32 (0F BB)
+ _handlers.Add(new BtcRm32ImmHandler(_decoder)); // BTC r/m32, imm8 (0F BA /7)
+
+ // BSF and BSR (Bit Scan) handlers
+ _handlers.Add(new BsfR32Rm32Handler(_decoder)); // BSF r32, r/m32 (0F BC)
+ _handlers.Add(new BsrR32Rm32Handler(_decoder)); // BSR r32, r/m32 (0F BD)
+ }
+
///
/// Registers all NEG instruction handlers
///
diff --git a/X86Disassembler/X86/Handlers/Jump/JmpRel32Handler.cs b/X86Disassembler/X86/Handlers/Jump/JmpRel32Handler.cs
index 37253bf..5b15c7e 100644
--- a/X86Disassembler/X86/Handlers/Jump/JmpRel32Handler.cs
+++ b/X86Disassembler/X86/Handlers/Jump/JmpRel32Handler.cs
@@ -23,7 +23,9 @@ public class JmpRel32Handler : InstructionHandler
/// True if this handler can decode the opcode
public override bool CanHandle(byte opcode)
{
- return opcode == 0xE9;
+ // Only handle opcode 0xE9 when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return opcode == 0xE9 && !Decoder.HasOperandSizePrefix();
}
///
diff --git a/X86Disassembler/X86/Handlers/Jump/JmpRm32Handler.cs b/X86Disassembler/X86/Handlers/Jump/JmpRm32Handler.cs
index 0bbaee0..bd24c7f 100644
--- a/X86Disassembler/X86/Handlers/Jump/JmpRm32Handler.cs
+++ b/X86Disassembler/X86/Handlers/Jump/JmpRm32Handler.cs
@@ -39,7 +39,9 @@ public class JmpRm32Handler : InstructionHandler
var reg = ModRMDecoder.PeakModRMReg();
// JMP r/m32 is encoded as FF /4 (reg field = 4)
- return reg == 4;
+ // Only handle when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return reg == 4 && !Decoder.HasOperandSizePrefix();
}
///
diff --git a/X86Disassembler/X86/Handlers/Lea/LeaR32MHandler.cs b/X86Disassembler/X86/Handlers/Lea/LeaR32MHandler.cs
index dda70df..eaadf84 100644
--- a/X86Disassembler/X86/Handlers/Lea/LeaR32MHandler.cs
+++ b/X86Disassembler/X86/Handlers/Lea/LeaR32MHandler.cs
@@ -23,7 +23,9 @@ public class LeaR32MHandler : InstructionHandler
/// True if this handler can decode the opcode
public override bool CanHandle(byte opcode)
{
- return opcode == 0x8D;
+ // Only handle opcode 0x8D when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return opcode == 0x8D && !Decoder.HasOperandSizePrefix();
}
///
diff --git a/X86Disassembler/X86/Handlers/Mov/MovMemRegHandler.cs b/X86Disassembler/X86/Handlers/Mov/MovMemRegHandler.cs
index 4a68a9a..476df3d 100644
--- a/X86Disassembler/X86/Handlers/Mov/MovMemRegHandler.cs
+++ b/X86Disassembler/X86/Handlers/Mov/MovMemRegHandler.cs
@@ -23,7 +23,13 @@ public class MovMemRegHandler : InstructionHandler
/// True if this handler can decode the opcode
public override bool CanHandle(byte opcode)
{
- return opcode == 0x88 || opcode == 0x89;
+ // For 8-bit operations (0x88), no prefix check needed
+ if (opcode == 0x88)
+ return true;
+
+ // For 32-bit operations (0x89), only handle when operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return opcode == 0x89 && !Decoder.HasOperandSizePrefix();
}
///
diff --git a/X86Disassembler/X86/Handlers/Mov/MovRegMemHandler.cs b/X86Disassembler/X86/Handlers/Mov/MovRegMemHandler.cs
index c6a65bc..7f7d6dd 100644
--- a/X86Disassembler/X86/Handlers/Mov/MovRegMemHandler.cs
+++ b/X86Disassembler/X86/Handlers/Mov/MovRegMemHandler.cs
@@ -23,7 +23,13 @@ public class MovRegMemHandler : InstructionHandler
/// True if this handler can decode the opcode
public override bool CanHandle(byte opcode)
{
- return opcode == 0x8A || opcode == 0x8B;
+ // For 8-bit operations (0x8A), no prefix check needed
+ if (opcode == 0x8A)
+ return true;
+
+ // For 32-bit operations (0x8B), only handle when operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return opcode == 0x8B && !Decoder.HasOperandSizePrefix();
}
///
diff --git a/X86Disassembler/X86/Handlers/Mov/MovRm32Imm32Handler.cs b/X86Disassembler/X86/Handlers/Mov/MovRm32Imm32Handler.cs
index 899737c..ef77eb3 100644
--- a/X86Disassembler/X86/Handlers/Mov/MovRm32Imm32Handler.cs
+++ b/X86Disassembler/X86/Handlers/Mov/MovRm32Imm32Handler.cs
@@ -34,7 +34,7 @@ public class MovRm32Imm32Handler : InstructionHandler
return false;
}
- // Peek at the ModR/M byte without advancing the position
+ // Peak at the ModR/M byte without advancing the position
var reg = ModRMDecoder.PeakModRMReg();
// MOV r/m8, imm8 only uses reg=0
diff --git a/X86Disassembler/X86/Handlers/Mov/MovRm8Imm8Handler.cs b/X86Disassembler/X86/Handlers/Mov/MovRm8Imm8Handler.cs
index dabfcf8..0f58806 100644
--- a/X86Disassembler/X86/Handlers/Mov/MovRm8Imm8Handler.cs
+++ b/X86Disassembler/X86/Handlers/Mov/MovRm8Imm8Handler.cs
@@ -35,7 +35,7 @@ public class MovRm8Imm8Handler : InstructionHandler
return false;
}
- // Peek at the ModR/M byte without advancing the position
+ // Peak at the ModR/M byte without advancing the position
var reg = ModRMDecoder.PeakModRMReg();
// MOV r/m8, imm8 only uses reg=0
diff --git a/X86Disassembler/X86/Handlers/Neg/NegRm32Handler.cs b/X86Disassembler/X86/Handlers/Neg/NegRm32Handler.cs
index cc44618..901596b 100644
--- a/X86Disassembler/X86/Handlers/Neg/NegRm32Handler.cs
+++ b/X86Disassembler/X86/Handlers/Neg/NegRm32Handler.cs
@@ -32,7 +32,9 @@ public class NegRm32Handler : InstructionHandler
var reg = ModRMDecoder.PeakModRMReg();
- return reg == 3; // 3 = NEG
+ // Only handle when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return reg == 3 && !Decoder.HasOperandSizePrefix(); // 3 = NEG
}
///
diff --git a/X86Disassembler/X86/Handlers/Not/NotRm32Handler.cs b/X86Disassembler/X86/Handlers/Not/NotRm32Handler.cs
index bb7cdb8..5c0a8c0 100644
--- a/X86Disassembler/X86/Handlers/Not/NotRm32Handler.cs
+++ b/X86Disassembler/X86/Handlers/Not/NotRm32Handler.cs
@@ -33,7 +33,9 @@ public class NotRm32Handler : InstructionHandler
var reg = ModRMDecoder.PeakModRMReg();
- return reg == 2; // 2 = NOT
+ // Only handle when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return reg == 2 && !Decoder.HasOperandSizePrefix(); // 2 = NOT
}
///
@@ -55,7 +57,7 @@ public class NotRm32Handler : InstructionHandler
// Read the ModR/M byte
// For NOT r/m32 (0xF7 /2):
// - The r/m field with mod specifies the operand (register or memory)
- var (_, reg, _, operand) = ModRMDecoder.ReadModRM();
+ var (_, _, _, operand) = ModRMDecoder.ReadModRM();
// Set the structured operands
// NOT has only one operand
diff --git a/X86Disassembler/X86/Handlers/Not/NotRm8Handler.cs b/X86Disassembler/X86/Handlers/Not/NotRm8Handler.cs
index b882b40..c17c2b2 100644
--- a/X86Disassembler/X86/Handlers/Not/NotRm8Handler.cs
+++ b/X86Disassembler/X86/Handlers/Not/NotRm8Handler.cs
@@ -55,7 +55,7 @@ public class NotRm8Handler : InstructionHandler
// Read the ModR/M byte
// For NOT r/m8 (0xF6 /2):
// - The r/m field with mod specifies the operand (register or memory)
- var (_, reg, _, operand) = ModRMDecoder.ReadModRM8();
+ var (_, _, _, operand) = ModRMDecoder.ReadModRM8();
// Set the structured operands
// NOT has only one operand
diff --git a/X86Disassembler/X86/Handlers/Or/OrR32Rm32Handler.cs b/X86Disassembler/X86/Handlers/Or/OrR32Rm32Handler.cs
index 8e6fbd0..72edc4f 100644
--- a/X86Disassembler/X86/Handlers/Or/OrR32Rm32Handler.cs
+++ b/X86Disassembler/X86/Handlers/Or/OrR32Rm32Handler.cs
@@ -23,7 +23,9 @@ public class OrR32Rm32Handler : InstructionHandler
/// True if this handler can decode the opcode
public override bool CanHandle(byte opcode)
{
- return opcode == 0x0B;
+ // Only handle opcode 0x0B when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return opcode == 0x0B && !Decoder.HasOperandSizePrefix();
}
///
diff --git a/X86Disassembler/X86/Handlers/Or/OrRm32R32Handler.cs b/X86Disassembler/X86/Handlers/Or/OrRm32R32Handler.cs
index 3d42e31..300206a 100644
--- a/X86Disassembler/X86/Handlers/Or/OrRm32R32Handler.cs
+++ b/X86Disassembler/X86/Handlers/Or/OrRm32R32Handler.cs
@@ -23,7 +23,9 @@ public class OrRm32R32Handler : InstructionHandler
/// True if this handler can decode the opcode
public override bool CanHandle(byte opcode)
{
- return opcode == 0x09;
+ // Only handle opcode 0x09 when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return opcode == 0x09 && !Decoder.HasOperandSizePrefix();
}
///
diff --git a/X86Disassembler/X86/Handlers/Pop/PopRegHandler.cs b/X86Disassembler/X86/Handlers/Pop/PopRegHandler.cs
index e3ab59d..7cea6a3 100644
--- a/X86Disassembler/X86/Handlers/Pop/PopRegHandler.cs
+++ b/X86Disassembler/X86/Handlers/Pop/PopRegHandler.cs
@@ -23,7 +23,9 @@ public class PopRegHandler : InstructionHandler
/// True if this handler can decode the opcode
public override bool CanHandle(byte opcode)
{
- return opcode >= 0x58 && opcode <= 0x5F;
+ // Only handle opcodes 0x58-0x5F when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return opcode >= 0x58 && opcode <= 0x5F && !Decoder.HasOperandSizePrefix();
}
///
diff --git a/X86Disassembler/X86/Handlers/Pop/PopRm32Handler.cs b/X86Disassembler/X86/Handlers/Pop/PopRm32Handler.cs
new file mode 100644
index 0000000..ae09301
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Pop/PopRm32Handler.cs
@@ -0,0 +1,77 @@
+using X86Disassembler.X86.Operands;
+
+namespace X86Disassembler.X86.Handlers.Pop;
+
+///
+/// Handler for POP r/m32 instruction (0x8F /0)
+///
+public class PopRm32Handler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the PopRm32Handler class
+ ///
+ /// The instruction decoder that owns this handler
+ public PopRm32Handler(InstructionDecoder decoder)
+ : base(decoder)
+ {
+ }
+
+ ///
+ /// Checks if this handler can decode the given opcode
+ ///
+ /// The opcode to check
+ /// True if this handler can decode the opcode
+ public override bool CanHandle(byte opcode)
+ {
+ // POP r/m32 is encoded as 8F /0
+ if (opcode != 0x8F)
+ {
+ return false;
+ }
+
+ // Check if we have enough bytes to read the ModR/M byte
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ var reg = ModRMDecoder.PeakModRMReg();
+
+ // POP r/m32 is encoded as 8F /0 (reg field = 0)
+ // Only handle when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return reg == 0 && !Decoder.HasOperandSizePrefix();
+ }
+
+ ///
+ /// Decodes a POP r/m32 instruction
+ ///
+ /// The opcode of the instruction
+ /// The instruction object to populate
+ /// True if the instruction was successfully decoded
+ public override bool Decode(byte opcode, Instruction instruction)
+ {
+ // Set the instruction type
+ instruction.Type = InstructionType.Pop;
+
+ // Check if we have enough bytes for the ModR/M byte
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Read the ModR/M byte
+ // For POP r/m32 (8F /0):
+ // - The r/m field with mod specifies the operand (register or memory)
+ var (_, _, _, operand) = ModRMDecoder.ReadModRM();
+
+ // Set the structured operands
+ // POP has only one operand
+ instruction.StructuredOperands =
+ [
+ operand
+ ];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Push/PushRm32Handler.cs b/X86Disassembler/X86/Handlers/Push/PushRm32Handler.cs
index 8a9a5d0..51301be 100644
--- a/X86Disassembler/X86/Handlers/Push/PushRm32Handler.cs
+++ b/X86Disassembler/X86/Handlers/Push/PushRm32Handler.cs
@@ -38,7 +38,9 @@ public class PushRm32Handler : InstructionHandler
var reg = ModRMDecoder.PeakModRMReg();
// PUSH r/m32 is encoded as FF /6 (reg field = 6)
- return reg == 6;
+ // Only handle when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return reg == 6 && !Decoder.HasOperandSizePrefix();
}
///
diff --git a/X86Disassembler/X86/Handlers/Ret/RetHandler.cs b/X86Disassembler/X86/Handlers/Ret/RetHandler.cs
index f89478d..b985719 100644
--- a/X86Disassembler/X86/Handlers/Ret/RetHandler.cs
+++ b/X86Disassembler/X86/Handlers/Ret/RetHandler.cs
@@ -23,7 +23,9 @@ public class RetHandler : InstructionHandler
/// True if this handler can decode the opcode
public override bool CanHandle(byte opcode)
{
- return opcode == 0xC3;
+ // Only handle opcode 0xC3 when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return opcode == 0xC3 && !Decoder.HasOperandSizePrefix();
}
///
diff --git a/X86Disassembler/X86/Handlers/Ret/RetImmHandler.cs b/X86Disassembler/X86/Handlers/Ret/RetImmHandler.cs
index 1f5b9fa..e5ff54e 100644
--- a/X86Disassembler/X86/Handlers/Ret/RetImmHandler.cs
+++ b/X86Disassembler/X86/Handlers/Ret/RetImmHandler.cs
@@ -23,7 +23,9 @@ public class RetImmHandler : InstructionHandler
/// True if this handler can decode the opcode
public override bool CanHandle(byte opcode)
{
- return opcode == 0xC2;
+ // Only handle opcode 0xC2 when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return opcode == 0xC2 && !Decoder.HasOperandSizePrefix();
}
///
diff --git a/X86Disassembler/X86/Handlers/Sub/SubAlImm8Handler.cs b/X86Disassembler/X86/Handlers/Sub/SubAlImm8Handler.cs
index 624e192..09d8af3 100644
--- a/X86Disassembler/X86/Handlers/Sub/SubAlImm8Handler.cs
+++ b/X86Disassembler/X86/Handlers/Sub/SubAlImm8Handler.cs
@@ -46,7 +46,7 @@ public class SubAlImm8Handler : InstructionHandler
instruction.Type = InstructionType.Sub;
// Create the destination register operand (AL)
- var destinationOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.A, 8);
+ var destinationOperand = OperandFactory.CreateRegisterOperand8(RegisterIndex8.AL);
// Create the source immediate operand
var sourceOperand = OperandFactory.CreateImmediateOperand(imm8, 8);
diff --git a/X86Disassembler/X86/Handlers/Sub/SubR32Rm32Handler.cs b/X86Disassembler/X86/Handlers/Sub/SubR32Rm32Handler.cs
index c1ec14e..f7e1ea3 100644
--- a/X86Disassembler/X86/Handlers/Sub/SubR32Rm32Handler.cs
+++ b/X86Disassembler/X86/Handlers/Sub/SubR32Rm32Handler.cs
@@ -23,7 +23,9 @@ public class SubR32Rm32Handler : InstructionHandler
/// True if this handler can decode the opcode
public override bool CanHandle(byte opcode)
{
- return opcode == 0x2B;
+ // Only handle opcode 0x2B when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return opcode == 0x2B && !Decoder.HasOperandSizePrefix();
}
///
diff --git a/X86Disassembler/X86/Handlers/Sub/SubRm32R32Handler.cs b/X86Disassembler/X86/Handlers/Sub/SubRm32R32Handler.cs
index 58ff242..44c7a52 100644
--- a/X86Disassembler/X86/Handlers/Sub/SubRm32R32Handler.cs
+++ b/X86Disassembler/X86/Handlers/Sub/SubRm32R32Handler.cs
@@ -23,7 +23,9 @@ public class SubRm32R32Handler : InstructionHandler
/// True if this handler can decode the opcode
public override bool CanHandle(byte opcode)
{
- return opcode == 0x29;
+ // Only handle opcode 0x29 when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return opcode == 0x29 && !Decoder.HasOperandSizePrefix();
}
///
diff --git a/X86Disassembler/X86/Handlers/Test/TestRegMemHandler.cs b/X86Disassembler/X86/Handlers/Test/TestRegMemHandler.cs
index 73998e1..732df16 100644
--- a/X86Disassembler/X86/Handlers/Test/TestRegMemHandler.cs
+++ b/X86Disassembler/X86/Handlers/Test/TestRegMemHandler.cs
@@ -23,7 +23,9 @@ public class TestRegMemHandler : InstructionHandler
/// True if this handler can decode the opcode
public override bool CanHandle(byte opcode)
{
- return opcode == 0x85;
+ // Only handle opcode 0x85 when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return opcode == 0x85 && !Decoder.HasOperandSizePrefix();
}
///
diff --git a/X86Disassembler/X86/Handlers/Xchg/XchgEaxRegHandler.cs b/X86Disassembler/X86/Handlers/Xchg/XchgEaxRegHandler.cs
index 32ea7ea..b97651e 100644
--- a/X86Disassembler/X86/Handlers/Xchg/XchgEaxRegHandler.cs
+++ b/X86Disassembler/X86/Handlers/Xchg/XchgEaxRegHandler.cs
@@ -23,40 +23,9 @@ public class XchgEaxRegHandler : InstructionHandler
/// True if this handler can decode the opcode
public override bool CanHandle(byte opcode)
{
- return opcode >= 0x91 && opcode <= 0x97;
- }
-
- ///
- /// Maps the register index from the opcode to the RegisterIndex enum value expected by tests
- ///
- /// The register index from the opcode (0-7)
- /// The corresponding RegisterIndex enum value
- private RegisterIndex MapOpcodeToRegisterIndex(int opcodeRegIndex)
- {
- // The mapping from opcode register index to RegisterIndex enum is:
- // 0 -> A (EAX)
- // 1 -> C (ECX)
- // 2 -> D (EDX)
- // 3 -> B (EBX)
- // 4 -> Sp (ESP)
- // 5 -> Bp (EBP)
- // 6 -> Si (ESI)
- // 7 -> Di (EDI)
-
- // This mapping is based on the x86 instruction encoding
- // but we need to map to the RegisterIndex enum values that the tests expect
- return opcodeRegIndex switch
- {
- 0 => RegisterIndex.A, // EAX
- 1 => RegisterIndex.C, // ECX
- 2 => RegisterIndex.D, // EDX
- 3 => RegisterIndex.B, // EBX
- 4 => RegisterIndex.Sp, // ESP
- 5 => RegisterIndex.Bp, // EBP
- 6 => RegisterIndex.Si, // ESI
- 7 => RegisterIndex.Di, // EDI
- _ => RegisterIndex.A // Default case, should never happen
- };
+ // Only handle opcodes 0x91-0x97 when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return opcode >= 0x91 && opcode <= 0x97 && !Decoder.HasOperandSizePrefix();
}
///
@@ -71,10 +40,7 @@ public class XchgEaxRegHandler : InstructionHandler
instruction.Type = InstructionType.Xchg;
// Register is encoded in the low 3 bits of the opcode
- int opcodeRegIndex = opcode & 0x07;
-
- // Map the opcode register index to the RegisterIndex enum value
- RegisterIndex reg = MapOpcodeToRegisterIndex(opcodeRegIndex);
+ RegisterIndex reg = (RegisterIndex)(opcode & 0x07);
// Create the register operands
var eaxOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.A);
diff --git a/X86Disassembler/X86/Handlers/Xor/XorAlImmHandler.cs b/X86Disassembler/X86/Handlers/Xor/XorAlImmHandler.cs
index ed26ecb..94d3395 100644
--- a/X86Disassembler/X86/Handlers/Xor/XorAlImmHandler.cs
+++ b/X86Disassembler/X86/Handlers/Xor/XorAlImmHandler.cs
@@ -46,7 +46,7 @@ public class XorAlImmHandler : InstructionHandler
byte imm8 = Decoder.ReadByte();
// Create the register operand for AL
- var alOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.A, 8);
+ var alOperand = OperandFactory.CreateRegisterOperand8(RegisterIndex8.AL);
// Create the immediate operand
var immOperand = OperandFactory.CreateImmediateOperand(imm8, 8);
diff --git a/X86Disassembler/X86/Handlers/Xor/XorMemRegHandler.cs b/X86Disassembler/X86/Handlers/Xor/XorMemRegHandler.cs
index f19c75f..adc0335 100644
--- a/X86Disassembler/X86/Handlers/Xor/XorMemRegHandler.cs
+++ b/X86Disassembler/X86/Handlers/Xor/XorMemRegHandler.cs
@@ -23,7 +23,9 @@ public class XorMemRegHandler : InstructionHandler
/// True if this handler can decode the opcode
public override bool CanHandle(byte opcode)
{
- return opcode == 0x31;
+ // Only handle opcode 0x31 when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return opcode == 0x31 && !Decoder.HasOperandSizePrefix();
}
///
diff --git a/X86Disassembler/X86/Handlers/Xor/XorRegMemHandler.cs b/X86Disassembler/X86/Handlers/Xor/XorRegMemHandler.cs
index 4a7958a..cd3825b 100644
--- a/X86Disassembler/X86/Handlers/Xor/XorRegMemHandler.cs
+++ b/X86Disassembler/X86/Handlers/Xor/XorRegMemHandler.cs
@@ -25,7 +25,9 @@ public class XorRegMemHandler : InstructionHandler
/// True if this handler can decode the opcode
public override bool CanHandle(byte opcode)
{
- return opcode == 0x33;
+ // Only handle opcode 0x33 when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return opcode == 0x33 && !Decoder.HasOperandSizePrefix();
}
///
diff --git a/X86Disassembler/X86/InstructionDecoder.cs b/X86Disassembler/X86/InstructionDecoder.cs
index b1465f0..8c06e67 100644
--- a/X86Disassembler/X86/InstructionDecoder.cs
+++ b/X86Disassembler/X86/InstructionDecoder.cs
@@ -1,4 +1,3 @@
-using System.Diagnostics;
using System.Diagnostics.Contracts;
namespace X86Disassembler.X86;
@@ -6,6 +5,11 @@ namespace X86Disassembler.X86;
using Handlers;
using Operands;
+public static class Printer
+{
+ public static Action? WriteLine;
+}
+
///
/// Decodes x86 instructions from a byte buffer
///
@@ -83,44 +87,19 @@ public class InstructionDecoder
}
}
- // If only prefixes were found, return a prefix-only instruction
+ // If only prefixes were found and we're at the end of the buffer, return null
if (_position > startPosition && !CanReadByte())
- {
- // Check for segment override prefix
- if (_prefixDecoder.HasSegmentOverridePrefix())
- {
- // Set the instruction type to Rep for segment override prefixes when they appear alone
- // This matches the expected behavior in the tests
- instruction.Type = InstructionType.Rep;
- }
- else
- {
- // Set the instruction type to Unknown for other prefixes
- instruction.Type = InstructionType.Unknown;
- }
-
- // Add segment override prefix as an operand if present
- string segmentOverride = _prefixDecoder.GetSegmentOverride();
- if (!string.IsNullOrEmpty(segmentOverride))
- {
- // Could create a special operand for segment overrides if needed
- }
-
- return instruction;
- }
-
- if (!CanReadByte())
{
return null;
}
-
+
// Read the opcode
byte opcode = ReadByte();
// Get a handler for the opcode
var handler = _handlerFactory.GetHandler(opcode);
- Debug.WriteLine($"Resolved handler {handler?.GetType().Name}");
+ Printer.WriteLine?.Invoke($"Resolved handler {handler?.GetType().Name}");
bool handlerSuccess = false;
@@ -326,6 +305,20 @@ public class InstructionDecoder
return _codeBuffer[_position];
}
+ ///
+ /// Peaks a byte from the buffer without adjusting position
+ ///
+ /// The byte peaked
+ public (byte b1, byte b2) PeakTwoBytes()
+ {
+ if (_position + 1 >= _length)
+ {
+ return (0,0);
+ }
+
+ return (_codeBuffer[_position], _codeBuffer[_position + 1]);
+ }
+
///
/// Peaks a byte from the buffer at the specified offset from current position without adjusting position
///
diff --git a/X86Disassembler/X86/ModRMDecoder.cs b/X86Disassembler/X86/ModRMDecoder.cs
index a7b11cf..b82da19 100644
--- a/X86Disassembler/X86/ModRMDecoder.cs
+++ b/X86Disassembler/X86/ModRMDecoder.cs
@@ -185,6 +185,18 @@ public class ModRMDecoder
return regIndex;
}
+ ///
+ /// Extracts modRM reg field
+ ///
+ /// A reg from the ModR/M byte
+ public static byte GetRegFromModRM(byte modRm)
+ {
+ // Extract fields from ModR/M byte
+ byte regIndex = (byte)((modRm & Constants.REG_MASK) >> 3); // Middle 3 bits (bits 3-5)
+
+ return regIndex;
+ }
+
///
/// Reads and decodes a ModR/M byte for standard 32-bit operands
///
diff --git a/X86Disassembler/X86/Operands/DisplacementMemoryOperand.cs b/X86Disassembler/X86/Operands/DisplacementMemoryOperand.cs
index 9a43955..5390ab4 100644
--- a/X86Disassembler/X86/Operands/DisplacementMemoryOperand.cs
+++ b/X86Disassembler/X86/Operands/DisplacementMemoryOperand.cs
@@ -39,26 +39,28 @@ public class DisplacementMemoryOperand : MemoryOperand
var registerName = RegisterMapper.GetRegisterName(BaseRegister, 32);
// Format the displacement value
- string formattedDisplacement;
- string sign;
-
- // Handle positive and negative displacements
- if (Displacement >= 0)
+ long absDisplacement = Math.Abs(Displacement);
+ string sign = Displacement >= 0 ? "+" : "-";
+ string format;
+
+ if (absDisplacement == 0)
{
- sign = "+";
- formattedDisplacement = Displacement < 256
- ? $"0x{Displacement:X2}"
- : $"0x{Displacement:X8}";
+ format = "X2";
+ }
+ else if (absDisplacement <= 0xFF)
+ {
+ format = "X2";
+ }
+ else if (absDisplacement <= 0xFFFF)
+ {
+ format = "X4";
}
else
{
- sign = "-";
- // For negative values, take the absolute value for display
- var absDisplacement = Math.Abs(Displacement);
- formattedDisplacement = absDisplacement < 256
- ? $"0x{absDisplacement:X2}"
- : $"0x{absDisplacement:X8}";
+ format = "X8";
}
+
+ string formattedDisplacement = $"0x{absDisplacement.ToString(format)}";
return $"{GetSizePrefix()}[{registerName}{sign}{formattedDisplacement}]";
}
diff --git a/X86Disassembler/X86/Operands/ImmediateOperand.cs b/X86Disassembler/X86/Operands/ImmediateOperand.cs
index 605e78d..ac48a75 100644
--- a/X86Disassembler/X86/Operands/ImmediateOperand.cs
+++ b/X86Disassembler/X86/Operands/ImmediateOperand.cs
@@ -46,42 +46,25 @@ public class ImmediateOperand : Operand
_ => Value
};
- // For 8-bit immediate values, always use at least 2 digits
- if (Size == 8)
+ string format;
+
+ if (maskedValue == 0)
{
- return $"0x{maskedValue:X2}";
+ format = "X2";
}
-
- // For 16-bit immediate values, format depends on the value
- if (Size == 16)
+ else if (maskedValue <= 0xFF)
{
- // For small values (< 256), show without leading zeros
- if (maskedValue < 256)
- {
- return $"0x{maskedValue:X}";
- }
-
- // For larger values, use at least 4 digits
- return $"0x{maskedValue:X4}";
+ format = "X2";
}
-
- // For 32-bit immediate values, format depends on the instruction context
- if (Size == 32)
+ else if (maskedValue <= 0xFFFF)
{
- // For small values (0), always show as 0x00
- if (maskedValue == 0)
- {
- return "0x00";
- }
-
- // For other small values (< 256), show as 0xNN
- if (maskedValue < 256)
- {
- return $"0x{maskedValue:X2}";
- }
+ format = "X4";
}
-
- // For larger 32-bit values, show the full 32-bit representation
- return $"0x{maskedValue:X8}";
+ else
+ {
+ format = "X8";
+ }
+
+ return $"0x{maskedValue.ToString(format)}";
}
}
diff --git a/X86DisassemblerTests/InstructionTests/DataTransferInstructionTests.cs b/X86DisassemblerTests/InstructionTests/DataTransferInstructionTests.cs
index 1529fe9..dd078f6 100644
--- a/X86DisassemblerTests/InstructionTests/DataTransferInstructionTests.cs
+++ b/X86DisassemblerTests/InstructionTests/DataTransferInstructionTests.cs
@@ -148,9 +148,9 @@ public class DataTransferInstructionTests
// Check the first operand (AL)
var alOperand = instruction.StructuredOperands[0];
- Assert.IsType(alOperand);
- var alRegisterOperand = (RegisterOperand)alOperand;
- Assert.Equal(RegisterIndex.A, alRegisterOperand.Register);
+ Assert.IsType(alOperand);
+ var alRegisterOperand = (Register8Operand)alOperand;
+ Assert.Equal(RegisterIndex8.AL, alRegisterOperand.Register);
Assert.Equal(8, alRegisterOperand.Size); // Validate that it's an 8-bit register (AL)
// Check the second operand (Immediate)
diff --git a/X86DisassemblerTests/InstructionTests/PushInstructionTests.cs b/X86DisassemblerTests/InstructionTests/PushInstructionTests.cs
new file mode 100644
index 0000000..78b0c3b
--- /dev/null
+++ b/X86DisassemblerTests/InstructionTests/PushInstructionTests.cs
@@ -0,0 +1,97 @@
+using X86Disassembler.X86;
+using X86Disassembler.X86.Operands;
+
+namespace X86DisassemblerTests.InstructionTests;
+
+///
+/// Tests for PUSH instruction handlers
+///
+public class PushInstructionTests
+{
+ ///
+ /// Tests the PUSH imm32 instruction (0x68)
+ ///
+ [Fact]
+ public void TestPushImm32()
+ {
+ // Arrange
+ byte[] code = { 0x68, 0x78, 0x56, 0x34, 0x12 }; // PUSH 0x12345678
+
+ // Act
+ Disassembler disassembler = new Disassembler(code, 0x1000);
+ var instructions = disassembler.Disassemble();
+
+ // Assert
+ Assert.Single(instructions);
+ var instruction = instructions[0];
+ Assert.Equal(InstructionType.Push, instruction.Type);
+
+ // Check that we have one operand
+ Assert.Single(instruction.StructuredOperands);
+
+ // Check the operand (immediate value)
+ var operand = instruction.StructuredOperands[0];
+ Assert.IsType(operand);
+ var immOperand = (ImmediateOperand)operand;
+ Assert.Equal(0x12345678u, immOperand.Value);
+ Assert.Equal(32, immOperand.Size);
+ }
+
+ ///
+ /// Tests the PUSH imm16 instruction with operand size prefix (0x66 0x68)
+ ///
+ [Fact]
+ public void TestPushImm16WithOperandSizePrefix()
+ {
+ // Arrange
+ byte[] code = { 0x66, 0x68, 0x78, 0x56 }; // PUSH 0x5678 (with operand size prefix)
+
+ // Act
+ Disassembler disassembler = new Disassembler(code, 0x1000);
+ var instructions = disassembler.Disassemble();
+
+ // Assert
+ Assert.Single(instructions);
+ var instruction = instructions[0];
+ Assert.Equal(InstructionType.Push, instruction.Type);
+
+ // Check that we have one operand
+ Assert.Single(instruction.StructuredOperands);
+
+ // Check the operand (immediate value)
+ var operand = instruction.StructuredOperands[0];
+ Assert.IsType(operand);
+ var immOperand = (ImmediateOperand)operand;
+ Assert.Equal(0x5678u, immOperand.Value);
+ Assert.Equal(16, immOperand.Size);
+ }
+
+ ///
+ /// Tests the PUSH imm8 instruction (0x6A)
+ ///
+ [Fact]
+ public void TestPushImm8()
+ {
+ // Arrange
+ byte[] code = { 0x6A, 0x42 }; // PUSH 0x42
+
+ // Act
+ Disassembler disassembler = new Disassembler(code, 0x1000);
+ var instructions = disassembler.Disassemble();
+
+ // Assert
+ Assert.Single(instructions);
+ var instruction = instructions[0];
+ Assert.Equal(InstructionType.Push, instruction.Type);
+
+ // Check that we have one operand
+ Assert.Single(instruction.StructuredOperands);
+
+ // Check the operand (immediate value)
+ var operand = instruction.StructuredOperands[0];
+ Assert.IsType(operand);
+ var immOperand = (ImmediateOperand)operand;
+ Assert.Equal(0x42u, immOperand.Value);
+ Assert.Equal(8, immOperand.Size);
+ }
+}
diff --git a/X86DisassemblerTests/InstructionTests/SegmentOverrideTests.cs b/X86DisassemblerTests/InstructionTests/SegmentOverrideTests.cs
index 29edb4c..35d7414 100644
--- a/X86DisassemblerTests/InstructionTests/SegmentOverrideTests.cs
+++ b/X86DisassemblerTests/InstructionTests/SegmentOverrideTests.cs
@@ -245,27 +245,6 @@ public class SegmentOverrideTests
Assert.Equal(-4, memoryOperand.Displacement);
}
- ///
- /// Tests that the FS segment override prefix (0x64) is correctly recognized when it's the only byte
- ///
- [Fact]
- public void FsSegmentOverride_Alone_IsRecognized()
- {
- // Arrange
- // Just the FS segment override prefix (0x64)
- byte[] codeBuffer = new byte[] { 0x64 };
- var disassembler = new Disassembler(codeBuffer, 0);
-
- // Act
- var instructions = disassembler.Disassemble();
-
- // Assert
- Assert.Single(instructions);
- var instruction = instructions[0];
- Assert.NotNull(instruction);
- Assert.Equal(InstructionType.Rep, instruction.Type);
- }
-
///
/// Tests segment override with a complex addressing mode
///
diff --git a/X86DisassemblerTests/RawFromFileDisassemblyTests.cs b/X86DisassemblerTests/RawFromFileDisassemblyTests.cs
index c8e02e1..91d92f6 100644
--- a/X86DisassemblerTests/RawFromFileDisassemblyTests.cs
+++ b/X86DisassemblerTests/RawFromFileDisassemblyTests.cs
@@ -12,6 +12,8 @@ public class RawFromFileDisassemblyTests(ITestOutputHelper output)
[ClassData(typeof(TestDataProvider))]
public void RunTests(string f, int idx, TestFromFileEntry test)
{
+ Printer.WriteLine = output.WriteLine;
+
// Convert hex string to byte array
byte[] code = HexStringToByteArray(test.RawBytes);
diff --git a/X86DisassemblerTests/TestData/adc_tests.csv b/X86DisassemblerTests/TestData/adc_tests.csv
index 7d98d86..e16e3ea 100644
--- a/X86DisassemblerTests/TestData/adc_tests.csv
+++ b/X86DisassemblerTests/TestData/adc_tests.csv
@@ -2,57 +2,26 @@
# Format: RawBytes;Instructions
RawBytes;Instructions
-# ADC r/m8, imm8 (opcode 80 /2)
-80D042;[{ "Type": "Adc", "Operands": ["al", "0x42"] }]
-80D342;[{ "Type": "Adc", "Operands": ["bl", "0x42"] }]
-80D142;[{ "Type": "Adc", "Operands": ["cl", "0x42"] }]
-80D242;[{ "Type": "Adc", "Operands": ["dl", "0x42"] }]
-
-# ADC AL, imm8 (opcode 14)
-1442;[{ "Type": "Adc", "Operands": ["al", "0x42"] }]
-
-# ADC r/m32, imm32 (opcode 81 /2)
-81D078563412;[{ "Type": "Adc", "Operands": ["eax", "0x12345678"] }]
-81D378563412;[{ "Type": "Adc", "Operands": ["ebx", "0x12345678"] }]
-81D178563412;[{ "Type": "Adc", "Operands": ["ecx", "0x12345678"] }]
-81D278563412;[{ "Type": "Adc", "Operands": ["edx", "0x12345678"] }]
-
-# ADC EAX, imm32 (opcode 15)
-1578563412;[{ "Type": "Adc", "Operands": ["eax", "0x12345678"] }]
-
-# ADC r/m32, imm8 (opcode 83 /2)
-83D042;[{ "Type": "Adc", "Operands": ["eax", "0x42"] }]
-83D342;[{ "Type": "Adc", "Operands": ["ebx", "0x42"] }]
-83D142;[{ "Type": "Adc", "Operands": ["ecx", "0x42"] }]
-83D242;[{ "Type": "Adc", "Operands": ["edx", "0x42"] }]
-
-# ADC r/m8, r8 (opcode 10)
-10C3;[{ "Type": "Adc", "Operands": ["bl", "al"] }]
-10D9;[{ "Type": "Adc", "Operands": ["cl", "bl"] }]
-10E2;[{ "Type": "Adc", "Operands": ["dl", "ah"] }]
-
-# ADC r8, r/m8 (opcode 12)
-12C3;[{ "Type": "Adc", "Operands": ["al", "bl"] }]
-12D9;[{ "Type": "Adc", "Operands": ["bl", "cl"] }]
-12E2;[{ "Type": "Adc", "Operands": ["ah", "dl"] }]
-
-# ADC r/m32, r32 (opcode 11)
+14AA;[{ "Type": "Adc", "Operands": ["al", "0xAA"] }]
+80D1AA;[{ "Type": "Adc", "Operands": ["cl", "0xAA"] }]
+8010AA;[{ "Type": "Adc", "Operands": ["byte ptr [eax]", "0xAA"] }]
+805310AA;[{ "Type": "Adc", "Operands": ["byte ptr [ebx+0x10]", "0xAA"] }]
+10D8;[{ "Type": "Adc", "Operands": ["al", "bl"] }]
+1018;[{ "Type": "Adc", "Operands": ["byte ptr [eax]", "bl"] }]
+1218;[{ "Type": "Adc", "Operands": ["bl", "byte ptr [eax]"] }]
+801488AA;[{ "Type": "Adc", "Operands": ["byte ptr [eax+ecx*4]", "0xAA"] }]
+6681D1AA00;[{ "Type": "Adc", "Operands": ["cx", "0xAA"] }]
+668110AA00;[{ "Type": "Adc", "Operands": ["word ptr [eax]", "0xAA"] }]
+66815310AA00;[{ "Type": "Adc", "Operands": ["word ptr [ebx+0x10]", "0xAA"] }]
+6611D8;[{ "Type": "Adc", "Operands": ["ax", "bx"] }]
+661118;[{ "Type": "Adc", "Operands": ["word ptr [eax]", "bx"] }]
+661318;[{ "Type": "Adc", "Operands": ["bx", "word ptr [eax]"] }]
+66811488AA00;[{ "Type": "Adc", "Operands": ["word ptr [eax+ecx*4]", "0xAA"] }]
+15AAAA0000;[{ "Type": "Adc", "Operands": ["eax", "0xAAAA"] }]
+81D1AAAA0000;[{ "Type": "Adc", "Operands": ["ecx", "0xAAAA"] }]
+8110AAAA0000;[{ "Type": "Adc", "Operands": ["dword ptr [eax]", "0xAAAA"] }]
+815310AAAA0000;[{ "Type": "Adc", "Operands": ["dword ptr [ebx+0x10]", "0xAAAA"] }]
11D8;[{ "Type": "Adc", "Operands": ["eax", "ebx"] }]
-11CA;[{ "Type": "Adc", "Operands": ["edx", "ecx"] }]
-11E5;[{ "Type": "Adc", "Operands": ["ebp", "esp"] }]
-114B10;[{ "Type": "Adc", "Operands": ["dword ptr [ebx+0x10]", "ecx"] }]
-
-# ADC r32, r/m32 (opcode 13)
-13D8;[{ "Type": "Adc", "Operands": ["ebx", "eax"] }]
-13CA;[{ "Type": "Adc", "Operands": ["ecx", "edx"] }]
-13E5;[{ "Type": "Adc", "Operands": ["esp", "ebp"] }]
-134B10;[{ "Type": "Adc", "Operands": ["ecx", "dword ptr [ebx+0x10]"] }]
-
-# ADC with memory operands
-8014251000000042;[{ "Type": "Adc", "Operands": ["byte ptr [0x10]", "0x42"] }]
-8114251000000078563412;[{ "Type": "Adc", "Operands": ["dword ptr [0x10]", "0x12345678"] }]
-8314251000000042;[{ "Type": "Adc", "Operands": ["dword ptr [0x10]", "0x42"] }]
-1004251000000000;[{ "Type": "Adc", "Operands": ["byte ptr [0x10]", "al"] }]
-1204251000000000;[{ "Type": "Adc", "Operands": ["al", "byte ptr [0x10]"] }]
-1104251000000000;[{ "Type": "Adc", "Operands": ["dword ptr [0x10]", "eax"] }]
-1304251000000000;[{ "Type": "Adc", "Operands": ["eax", "dword ptr [0x10]"] }]
+1118;[{ "Type": "Adc", "Operands": ["dword ptr [eax]", "ebx"] }]
+1318;[{ "Type": "Adc", "Operands": ["ebx", "dword ptr [eax]"] }]
+811488AAAA0000;[{ "Type": "Adc", "Operands": ["dword ptr [eax+ecx*4]", "0xAAAA"] }]
\ No newline at end of file
diff --git a/X86DisassemblerTests/TestData/add_tests.csv b/X86DisassemblerTests/TestData/add_tests.csv
index 14e0cbf..0e505b8 100644
--- a/X86DisassemblerTests/TestData/add_tests.csv
+++ b/X86DisassemblerTests/TestData/add_tests.csv
@@ -1,60 +1,36 @@
-# ADD instruction tests
# Format: RawBytes;Instructions
RawBytes;Instructions
+# 8-bit ADD
+04AA;[{ "Type": "Add", "Operands": ["al", "0xAA"] }]
+80C1AA;[{ "Type": "Add", "Operands": ["cl", "0xAA"] }]
+8000AA;[{ "Type": "Add", "Operands": ["byte ptr [eax]", "0xAA"] }]
+805310AA;[{ "Type": "Add", "Operands": ["byte ptr [ebx+0x10]", "0xAA"] }]
+00D8;[{ "Type": "Add", "Operands": ["al", "bl"] }]
+0018;[{ "Type": "Add", "Operands": ["byte ptr [eax]", "bl"] }]
+0218;[{ "Type": "Add", "Operands": ["bl", "byte ptr [eax]"] }]
+800488AA;[{ "Type": "Add", "Operands": ["byte ptr [eax+ecx*4]", "0xAA"] }]
-# ADD r/m8, imm8 (opcode 80 /0)
-80C042;[{ "Type": "Add", "Operands": ["al", "0x42"] }]
-80C342;[{ "Type": "Add", "Operands": ["bl", "0x42"] }]
-80C142;[{ "Type": "Add", "Operands": ["cl", "0x42"] }]
-80C242;[{ "Type": "Add", "Operands": ["dl", "0x42"] }]
+# 16-bit ADD (with 66 prefix)
+6605AA00;[{ "Type": "Add", "Operands": ["ax", "0xAA"] }]
+6681C1AA00;[{ "Type": "Add", "Operands": ["cx", "0xAA"] }]
+668100AA00;[{ "Type": "Add", "Operands": ["word ptr [eax]", "0xAA"] }]
+66814310AA00;[{ "Type": "Add", "Operands": ["word ptr [ebx+0x10]", "0xAA"] }]
+6601D8;[{ "Type": "Add", "Operands": ["ax", "bx"] }]
+660118;[{ "Type": "Add", "Operands": ["word ptr [eax]", "bx"] }]
+660318;[{ "Type": "Add", "Operands": ["bx", "word ptr [eax]"] }]
+66810488AA00;[{ "Type": "Add", "Operands": ["word ptr [eax+ecx*4]", "0xAA"] }]
-# ADD AL, imm8 (opcode 04)
-0442;[{ "Type": "Add", "Operands": ["al", "0x42"] }]
-
-# ADD r/m32, imm32 (opcode 81 /0)
-81C078563412;[{ "Type": "Add", "Operands": ["eax", "0x12345678"] }]
-81C378563412;[{ "Type": "Add", "Operands": ["ebx", "0x12345678"] }]
-81C178563412;[{ "Type": "Add", "Operands": ["ecx", "0x12345678"] }]
-81C278563412;[{ "Type": "Add", "Operands": ["edx", "0x12345678"] }]
-
-# ADD EAX, imm32 (opcode 05)
-0578563412;[{ "Type": "Add", "Operands": ["eax", "0x12345678"] }]
-
-# ADD r/m32, imm8 (opcode 83 /0) with sign extension
-83C042;[{ "Type": "Add", "Operands": ["eax", "0x42"] }]
-83C342;[{ "Type": "Add", "Operands": ["ebx", "0x42"] }]
-83C142;[{ "Type": "Add", "Operands": ["ecx", "0x42"] }]
-83C242;[{ "Type": "Add", "Operands": ["edx", "0x42"] }]
-83C0FF;[{ "Type": "Add", "Operands": ["eax", "0xFFFFFFFF"] }]
-83C3FF;[{ "Type": "Add", "Operands": ["ebx", "0xFFFFFFFF"] }]
-
-# ADD r/m8, r8 (opcode 00)
-00C3;[{ "Type": "Add", "Operands": ["bl", "al"] }]
-00D9;[{ "Type": "Add", "Operands": ["cl", "bl"] }]
-00E2;[{ "Type": "Add", "Operands": ["dl", "ah"] }]
-
-# ADD r8, r/m8 (opcode 02)
-02C3;[{ "Type": "Add", "Operands": ["al", "bl"] }]
-02D9;[{ "Type": "Add", "Operands": ["bl", "cl"] }]
-02E2;[{ "Type": "Add", "Operands": ["ah", "dl"] }]
-
-# ADD r/m32, r32 (opcode 01)
+# 32-bit ADD
+05AA000000;[{ "Type": "Add", "Operands": ["eax", "0xAA"] }]
+81C1AA000000;[{ "Type": "Add", "Operands": ["ecx", "0xAA"] }]
+8100AA000000;[{ "Type": "Add", "Operands": ["dword ptr [eax]", "0xAA"] }]
+814310AA000000;[{ "Type": "Add", "Operands": ["dword ptr [ebx+0x10]", "0xAA"] }]
01D8;[{ "Type": "Add", "Operands": ["eax", "ebx"] }]
-01CA;[{ "Type": "Add", "Operands": ["edx", "ecx"] }]
-01E5;[{ "Type": "Add", "Operands": ["ebp", "esp"] }]
-014B10;[{ "Type": "Add", "Operands": ["dword ptr [ebx+0x10]", "ecx"] }]
+0118;[{ "Type": "Add", "Operands": ["dword ptr [eax]", "ebx"] }]
+0318;[{ "Type": "Add", "Operands": ["ebx", "dword ptr [eax]"] }]
+810488AA000000;[{ "Type": "Add", "Operands": ["dword ptr [eax+ecx*4]", "0xAA"] }]
-# ADD r32, r/m32 (opcode 03)
-03D8;[{ "Type": "Add", "Operands": ["ebx", "eax"] }]
-03CA;[{ "Type": "Add", "Operands": ["ecx", "edx"] }]
-03E5;[{ "Type": "Add", "Operands": ["esp", "ebp"] }]
-034B10;[{ "Type": "Add", "Operands": ["ecx", "dword ptr [ebx+0x10]"] }]
-
-# ADD with memory operands
-8004251000000042;[{ "Type": "Add", "Operands": ["byte ptr [0x10]", "0x42"] }]
-8104251000000078563412;[{ "Type": "Add", "Operands": ["dword ptr [0x10]", "0x12345678"] }]
-8304251000000042;[{ "Type": "Add", "Operands": ["dword ptr [0x10]", "0x42"] }]
-00042510000000;[{ "Type": "Add", "Operands": ["byte ptr [0x10]", "al"] }]
-02042510000000;[{ "Type": "Add", "Operands": ["al", "byte ptr [0x10]"] }]
-01042510000000;[{ "Type": "Add", "Operands": ["dword ptr [0x10]", "eax"] }]
-03042510000000;[{ "Type": "Add", "Operands": ["eax", "dword ptr [0x10]"] }]
+# Mixed addressing modes
+00A314285600;[{ "Type": "Add", "Operands": ["byte ptr [ebx+0x562814]", "ah"] }]
+6601B310203040;[{ "Type": "Add", "Operands": ["si", "word ptr [ebx+0x40302010]"] }]
+030C8D10203040;[{ "Type": "Add", "Operands": ["ecx", "dword ptr [ebp*4+0x40302010]"] }]
\ No newline at end of file
diff --git a/X86DisassemblerTests/TestData/and_tests.csv b/X86DisassemblerTests/TestData/and_tests.csv
index 949721d..f439492 100644
--- a/X86DisassemblerTests/TestData/and_tests.csv
+++ b/X86DisassemblerTests/TestData/and_tests.csv
@@ -1,58 +1,42 @@
-# AND instruction tests
# Format: RawBytes;Instructions
RawBytes;Instructions
+# 8-bit AND
+24AA;[{ "Type": "And", "Operands": ["al", "0xAA"] }]
+# Alternate encoding
+80E0AA;[{ "Type": "And", "Operands": ["al", "0xAA"] }]
+80E1AA;[{ "Type": "And", "Operands": ["cl", "0xAA"] }]
+8020AA;[{ "Type": "And", "Operands": ["byte ptr [eax]", "0xAA"] }]
+806310AA;[{ "Type": "And", "Operands": ["byte ptr [ebx+0x10]", "0xAA"] }]
+20D8;[{ "Type": "And", "Operands": ["al", "bl"] }]
+2018;[{ "Type": "And", "Operands": ["byte ptr [eax]", "bl"] }]
+2218;[{ "Type": "And", "Operands": ["bl", "byte ptr [eax]"] }]
+800488AA;[{ "Type": "And", "Operands": ["byte ptr [eax+ecx*4]", "0xAA"] }]
-# AND r/m8, imm8 (opcode 80 /4)
-80E042;[{ "Type": "And", "Operands": ["al", "0x42"] }]
-80E342;[{ "Type": "And", "Operands": ["bl", "0x42"] }]
-80E142;[{ "Type": "And", "Operands": ["cl", "0x42"] }]
-80E242;[{ "Type": "And", "Operands": ["dl", "0x42"] }]
+# 16-bit AND (with 66 prefix)
+6625AA00;[{ "Type": "And", "Operands": ["ax", "0xAA"] }]
+# Alternate encoding
+6681E0AA00;[{ "Type": "And", "Operands": ["ax", "0xAA"] }]
+6681E1AA00;[{ "Type": "And", "Operands": ["cx", "0xAA"] }]
+668120AA00;[{ "Type": "And", "Operands": ["word ptr [eax]", "0xAA"] }]
+66816310AA00;[{ "Type": "And", "Operands": ["word ptr [ebx+0x10]", "0xAA"] }]
+6621D8;[{ "Type": "And", "Operands": ["ax", "bx"] }]
+662118;[{ "Type": "And", "Operands": ["word ptr [eax]", "bx"] }]
+662318;[{ "Type": "And", "Operands": ["bx", "word ptr [eax]"] }]
+66810488AA00;[{ "Type": "And", "Operands": ["word ptr [eax+ecx*4]", "0xAA"] }]
-# AND AL, imm8 (opcode 24)
-2442;[{ "Type": "And", "Operands": ["al", "0x42"] }]
-
-# AND r/m32, imm32 (opcode 81 /4)
-81E078563412;[{ "Type": "And", "Operands": ["eax", "0x12345678"] }]
-81E378563412;[{ "Type": "And", "Operands": ["ebx", "0x12345678"] }]
-81E178563412;[{ "Type": "And", "Operands": ["ecx", "0x12345678"] }]
-81E278563412;[{ "Type": "And", "Operands": ["edx", "0x12345678"] }]
-
-# AND EAX, imm32 (opcode 25)
-2578563412;[{ "Type": "And", "Operands": ["eax", "0x12345678"] }]
-
-# AND r/m32, imm8 (opcode 83 /4)
-83E042;[{ "Type": "And", "Operands": ["eax", "0x42"] }]
-83E342;[{ "Type": "And", "Operands": ["ebx", "0x42"] }]
-83E142;[{ "Type": "And", "Operands": ["ecx", "0x42"] }]
-83E242;[{ "Type": "And", "Operands": ["edx", "0x42"] }]
-
-# AND r/m8, r8 (opcode 20)
-20C3;[{ "Type": "And", "Operands": ["bl", "al"] }]
-20D9;[{ "Type": "And", "Operands": ["cl", "bl"] }]
-20E2;[{ "Type": "And", "Operands": ["dl", "ah"] }]
-
-# AND r8, r/m8 (opcode 22)
-22C3;[{ "Type": "And", "Operands": ["al", "bl"] }]
-22D9;[{ "Type": "And", "Operands": ["bl", "cl"] }]
-22E2;[{ "Type": "And", "Operands": ["ah", "dl"] }]
-
-# AND r/m32, r32 (opcode 21)
+# 32-bit AND
+25AA000000;[{ "Type": "And", "Operands": ["eax", "0xAA"] }]
+# Alternate encoding
+81E0AA000000;[{ "Type": "And", "Operands": ["eax", "0xAA"] }]
+81E1AA000000;[{ "Type": "And", "Operands": ["ecx", "0xAA"] }]
+8120AA000000;[{ "Type": "And", "Operands": ["dword ptr [eax]", "0xAA"] }]
+816310AA000000;[{ "Type": "And", "Operands": ["dword ptr [ebx+0x10]", "0xAA"] }]
21D8;[{ "Type": "And", "Operands": ["eax", "ebx"] }]
-21CA;[{ "Type": "And", "Operands": ["edx", "ecx"] }]
-21E5;[{ "Type": "And", "Operands": ["ebp", "esp"] }]
-214B10;[{ "Type": "And", "Operands": ["dword ptr [ebx+0x10]", "ecx"] }]
+2118;[{ "Type": "And", "Operands": ["dword ptr [eax]", "ebx"] }]
+2318;[{ "Type": "And", "Operands": ["ebx", "dword ptr [eax]"] }]
+810488AA000000;[{ "Type": "And", "Operands": ["dword ptr [eax+ecx*4]", "0xAA"] }]
-# AND r32, r/m32 (opcode 23)
-23D8;[{ "Type": "And", "Operands": ["ebx", "eax"] }]
-23CA;[{ "Type": "And", "Operands": ["ecx", "edx"] }]
-23E5;[{ "Type": "And", "Operands": ["esp", "ebp"] }]
-234B10;[{ "Type": "And", "Operands": ["ecx", "dword ptr [ebx+0x10]"] }]
-
-# AND with memory operands
-8024251000000042;[{ "Type": "And", "Operands": ["byte ptr [0x10]", "0x42"] }]
-8124251000000078563412;[{ "Type": "And", "Operands": ["dword ptr [0x10]", "0x12345678"] }]
-8324251000000042;[{ "Type": "And", "Operands": ["dword ptr [0x10]", "0x42"] }]
-20042510000000;[{ "Type": "And", "Operands": ["byte ptr [0x10]", "al"] }]
-22042510000000;[{ "Type": "And", "Operands": ["al", "byte ptr [0x10]"] }]
-21042510000000;[{ "Type": "And", "Operands": ["dword ptr [0x10]", "eax"] }]
-23042510000000;[{ "Type": "And", "Operands": ["eax", "dword ptr [0x10]"] }]
+# Complex addressing modes
+20A314285600;[{ "Type": "And", "Operands": ["byte ptr [ebx+0x562814]", "ah"] }]
+6621B310203040;[{ "Type": "And", "Operands": ["word ptr [ebx+0x40302010]", "si"] }]
+230C8D10203040;[{ "Type": "And", "Operands": ["ecx", "dword ptr [ebp*4+0x40302010]"] }]
\ No newline at end of file
diff --git a/X86DisassemblerTests/TestData/bit_tests.csv b/X86DisassemblerTests/TestData/bit_tests.csv
index a6d7fc2..84319d1 100644
--- a/X86DisassemblerTests/TestData/bit_tests.csv
+++ b/X86DisassemblerTests/TestData/bit_tests.csv
@@ -2,20 +2,40 @@
# Format: RawBytes;Instructions
RawBytes;Instructions
+# BT - Bit Test (Immediate)
+0FBA2005;[{ "Type": "Bt", "Operands": ["dword ptr [eax]", "0x05"] }]
+0FBA650005;[{ "Type": "Bt", "Operands": ["dword ptr [ebp+0x00]", "0x05"] }]
+0FBA2305;[{ "Type": "Bt", "Operands": ["dword ptr [ebx]", "0x05"] }]
+0FBA2105;[{ "Type": "Bt", "Operands": ["dword ptr [ecx]", "0x05"] }]
+0FBA2205;[{ "Type": "Bt", "Operands": ["dword ptr [edx]", "0x05"] }]
+
+# BTS - Bit Test and Set (Immediate)
+0FBAA805;[{ "Type": "Bts", "Operands": ["dword ptr [eax]", "0x05"] }]
+0FBA6D0005;[{ "Type": "Bts", "Operands": ["dword ptr [ebp+0x00]", "0x05"] }]
+0FBAAB05;[{ "Type": "Bts", "Operands": ["dword ptr [ebx]", "0x05"] }]
+0FBAA905;[{ "Type": "Bts", "Operands": ["dword ptr [ecx]", "0x05"] }]
+0FBAAA05;[{ "Type": "Bts", "Operands": ["dword ptr [edx]", "0x05"] }]
+
+# BTR - Bit Test and Reset (Immediate)
+0FBAB005;[{ "Type": "Btr", "Operands": ["dword ptr [eax]", "0x05"] }]
+0FBA750005;[{ "Type": "Btr", "Operands": ["dword ptr [ebp+0x00]", "0x05"] }]
+0FBAB305;[{ "Type": "Btr", "Operands": ["dword ptr [ebx]", "0x05"] }]
+0FBAB105;[{ "Type": "Btr", "Operands": ["dword ptr [ecx]", "0x05"] }]
+0FBAB205;[{ "Type": "Btr", "Operands": ["dword ptr [edx]", "0x05"] }]
+
+# BTC - Bit Test and Complement (Immediate)
+0FBAB805;[{ "Type": "Btc", "Operands": ["dword ptr [eax]", "0x05"] }]
+0FBA7D0005;[{ "Type": "Btc", "Operands": ["dword ptr [ebp+0x00]", "0x05"] }]
+0FBABB05;[{ "Type": "Btc", "Operands": ["dword ptr [ebx]", "0x05"] }]
+0FBAB905;[{ "Type": "Btc", "Operands": ["dword ptr [ecx]", "0x05"] }]
+0FBABA05;[{ "Type": "Btc", "Operands": ["dword ptr [edx]", "0x05"] }]
+
# BT - Bit Test
0FA3C1;[{ "Type": "Bt", "Operands": ["ecx", "eax"] }]
0FA3D9;[{ "Type": "Bt", "Operands": ["ecx", "ebx"] }]
0FA3CA;[{ "Type": "Bt", "Operands": ["edx", "ecx"] }]
0FA3E2;[{ "Type": "Bt", "Operands": ["edx", "esp"] }]
0FA3F6;[{ "Type": "Bt", "Operands": ["esi", "esi"] }]
-0FA30425;[{ "Type": "Bt", "Operands": ["dword ptr [eax]", "eax"] }]
-0FA30C25;[{ "Type": "Bt", "Operands": ["dword ptr [eax]", "ecx"] }]
-0FA31425;[{ "Type": "Bt", "Operands": ["dword ptr [eax]", "edx"] }]
-0FBA2005;[{ "Type": "Bt", "Operands": ["dword ptr [eax]", "0x05"] }]
-0FBA2505;[{ "Type": "Bt", "Operands": ["dword ptr [ebp]", "0x05"] }]
-0FBA2305;[{ "Type": "Bt", "Operands": ["dword ptr [ebx]", "0x05"] }]
-0FBA2105;[{ "Type": "Bt", "Operands": ["dword ptr [ecx]", "0x05"] }]
-0FBA2205;[{ "Type": "Bt", "Operands": ["dword ptr [edx]", "0x05"] }]
# BTS - Bit Test and Set
0FABC1;[{ "Type": "Bts", "Operands": ["ecx", "eax"] }]
@@ -23,14 +43,6 @@ RawBytes;Instructions
0FABCA;[{ "Type": "Bts", "Operands": ["edx", "ecx"] }]
0FABE2;[{ "Type": "Bts", "Operands": ["edx", "esp"] }]
0FABF6;[{ "Type": "Bts", "Operands": ["esi", "esi"] }]
-0FAB0425;[{ "Type": "Bts", "Operands": ["dword ptr [eax]", "eax"] }]
-0FAB0C25;[{ "Type": "Bts", "Operands": ["dword ptr [eax]", "ecx"] }]
-0FAB1425;[{ "Type": "Bts", "Operands": ["dword ptr [eax]", "edx"] }]
-0FBA2805;[{ "Type": "Bts", "Operands": ["dword ptr [eax]", "0x05"] }]
-0FBA2D05;[{ "Type": "Bts", "Operands": ["dword ptr [ebp]", "0x05"] }]
-0FBA2B05;[{ "Type": "Bts", "Operands": ["dword ptr [ebx]", "0x05"] }]
-0FBA2905;[{ "Type": "Bts", "Operands": ["dword ptr [ecx]", "0x05"] }]
-0FBA2A05;[{ "Type": "Bts", "Operands": ["dword ptr [edx]", "0x05"] }]
# BTR - Bit Test and Reset
0FB3C1;[{ "Type": "Btr", "Operands": ["ecx", "eax"] }]
@@ -38,29 +50,6 @@ RawBytes;Instructions
0FB3CA;[{ "Type": "Btr", "Operands": ["edx", "ecx"] }]
0FB3E2;[{ "Type": "Btr", "Operands": ["edx", "esp"] }]
0FB3F6;[{ "Type": "Btr", "Operands": ["esi", "esi"] }]
-0FB30425;[{ "Type": "Btr", "Operands": ["dword ptr [eax]", "eax"] }]
-0FB30C25;[{ "Type": "Btr", "Operands": ["dword ptr [eax]", "ecx"] }]
-0FB31425;[{ "Type": "Btr", "Operands": ["dword ptr [eax]", "edx"] }]
-0FBA3005;[{ "Type": "Btr", "Operands": ["dword ptr [eax]", "0x05"] }]
-0FBA3505;[{ "Type": "Btr", "Operands": ["dword ptr [ebp]", "0x05"] }]
-0FBA3305;[{ "Type": "Btr", "Operands": ["dword ptr [ebx]", "0x05"] }]
-0FBA3105;[{ "Type": "Btr", "Operands": ["dword ptr [ecx]", "0x05"] }]
-0FBA3205;[{ "Type": "Btr", "Operands": ["dword ptr [edx]", "0x05"] }]
-
-# BTC - Bit Test and Complement
-0FBBC1;[{ "Type": "Btc", "Operands": ["ecx", "eax"] }]
-0FBBD9;[{ "Type": "Btc", "Operands": ["ecx", "ebx"] }]
-0FBBCA;[{ "Type": "Btc", "Operands": ["edx", "ecx"] }]
-0FBBE2;[{ "Type": "Btc", "Operands": ["edx", "esp"] }]
-0FBBF6;[{ "Type": "Btc", "Operands": ["esi", "esi"] }]
-0FBB0425;[{ "Type": "Btc", "Operands": ["dword ptr [eax]", "eax"] }]
-0FBB0C25;[{ "Type": "Btc", "Operands": ["dword ptr [eax]", "ecx"] }]
-0FBB1425;[{ "Type": "Btc", "Operands": ["dword ptr [eax]", "edx"] }]
-0FBA3805;[{ "Type": "Btc", "Operands": ["dword ptr [eax]", "0x05"] }]
-0FBA3D05;[{ "Type": "Btc", "Operands": ["dword ptr [ebp]", "0x05"] }]
-0FBA3B05;[{ "Type": "Btc", "Operands": ["dword ptr [ebx]", "0x05"] }]
-0FBA3905;[{ "Type": "Btc", "Operands": ["dword ptr [ecx]", "0x05"] }]
-0FBA3A05;[{ "Type": "Btc", "Operands": ["dword ptr [edx]", "0x05"] }]
# BSF - Bit Scan Forward
0FBCC1;[{ "Type": "Bsf", "Operands": ["eax", "ecx"] }]
@@ -68,11 +57,20 @@ RawBytes;Instructions
0FBCCA;[{ "Type": "Bsf", "Operands": ["ecx", "edx"] }]
0FBCE2;[{ "Type": "Bsf", "Operands": ["esp", "edx"] }]
0FBCF6;[{ "Type": "Bsf", "Operands": ["esi", "esi"] }]
-0FBC0425;[{ "Type": "Bsf", "Operands": ["eax", "dword ptr [eax]"] }]
-0FBC0C25;[{ "Type": "Bsf", "Operands": ["ecx", "dword ptr [eax]"] }]
-0FBC1425;[{ "Type": "Bsf", "Operands": ["edx", "dword ptr [eax]"] }]
-0FBC1C25;[{ "Type": "Bsf", "Operands": ["ebx", "dword ptr [eax]"] }]
-0FBC2425;[{ "Type": "Bsf", "Operands": ["esp", "dword ptr [eax]"] }]
+
+# BTC - Bit Test and Complement
+0FBBC1;[{ "Type": "Btc", "Operands": ["ecx", "eax"] }]
+0FBBD9;[{ "Type": "Btc", "Operands": ["ecx", "ebx"] }]
+0FBBCA;[{ "Type": "Btc", "Operands": ["edx", "ecx"] }]
+0FBBE2;[{ "Type": "Btc", "Operands": ["edx", "esp"] }]
+0FBBF6;[{ "Type": "Btc", "Operands": ["esi", "esi"] }]
+
+# BSF - Bit Scan Forward
+0FBC00;[{ "Type": "Bsf", "Operands": ["eax", "dword ptr [eax]"] }]
+0FBC08;[{ "Type": "Bsf", "Operands": ["ecx", "dword ptr [eax]"] }]
+0FBC10;[{ "Type": "Bsf", "Operands": ["edx", "dword ptr [eax]"] }]
+0FBC18;[{ "Type": "Bsf", "Operands": ["ebx", "dword ptr [eax]"] }]
+0FBC20;[{ "Type": "Bsf", "Operands": ["esp", "dword ptr [eax]"] }]
# BSR - Bit Scan Reverse
0FBDC1;[{ "Type": "Bsr", "Operands": ["eax", "ecx"] }]
@@ -80,8 +78,8 @@ RawBytes;Instructions
0FBDCA;[{ "Type": "Bsr", "Operands": ["ecx", "edx"] }]
0FBDE2;[{ "Type": "Bsr", "Operands": ["esp", "edx"] }]
0FBDF6;[{ "Type": "Bsr", "Operands": ["esi", "esi"] }]
-0FBD0425;[{ "Type": "Bsr", "Operands": ["eax", "dword ptr [eax]"] }]
-0FBD0C25;[{ "Type": "Bsr", "Operands": ["ecx", "dword ptr [eax]"] }]
-0FBD1425;[{ "Type": "Bsr", "Operands": ["edx", "dword ptr [eax]"] }]
-0FBD1C25;[{ "Type": "Bsr", "Operands": ["ebx", "dword ptr [eax]"] }]
-0FBD2425;[{ "Type": "Bsr", "Operands": ["esp", "dword ptr [eax]"] }]
+0FBD00;[{ "Type": "Bsr", "Operands": ["eax", "dword ptr [eax]"] }]
+0FBD08;[{ "Type": "Bsr", "Operands": ["ecx", "dword ptr [eax]"] }]
+0FBD10;[{ "Type": "Bsr", "Operands": ["edx", "dword ptr [eax]"] }]
+0FBD18;[{ "Type": "Bsr", "Operands": ["ebx", "dword ptr [eax]"] }]
+0FBD20;[{ "Type": "Bsr", "Operands": ["esp", "dword ptr [eax]"] }]
diff --git a/X86DisassemblerTests/TestData/div_tests.csv b/X86DisassemblerTests/TestData/div_tests.csv
index 3b46f5a..a27b0d2 100644
--- a/X86DisassemblerTests/TestData/div_tests.csv
+++ b/X86DisassemblerTests/TestData/div_tests.csv
@@ -22,46 +22,23 @@ F7F5;[{ "Type": "Div", "Operands": ["ebp"] }]
F7F6;[{ "Type": "Div", "Operands": ["esi"] }]
F7F7;[{ "Type": "Div", "Operands": ["edi"] }]
-# DIV with memory operands
# Basic memory addressing
-# SPECIAL CASE: When using SIB byte with Base=101 (EBP) and Mod=00, it requires a 32-bit displacement
-# The correct encoding for "DIV byte ptr [eax]" would be F630 (with Mod=00, R/M=0 for EAX)
-# F63425;[{ "Type": "Div", "Operands": ["byte ptr [eax]"] }]
F630;[{ "Type": "Div", "Operands": ["byte ptr [eax]"] }]
-# For "DIV byte ptr [ebp]", we need to use Mod=01 with a zero displacement since [ebp] can't be encoded with Mod=00
-# F63C25;[{ "Type": "Div", "Operands": ["byte ptr [ebp]"] }]
-F66500;[{ "Type": "Div", "Operands": ["byte ptr [ebp]"] }]
-
-# The correct encoding for "DIV byte ptr [eax]" would be F630 (with Mod=00, R/M=0 for EAX)
-# F63825;[{ "Type": "Div", "Operands": ["byte ptr [eax]"] }]
F630;[{ "Type": "Div", "Operands": ["byte ptr [eax]"] }]
-# The correct encoding for "DIV dword ptr [eax]" would be F730 (with Mod=00, R/M=0 for EAX)
-# F73425;[{ "Type": "Div", "Operands": ["dword ptr [eax]"] }]
F730;[{ "Type": "Div", "Operands": ["dword ptr [eax]"] }]
-# For "DIV dword ptr [ebp]", we need to use Mod=01 with a zero displacement since [ebp] can't be encoded with Mod=00
-# F73C25;[{ "Type": "Div", "Operands": ["dword ptr [ebp]"] }]
-F76500;[{ "Type": "Div", "Operands": ["dword ptr [ebp]"] }]
+F77500;[{ "Type": "Div", "Operands": ["dword ptr [ebp+0x00]"] }]
-# The correct encoding for "DIV dword ptr [eax]" would be F730 (with Mod=00, R/M=0 for EAX)
-# F73825;[{ "Type": "Div", "Operands": ["dword ptr [eax]"] }]
F730;[{ "Type": "Div", "Operands": ["dword ptr [eax]"] }]
-# With displacement
-# The correct encoding for "DIV dword ptr [eax+0x10]" would be F74010 (with Mod=01, R/M=0 for EAX, disp8=0x10)
-# F7742510000000;[{ "Type": "Div", "Operands": ["dword ptr [eax+0x10]"] }]
-F74010;[{ "Type": "Div", "Operands": ["dword ptr [eax+0x10]"] }]
+F77010;[{ "Type": "Div", "Operands": ["dword ptr [eax+0x10]"] }]
-# The correct encoding for "DIV dword ptr [eax+0x20]" would be F74020 (with Mod=01, R/M=0 for EAX, disp8=0x20)
-# F7742520000000;[{ "Type": "Div", "Operands": ["dword ptr [eax+0x20]"] }]
-F74020;[{ "Type": "Div", "Operands": ["dword ptr [eax+0x20]"] }]
+F77020;[{ "Type": "Div", "Operands": ["dword ptr [eax+0x20]"] }]
-# The correct encoding for "DIV dword ptr [eax+0x30]" would be F74030 (with Mod=01, R/M=0 for EAX, disp8=0x30)
-# F7742530000000;[{ "Type": "Div", "Operands": ["dword ptr [eax+0x30]"] }]
-F74030;[{ "Type": "Div", "Operands": ["dword ptr [eax+0x30]"] }]
+F77030;[{ "Type": "Div", "Operands": ["dword ptr [eax+0x30]"] }]
# With SIB addressing
F7341C;[{ "Type": "Div", "Operands": ["dword ptr [esp+ebx*1]"] }]
@@ -70,10 +47,9 @@ F7349C;[{ "Type": "Div", "Operands": ["dword ptr [esp+ebx*4]"] }]
F734DC;[{ "Type": "Div", "Operands": ["dword ptr [esp+ebx*8]"] }]
# With segment override prefixes
-# not recognized by ghidra or online disasms
-# 26F73425;[{ "Type": "Div", "Operands": ["dword ptr es:[eax]"] }]
-# 2EF73425;[{ "Type": "Div", "Operands": ["dword ptr cs:[eax]"] }]
-# 36F73425;[{ "Type": "Div", "Operands": ["dword ptr ss:[eax]"] }]
-# 3EF73425;[{ "Type": "Div", "Operands": ["dword ptr ds:[eax]"] }]
-# 64F73425;[{ "Type": "Div", "Operands": ["dword ptr fs:[eax]"] }]
-# 65F73425;[{ "Type": "Div", "Operands": ["dword ptr gs:[eax]"] }]
+26F730;[{ "Type": "Div", "Operands": ["dword ptr es:[eax]"] }]
+2EF730;[{ "Type": "Div", "Operands": ["dword ptr cs:[eax]"] }]
+36F730;[{ "Type": "Div", "Operands": ["dword ptr ss:[eax]"] }]
+3EF730;[{ "Type": "Div", "Operands": ["dword ptr ds:[eax]"] }]
+64F730;[{ "Type": "Div", "Operands": ["dword ptr fs:[eax]"] }]
+65F730;[{ "Type": "Div", "Operands": ["dword ptr gs:[eax]"] }]
diff --git a/X86DisassemblerTests/TestData/poprm_tests.csv b/X86DisassemblerTests/TestData/poprm_tests.csv
index e3a1cb8..0cd741f 100644
--- a/X86DisassemblerTests/TestData/poprm_tests.csv
+++ b/X86DisassemblerTests/TestData/poprm_tests.csv
@@ -7,8 +7,8 @@ RawBytes;Instructions
8F01;[{ "Type": "Pop", "Operands": ["dword ptr [ecx]"] }]
8F02;[{ "Type": "Pop", "Operands": ["dword ptr [edx]"] }]
8F03;[{ "Type": "Pop", "Operands": ["dword ptr [ebx]"] }]
-8F04;[{ "Type": "Pop", "Operands": ["dword ptr [esp]"] }]
-8F05;[{ "Type": "Pop", "Operands": ["dword ptr [ebp]"] }]
+8F0424;[{ "Type": "Pop", "Operands": ["dword ptr [esp]"] }]
+88F4500;[{ "Type": "Pop", "Operands": ["dword ptr [ebp]"] }]
8F06;[{ "Type": "Pop", "Operands": ["dword ptr [esi]"] }]
8F07;[{ "Type": "Pop", "Operands": ["dword ptr [edi]"] }]
@@ -17,7 +17,7 @@ RawBytes;Instructions
8F4110;[{ "Type": "Pop", "Operands": ["dword ptr [ecx+0x10]"] }]
8F4210;[{ "Type": "Pop", "Operands": ["dword ptr [edx+0x10]"] }]
8F4310;[{ "Type": "Pop", "Operands": ["dword ptr [ebx+0x10]"] }]
-8F4410;[{ "Type": "Pop", "Operands": ["dword ptr [esp+0x10]"] }]
+8F442410;[{ "Type": "Pop", "Operands": ["dword ptr [esp+0x10]"] }]
8F4510;[{ "Type": "Pop", "Operands": ["dword ptr [ebp+0x10]"] }]
8F4610;[{ "Type": "Pop", "Operands": ["dword ptr [esi+0x10]"] }]
8F4710;[{ "Type": "Pop", "Operands": ["dword ptr [edi+0x10]"] }]
diff --git a/X86DisassemblerTests/TestData/pushimm_tests.csv b/X86DisassemblerTests/TestData/pushimm_tests.csv
index 33fa8b9..020ac89 100644
--- a/X86DisassemblerTests/TestData/pushimm_tests.csv
+++ b/X86DisassemblerTests/TestData/pushimm_tests.csv
@@ -11,9 +11,9 @@ RawBytes;Instructions
6AFF;[{ "Type": "Push", "Operands": ["0xFF"] }]
# PUSH imm32 with various values
-6800000000;[{ "Type": "Push", "Operands": ["0x00000000"] }]
+6800000000;[{ "Type": "Push", "Operands": ["0x00"] }]
68FFFFFFFF;[{ "Type": "Push", "Operands": ["0xFFFFFFFF"] }]
-6801000000;[{ "Type": "Push", "Operands": ["0x00000001"] }]
+6801000000;[{ "Type": "Push", "Operands": ["0x01"] }]
# PUSH imm16 with operand size prefix
66687856;[{ "Type": "Push", "Operands": ["0x5678"] }]
diff --git a/X86DisassemblerTests/TestData/pushrm_tests.csv b/X86DisassemblerTests/TestData/pushrm_tests.csv
index 2b87c68..ad350aa 100644
--- a/X86DisassemblerTests/TestData/pushrm_tests.csv
+++ b/X86DisassemblerTests/TestData/pushrm_tests.csv
@@ -7,8 +7,8 @@ FF30;[{ "Type": "Push", "Operands": ["dword ptr [eax]"] }]
FF31;[{ "Type": "Push", "Operands": ["dword ptr [ecx]"] }]
FF32;[{ "Type": "Push", "Operands": ["dword ptr [edx]"] }]
FF33;[{ "Type": "Push", "Operands": ["dword ptr [ebx]"] }]
-FF34;[{ "Type": "Push", "Operands": ["dword ptr [esp]"] }]
-FF35;[{ "Type": "Push", "Operands": ["dword ptr [ebp]"] }]
+FF3424;[{ "Type": "Push", "Operands": ["dword ptr [esp]"] }]
+FF7500;[{ "Type": "Push", "Operands": ["dword ptr [ebp]"] }]
FF36;[{ "Type": "Push", "Operands": ["dword ptr [esi]"] }]
FF37;[{ "Type": "Push", "Operands": ["dword ptr [edi]"] }]
@@ -17,16 +17,16 @@ FF7010;[{ "Type": "Push", "Operands": ["dword ptr [eax+0x10]"] }]
FF7110;[{ "Type": "Push", "Operands": ["dword ptr [ecx+0x10]"] }]
FF7210;[{ "Type": "Push", "Operands": ["dword ptr [edx+0x10]"] }]
FF7310;[{ "Type": "Push", "Operands": ["dword ptr [ebx+0x10]"] }]
-FF7410;[{ "Type": "Push", "Operands": ["dword ptr [esp+0x10]"] }]
+FF742410;[{ "Type": "Push", "Operands": ["dword ptr [esp+0x10]"] }]
FF7510;[{ "Type": "Push", "Operands": ["dword ptr [ebp+0x10]"] }]
FF7610;[{ "Type": "Push", "Operands": ["dword ptr [esi+0x10]"] }]
FF7710;[{ "Type": "Push", "Operands": ["dword ptr [edi+0x10]"] }]
# PUSH r/m32 (opcode FF /6) with SIB byte
-FF34C5;[{ "Type": "Push", "Operands": ["dword ptr [ebp+eax*8]"] }]
-FF34CD;[{ "Type": "Push", "Operands": ["dword ptr [ebp+ecx*8]"] }]
-FF34D5;[{ "Type": "Push", "Operands": ["dword ptr [ebp+edx*8]"] }]
-FF34DD;[{ "Type": "Push", "Operands": ["dword ptr [ebp+ebx*8]"] }]
+FF74C500;[{ "Type": "Push", "Operands": ["dword ptr [ebp+eax*8]"] }]
+FF74CD00;[{ "Type": "Push", "Operands": ["dword ptr [ebp+ecx*8]"] }]
+FF74D500;[{ "Type": "Push", "Operands": ["dword ptr [ebp+edx*8]"] }]
+FF74DD00;[{ "Type": "Push", "Operands": ["dword ptr [ebp+ebx*8]"] }]
# PUSH r/m32 (opcode FF /6) with direct memory operand
FF3578563412;[{ "Type": "Push", "Operands": ["dword ptr [0x12345678]"] }]
diff --git a/X86DisassemblerTests/TestData/sub_tests.csv b/X86DisassemblerTests/TestData/sub_tests.csv
index 9a85631..345731a 100644
--- a/X86DisassemblerTests/TestData/sub_tests.csv
+++ b/X86DisassemblerTests/TestData/sub_tests.csv
@@ -39,19 +39,19 @@ RawBytes;Instructions
# 16-bit register operations with operand size prefix (0x66)
# SUB r/m16, r16 (opcode 29 with 0x66 prefix)
-6629D8;[{ "Type": "Sub", "Operands": ["eax", "ebx"] }]
+6629D8;[{ "Type": "Sub", "Operands": ["ax", "bx"] }]
# SUB r16, r/m16 (opcode 2B with 0x66 prefix)
-662BD8;[{ "Type": "Sub", "Operands": ["ebx", "eax"] }]
+662BD8;[{ "Type": "Sub", "Operands": ["bx", "ax"] }]
# SUB AX, imm16 (opcode 2D with 0x66 prefix)
-662D3412;[{ "Type": "Sub", "Operands": ["eax", "0x1234"] }]
+662D3412;[{ "Type": "Sub", "Operands": ["ax", "0x1234"] }]
# SUB r/m16, imm8 (opcode 83 /5 with 0x66 prefix and sign extension)
-6683EB42;[{ "Type": "Sub", "Operands": ["ebx", "0x42"] }]
+6683EB42;[{ "Type": "Sub", "Operands": ["bx", "0x42"] }]
# SUB r/m16, imm16 (opcode 81 /5 with 0x66 prefix)
-6681EB3412;[{ "Type": "Sub", "Operands": ["ebx", "0x1234"] }]
+6681EB3412;[{ "Type": "Sub", "Operands": ["bx", "0x1234"] }]
# Additional test cases for more complex addressing modes
@@ -101,7 +101,7 @@ RawBytes;Instructions
81EF78563412;[{ "Type": "Sub", "Operands": ["edi", "0x12345678"] }]
# SUB r/m32, imm32 (opcode 81 /5) with memory operands
-818D10000000FFFFFFFF;[{ "Type": "Sub", "Operands": ["dword ptr [ebp+0x10]", "0xFFFFFFFF"] }]
+81AD10000000FFFFFFFF;[{ "Type": "Sub", "Operands": ["dword ptr [ebp+0x10]", "0xFFFFFFFF"] }]
# Additional tests for SubImmFromRm32SignExtendedHandler
# SUB r/m32, imm8 (opcode 83 /5) with sign extension
@@ -114,4 +114,4 @@ RawBytes;Instructions
83EFFF;[{ "Type": "Sub", "Operands": ["edi", "0xFFFFFFFF"] }]
# SUB r/m32, imm8 (opcode 83 /5) with memory operands and sign extension
-838D1000000080;[{ "Type": "Sub", "Operands": ["dword ptr [ebp+0x10]", "0xFFFFFF80"] }]
+83AD1000000080;[{ "Type": "Sub", "Operands": ["dword ptr [ebp+0x10]", "0xFFFFFF80"] }]
diff --git a/X86DisassemblerTests/TestData/test_tests.csv b/X86DisassemblerTests/TestData/test_tests.csv
index d51f957..0ad5711 100644
--- a/X86DisassemblerTests/TestData/test_tests.csv
+++ b/X86DisassemblerTests/TestData/test_tests.csv
@@ -19,6 +19,6 @@ F7C378563412;[{ "Type": "Test", "Operands": ["ebx", "0x12345678"] }]
85D9;[{ "Type": "Test", "Operands": ["ecx", "ebx"] }]
# TEST with memory operands
-F6042542;[{ "Type": "Test", "Operands": ["byte ptr [eax]", "0x42"] }]
-F7042578563412;[{ "Type": "Test", "Operands": ["dword ptr [eax]", "0x12345678"] }]
-85042510;[{ "Type": "Test", "Operands": ["dword ptr [eax+0x10]", "eax"] }]
+F60042;[{ "Type": "Test", "Operands": ["byte ptr [eax]", "0x42"] }]
+F70078563412;[{ "Type": "Test", "Operands": ["dword ptr [eax]", "0x12345678"] }]
+854510;[{ "Type": "Test", "Operands": ["dword ptr [eax+0x10]", "eax"] }]