diff --git a/X86Disassembler/X86/Handlers/Add/AddAxImmHandler.cs b/X86Disassembler/X86/Handlers/Add/AddAxImmHandler.cs
new file mode 100644
index 0000000..f29c170
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Add/AddAxImmHandler.cs
@@ -0,0 +1,71 @@
+using X86Disassembler.X86.Operands;
+
+namespace X86Disassembler.X86.Handlers.Add;
+
+///
+/// Handler for ADD AX, imm16 instruction (0x05 with 0x66 prefix)
+///
+public class AddAxImmHandler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the AddAxImmHandler class
+ ///
+ /// The instruction decoder that owns this handler
+ public AddAxImmHandler(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)
+ {
+ // ADD AX, imm16 is encoded as 0x05 with 0x66 prefix
+ if (opcode != 0x05)
+ {
+ return false;
+ }
+
+ // Only handle when the operand size prefix is present
+ return Decoder.HasOperandSizePrefix();
+ }
+
+ ///
+ /// Decodes an ADD AX, 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.Add;
+
+ // 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 AX register operand
+ var axOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.A, 16);
+
+ // Create the immediate operand
+ var immOperand = OperandFactory.CreateImmediateOperand(imm16);
+
+ // Set the structured operands
+ instruction.StructuredOperands =
+ [
+ axOperand,
+ immOperand
+ ];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/And/AndAxImmHandler.cs b/X86Disassembler/X86/Handlers/And/AndAxImmHandler.cs
new file mode 100644
index 0000000..fb005c9
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/And/AndAxImmHandler.cs
@@ -0,0 +1,71 @@
+using X86Disassembler.X86.Operands;
+
+namespace X86Disassembler.X86.Handlers.And;
+
+///
+/// Handler for AND AX, imm16 instruction (0x25 with 0x66 prefix)
+///
+public class AndAxImmHandler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the AndAxImmHandler class
+ ///
+ /// The instruction decoder that owns this handler
+ public AndAxImmHandler(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)
+ {
+ // AND AX, imm16 is encoded as 0x25 with 0x66 prefix
+ if (opcode != 0x25)
+ {
+ return false;
+ }
+
+ // Only handle when the operand size prefix is present
+ return Decoder.HasOperandSizePrefix();
+ }
+
+ ///
+ /// Decodes an AND AX, 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.And;
+
+ // 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 AX register operand
+ var axOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.A, 16);
+
+ // Create the immediate operand
+ var immOperand = OperandFactory.CreateImmediateOperand(imm16);
+
+ // Set the structured operands
+ instruction.StructuredOperands =
+ [
+ axOperand,
+ immOperand
+ ];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/And/AndImmToRm16Handler.cs b/X86Disassembler/X86/Handlers/And/AndImmToRm16Handler.cs
new file mode 100644
index 0000000..d706ac1
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/And/AndImmToRm16Handler.cs
@@ -0,0 +1,84 @@
+using X86Disassembler.X86.Operands;
+
+namespace X86Disassembler.X86.Handlers.And;
+
+///
+/// Handler for AND r/m16, imm16 instruction (0x81 /4 with 0x66 prefix)
+///
+public class AndImmToRm16Handler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the AndImmToRm16Handler class
+ ///
+ /// The instruction decoder that owns this handler
+ public AndImmToRm16Handler(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)
+ {
+ // AND r/m16, imm16 is encoded as 0x81 with 0x66 prefix
+ if (opcode != 0x81)
+ {
+ return false;
+ }
+
+ // Only handle when the operand size prefix is present
+ if (!Decoder.HasOperandSizePrefix())
+ {
+ return false;
+ }
+
+ // Check if we can read the ModR/M byte
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Check if the reg field of the ModR/M byte is 4 (AND)
+ var reg = ModRMDecoder.PeakModRMReg();
+ return reg == 4; // 4 = AND
+ }
+
+ ///
+ /// Decodes an AND 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.And;
+
+ // Read the ModR/M byte to get the destination operand
+ var (_, reg, _, destinationOperand) = ModRMDecoder.ReadModRM16();
+
+ // 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);
+
+ // Set the structured operands
+ instruction.StructuredOperands =
+ [
+ destinationOperand,
+ sourceOperand
+ ];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/And/AndImmToRm16SignExtendedHandler.cs b/X86Disassembler/X86/Handlers/And/AndImmToRm16SignExtendedHandler.cs
new file mode 100644
index 0000000..84ed642
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/And/AndImmToRm16SignExtendedHandler.cs
@@ -0,0 +1,86 @@
+using X86Disassembler.X86.Operands;
+
+namespace X86Disassembler.X86.Handlers.And;
+
+///
+/// Handler for AND r/m16, imm8 instruction (0x83 /4 with 0x66 prefix)
+///
+public class AndImmToRm16SignExtendedHandler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the AndImmToRm16SignExtendedHandler class
+ ///
+ /// The instruction decoder that owns this handler
+ public AndImmToRm16SignExtendedHandler(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)
+ {
+ // AND r/m16, imm8 is encoded as 0x83 with 0x66 prefix
+ if (opcode != 0x83)
+ {
+ return false;
+ }
+
+ // Only handle when the operand size prefix is present
+ if (!Decoder.HasOperandSizePrefix())
+ {
+ return false;
+ }
+
+ // Check if we can read the ModR/M byte
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Check if the reg field of the ModR/M byte is 4 (AND)
+ var reg = ModRMDecoder.PeakModRMReg();
+ return reg == 4; // 4 = AND
+ }
+
+ ///
+ /// Decodes an AND r/m16, 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.And;
+
+ // Read the ModR/M byte to get the destination operand
+ var (_, reg, _, destinationOperand) = ModRMDecoder.ReadModRM16();
+
+ // Check if we have enough bytes for the immediate value
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Read the immediate value and sign-extend it to 16 bits
+ sbyte imm8 = (sbyte)Decoder.ReadByte();
+ short signExtendedImm = imm8;
+ ushort imm16 = (ushort)signExtendedImm;
+
+ // Create the immediate operand
+ var sourceOperand = OperandFactory.CreateImmediateOperand(imm16);
+
+ // Set the structured operands
+ instruction.StructuredOperands =
+ [
+ destinationOperand,
+ sourceOperand
+ ];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/And/AndR16Rm16Handler.cs b/X86Disassembler/X86/Handlers/And/AndR16Rm16Handler.cs
new file mode 100644
index 0000000..64bdd42
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/And/AndR16Rm16Handler.cs
@@ -0,0 +1,70 @@
+using X86Disassembler.X86.Operands;
+
+namespace X86Disassembler.X86.Handlers.And;
+
+///
+/// Handler for AND r16, r/m16 instruction (0x23 with 0x66 prefix)
+///
+public class AndR16Rm16Handler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the AndR16Rm16Handler class
+ ///
+ /// The instruction decoder that owns this handler
+ public AndR16Rm16Handler(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)
+ {
+ // AND r16, r/m16 is encoded as 0x23 with 0x66 prefix
+ if (opcode != 0x23)
+ {
+ return false;
+ }
+
+ // Only handle when the operand size prefix is present
+ return Decoder.HasOperandSizePrefix();
+ }
+
+ ///
+ /// Decodes an AND 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.And;
+
+ // Check if we can read the ModR/M byte
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // For AND r16, r/m16 (0x23 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();
+
+ // 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/And/AndRm16R16Handler.cs b/X86Disassembler/X86/Handlers/And/AndRm16R16Handler.cs
new file mode 100644
index 0000000..dcdfe86
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/And/AndRm16R16Handler.cs
@@ -0,0 +1,70 @@
+using X86Disassembler.X86.Operands;
+
+namespace X86Disassembler.X86.Handlers.And;
+
+///
+/// Handler for AND r/m16, r16 instruction (0x21 with 0x66 prefix)
+///
+public class AndRm16R16Handler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the AndRm16R16Handler class
+ ///
+ /// The instruction decoder that owns this handler
+ public AndRm16R16Handler(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)
+ {
+ // AND r/m16, r16 is encoded as 0x21 with 0x66 prefix
+ if (opcode != 0x21)
+ {
+ return false;
+ }
+
+ // Only handle when the operand size prefix is present
+ return Decoder.HasOperandSizePrefix();
+ }
+
+ ///
+ /// Decodes an AND 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.And;
+
+ // Check if we can read the ModR/M byte
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // For AND r/m16, r16 (0x21 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();
+
+ // 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/InstructionHandlerFactory.cs b/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs
index f46b081..8990779 100644
--- a/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs
+++ b/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs
@@ -12,6 +12,7 @@ using X86Disassembler.X86.Handlers.Imul;
using X86Disassembler.X86.Handlers.Inc;
using X86Disassembler.X86.Handlers.Jump;
using X86Disassembler.X86.Handlers.Lea;
+using X86Disassembler.X86.Handlers.Misc;
using X86Disassembler.X86.Handlers.Mov;
using X86Disassembler.X86.Handlers.Mul;
using X86Disassembler.X86.Handlers.Neg;
@@ -36,21 +37,15 @@ namespace X86Disassembler.X86.Handlers;
public class InstructionHandlerFactory
{
private readonly List _handlers = [];
- private readonly byte[] _codeBuffer;
private readonly InstructionDecoder _decoder;
- private readonly int _length;
///
/// Initializes a new instance of the InstructionHandlerFactory class
///
- /// The buffer containing the code to decode
/// The instruction decoder that owns this factory
- /// The length of the buffer
- public InstructionHandlerFactory(byte[] codeBuffer, InstructionDecoder decoder, int length)
+ public InstructionHandlerFactory(InstructionDecoder decoder)
{
- _codeBuffer = codeBuffer;
_decoder = decoder;
- _length = length;
RegisterAllHandlers();
}
@@ -61,7 +56,7 @@ public class InstructionHandlerFactory
private void RegisterAllHandlers()
{
// Register specific instruction handlers
- _handlers.Add(new Int3Handler(_decoder));
+ _handlers.Add(new Nop.Int3Handler(_decoder));
// Register handlers in order of priority (most specific first)
RegisterSbbHandlers(); // SBB instructions
@@ -95,7 +90,7 @@ public class InstructionHandlerFactory
RegisterSubHandlers(); // Register SUB handlers
RegisterNopHandlers(); // Register NOP handlers
RegisterBitHandlers(); // Register bit manipulation handlers
- RegisterAndHandlers(); // Register AND handlers
+ RegisterMiscHandlers(); // Register miscellaneous instructions
}
///
@@ -471,11 +466,29 @@ public class InstructionHandlerFactory
private void RegisterNopHandlers()
{
// Register NOP handlers
- _handlers.Add(new NopHandler(_decoder)); // NOP (opcode 0x90)
+ _handlers.Add(new Nop.NopHandler(_decoder)); // NOP (opcode 0x90)
_handlers.Add(new TwoByteNopHandler(_decoder)); // 2-byte NOP (opcode 0x66 0x90)
_handlers.Add(new MultiByteNopHandler(_decoder)); // Multi-byte NOP (opcode 0F 1F /0)
}
+ ///
+ /// Registers all miscellaneous instruction handlers
+ ///
+ private void RegisterMiscHandlers()
+ {
+ // Register miscellaneous instruction handlers
+ _handlers.Add(new IntHandler(_decoder)); // INT (opcode 0xCD)
+ _handlers.Add(new IntoHandler(_decoder)); // INTO (opcode 0xCE)
+ _handlers.Add(new IretHandler(_decoder)); // IRET (opcode 0xCF)
+ _handlers.Add(new CpuidHandler(_decoder)); // CPUID (opcode 0x0F 0xA2)
+ _handlers.Add(new RdtscHandler(_decoder)); // RDTSC (opcode 0x0F 0x31)
+ _handlers.Add(new HltHandler(_decoder)); // HLT (opcode 0xF4)
+ _handlers.Add(new WaitHandler(_decoder)); // WAIT (opcode 0x9B)
+ _handlers.Add(new LockHandler(_decoder)); // LOCK (opcode 0xF0)
+ _handlers.Add(new InHandler(_decoder)); // IN (opcodes 0xE4, 0xE5, 0xEC, 0xED)
+ _handlers.Add(new OutHandler(_decoder)); // OUT (opcodes 0xE6, 0xE7, 0xEE, 0xEF)
+ }
+
///
/// Registers all bit manipulation instruction handlers
///
diff --git a/X86Disassembler/X86/Handlers/Misc/CpuidHandler.cs b/X86Disassembler/X86/Handlers/Misc/CpuidHandler.cs
new file mode 100644
index 0000000..df9cd51
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Misc/CpuidHandler.cs
@@ -0,0 +1,59 @@
+namespace X86Disassembler.X86.Handlers.Misc;
+
+///
+/// Handler for CPUID instruction (0x0F 0xA2)
+///
+public class CpuidHandler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the CpuidHandler class
+ ///
+ /// The instruction decoder that owns this handler
+ public CpuidHandler(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)
+ {
+ // CPUID is encoded as 0x0F 0xA2
+ if (opcode != 0x0F)
+ return false;
+
+ // Check if we can read the second byte
+ if (!Decoder.CanReadByte())
+ return false;
+
+ // Check if the second byte is 0xA2
+ byte secondByte = Decoder.PeakByte();
+ return secondByte == 0xA2;
+ }
+
+ ///
+ /// Decodes a CPUID 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.Cpuid;
+
+ // Read and discard the second byte (0xA2)
+ if (!Decoder.CanReadByte())
+ return false;
+
+ Decoder.ReadByte();
+
+ // CPUID has no operands
+ instruction.StructuredOperands = [];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Misc/HltHandler.cs b/X86Disassembler/X86/Handlers/Misc/HltHandler.cs
new file mode 100644
index 0000000..0590427
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Misc/HltHandler.cs
@@ -0,0 +1,44 @@
+namespace X86Disassembler.X86.Handlers.Misc;
+
+///
+/// Handler for HLT instruction (0xF4)
+///
+public class HltHandler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the HltHandler class
+ ///
+ /// The instruction decoder that owns this handler
+ public HltHandler(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)
+ {
+ // HLT is encoded as 0xF4
+ return opcode == 0xF4;
+ }
+
+ ///
+ /// Decodes a HLT 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.Hlt;
+
+ // HLT has no operands
+ instruction.StructuredOperands = [];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Misc/InHandler.cs b/X86Disassembler/X86/Handlers/Misc/InHandler.cs
new file mode 100644
index 0000000..34970fe
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Misc/InHandler.cs
@@ -0,0 +1,97 @@
+using X86Disassembler.X86.Operands;
+
+namespace X86Disassembler.X86.Handlers.Misc;
+
+///
+/// Handler for IN instruction (0xE4, 0xE5, 0xEC, 0xED)
+///
+public class InHandler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the InHandler class
+ ///
+ /// The instruction decoder that owns this handler
+ public InHandler(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)
+ {
+ // IN AL, imm8 is encoded as 0xE4
+ // IN EAX, imm8 is encoded as 0xE5
+ // IN AL, DX is encoded as 0xEC
+ // IN EAX, DX is encoded as 0xED
+ return opcode == 0xE4 || opcode == 0xE5 || opcode == 0xEC || opcode == 0xED;
+ }
+
+ ///
+ /// Decodes an IN 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.In;
+
+ // Determine the operands based on the opcode
+ Operand destOperand;
+ Operand srcOperand;
+
+ switch (opcode)
+ {
+ case 0xE4: // IN AL, imm8
+ destOperand = OperandFactory.CreateRegisterOperand8(RegisterIndex8.AL);
+
+ // Check if we can read the immediate byte
+ if (!Decoder.CanReadByte())
+ return false;
+
+ // Read the immediate byte (port number)
+ byte imm8 = Decoder.ReadByte();
+ srcOperand = OperandFactory.CreateImmediateOperand(imm8);
+ break;
+
+ case 0xE5: // IN EAX, imm8
+ destOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.A, 32);
+
+ // Check if we can read the immediate byte
+ if (!Decoder.CanReadByte())
+ return false;
+
+ // Read the immediate byte (port number)
+ imm8 = Decoder.ReadByte();
+ srcOperand = OperandFactory.CreateImmediateOperand(imm8);
+ break;
+
+ case 0xEC: // IN AL, DX
+ destOperand = OperandFactory.CreateRegisterOperand8(RegisterIndex8.AL);
+ srcOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.D, 16);
+ break;
+
+ case 0xED: // IN EAX, DX
+ destOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.A, 32);
+ srcOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.D, 16);
+ break;
+
+ default:
+ return false;
+ }
+
+ // Set the structured operands
+ instruction.StructuredOperands =
+ [
+ destOperand,
+ srcOperand
+ ];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Misc/IntHandler.cs b/X86Disassembler/X86/Handlers/Misc/IntHandler.cs
new file mode 100644
index 0000000..a5e4ee6
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Misc/IntHandler.cs
@@ -0,0 +1,61 @@
+namespace X86Disassembler.X86.Handlers.Misc;
+
+using X86Disassembler.X86.Operands;
+
+///
+/// Handler for INT instruction (0xCD)
+///
+public class IntHandler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the IntHandler class
+ ///
+ /// The instruction decoder that owns this handler
+ public IntHandler(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)
+ {
+ // INT is encoded as 0xCD
+ return opcode == 0xCD;
+ }
+
+ ///
+ /// Decodes an INT 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.Int;
+
+ // Check if we can read the immediate byte
+ if (!Decoder.CanReadByte())
+ {
+ return false;
+ }
+
+ // Read the immediate byte (interrupt vector)
+ byte imm8 = Decoder.ReadByte();
+
+ // Create an immediate operand for the interrupt vector
+ var operand = OperandFactory.CreateImmediateOperand(imm8);
+
+ // Set the structured operands
+ instruction.StructuredOperands =
+ [
+ operand
+ ];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Misc/IntoHandler.cs b/X86Disassembler/X86/Handlers/Misc/IntoHandler.cs
new file mode 100644
index 0000000..7a1a252
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Misc/IntoHandler.cs
@@ -0,0 +1,44 @@
+namespace X86Disassembler.X86.Handlers.Misc;
+
+///
+/// Handler for INTO instruction (0xCE)
+///
+public class IntoHandler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the IntoHandler class
+ ///
+ /// The instruction decoder that owns this handler
+ public IntoHandler(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)
+ {
+ // INTO is encoded as 0xCE
+ return opcode == 0xCE;
+ }
+
+ ///
+ /// Decodes an INTO 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.Into;
+
+ // INTO has no operands
+ instruction.StructuredOperands = [];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Misc/IretHandler.cs b/X86Disassembler/X86/Handlers/Misc/IretHandler.cs
new file mode 100644
index 0000000..ad7e4c6
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Misc/IretHandler.cs
@@ -0,0 +1,44 @@
+namespace X86Disassembler.X86.Handlers.Misc;
+
+///
+/// Handler for IRET/IRETD instruction (0xCF)
+///
+public class IretHandler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the IretHandler class
+ ///
+ /// The instruction decoder that owns this handler
+ public IretHandler(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)
+ {
+ // IRET/IRETD is encoded as 0xCF
+ return opcode == 0xCF;
+ }
+
+ ///
+ /// Decodes an IRET/IRETD 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.Iret;
+
+ // IRET/IRETD has no operands
+ instruction.StructuredOperands = [];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Misc/LockHandler.cs b/X86Disassembler/X86/Handlers/Misc/LockHandler.cs
new file mode 100644
index 0000000..3d13645
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Misc/LockHandler.cs
@@ -0,0 +1,44 @@
+namespace X86Disassembler.X86.Handlers.Misc;
+
+///
+/// Handler for LOCK prefix (0xF0)
+///
+public class LockHandler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the LockHandler class
+ ///
+ /// The instruction decoder that owns this handler
+ public LockHandler(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)
+ {
+ // LOCK prefix is encoded as 0xF0
+ return opcode == 0xF0;
+ }
+
+ ///
+ /// Decodes a LOCK prefix
+ ///
+ /// 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.Lock;
+
+ // LOCK prefix has no operands
+ instruction.StructuredOperands = [];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Misc/OutHandler.cs b/X86Disassembler/X86/Handlers/Misc/OutHandler.cs
new file mode 100644
index 0000000..97d6f39
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Misc/OutHandler.cs
@@ -0,0 +1,95 @@
+using X86Disassembler.X86.Operands;
+
+namespace X86Disassembler.X86.Handlers.Misc;
+
+///
+/// Handler for OUT instruction (0xE6, 0xE7, 0xEE, 0xEF)
+///
+public class OutHandler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the OutHandler class
+ ///
+ /// The instruction decoder that owns this handler
+ public OutHandler(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)
+ {
+ // OUT imm8, AL is encoded as 0xE6
+ // OUT imm8, EAX is encoded as 0xE7
+ // OUT DX, AL is encoded as 0xEE
+ // OUT DX, EAX is encoded as 0xEF
+ return opcode == 0xE6 || opcode == 0xE7 || opcode == 0xEE || opcode == 0xEF;
+ }
+
+ ///
+ /// Decodes an OUT 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.Out;
+
+ // Determine the operands based on the opcode
+ Operand destOperand;
+ Operand srcOperand;
+
+ switch (opcode)
+ {
+ case 0xE6: // OUT imm8, AL
+ // Check if we can read the immediate byte
+ if (!Decoder.CanReadByte())
+ return false;
+
+ // Read the immediate byte (port number)
+ byte imm8 = Decoder.ReadByte();
+ destOperand = OperandFactory.CreateImmediateOperand(imm8);
+ srcOperand = OperandFactory.CreateRegisterOperand8(RegisterIndex8.AL);
+ break;
+
+ case 0xE7: // OUT imm8, EAX
+ // Check if we can read the immediate byte
+ if (!Decoder.CanReadByte())
+ return false;
+
+ // Read the immediate byte (port number)
+ imm8 = Decoder.ReadByte();
+ destOperand = OperandFactory.CreateImmediateOperand(imm8);
+ srcOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.A, 32);
+ break;
+
+ case 0xEE: // OUT DX, AL
+ destOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.D, 16);
+ srcOperand = OperandFactory.CreateRegisterOperand8(RegisterIndex8.AL);
+ break;
+
+ case 0xEF: // OUT DX, EAX
+ destOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.D, 16);
+ srcOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.A, 32);
+ break;
+
+ default:
+ return false;
+ }
+
+ // Set the structured operands
+ instruction.StructuredOperands =
+ [
+ destOperand,
+ srcOperand
+ ];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Misc/RdtscHandler.cs b/X86Disassembler/X86/Handlers/Misc/RdtscHandler.cs
new file mode 100644
index 0000000..daa08a0
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Misc/RdtscHandler.cs
@@ -0,0 +1,59 @@
+namespace X86Disassembler.X86.Handlers.Misc;
+
+///
+/// Handler for RDTSC instruction (0x0F 0x31)
+///
+public class RdtscHandler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the RdtscHandler class
+ ///
+ /// The instruction decoder that owns this handler
+ public RdtscHandler(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)
+ {
+ // RDTSC is encoded as 0x0F 0x31
+ if (opcode != 0x0F)
+ return false;
+
+ // Check if we can read the second byte
+ if (!Decoder.CanReadByte())
+ return false;
+
+ // Check if the second byte is 0x31
+ byte secondByte = Decoder.PeakByte();
+ return secondByte == 0x31;
+ }
+
+ ///
+ /// Decodes a RDTSC 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.Rdtsc;
+
+ // Read and discard the second byte (0x31)
+ if (!Decoder.CanReadByte())
+ return false;
+
+ Decoder.ReadByte();
+
+ // RDTSC has no operands
+ instruction.StructuredOperands = [];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Misc/WaitHandler.cs b/X86Disassembler/X86/Handlers/Misc/WaitHandler.cs
new file mode 100644
index 0000000..7ae2d51
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Misc/WaitHandler.cs
@@ -0,0 +1,44 @@
+namespace X86Disassembler.X86.Handlers.Misc;
+
+///
+/// Handler for WAIT/FWAIT instruction (0x9B)
+///
+public class WaitHandler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the WaitHandler class
+ ///
+ /// The instruction decoder that owns this handler
+ public WaitHandler(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)
+ {
+ // WAIT/FWAIT is encoded as 0x9B
+ return opcode == 0x9B;
+ }
+
+ ///
+ /// Decodes a WAIT/FWAIT 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.Wait;
+
+ // WAIT/FWAIT has no operands
+ instruction.StructuredOperands = [];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/InstructionDecoder.cs b/X86Disassembler/X86/InstructionDecoder.cs
index 3affd5a..22be9cb 100644
--- a/X86Disassembler/X86/InstructionDecoder.cs
+++ b/X86Disassembler/X86/InstructionDecoder.cs
@@ -45,7 +45,7 @@ public class InstructionDecoder
_prefixDecoder = new PrefixDecoder();
// Create the instruction handler factory
- _handlerFactory = new InstructionHandlerFactory(_codeBuffer, this, _length);
+ _handlerFactory = new InstructionHandlerFactory(this);
}
///
@@ -131,15 +131,6 @@ public class InstructionDecoder
}
}
}
-
- // For MOV instructions with segment override prefixes in tests, skip the remaining bytes
- // This is a special case handling for the segment override tests
- if (handlerSuccess && hasSegmentOverride && instruction.Type == InstructionType.Mov)
- {
- // Skip to the end of the buffer for MOV instructions with segment override prefixes
- // This is needed for the segment override tests
- _position = _length;
- }
}
else
{
@@ -159,16 +150,24 @@ public class InstructionDecoder
if (_prefixDecoder.HasRepPrefix())
{
// Map instruction types with REP prefix to specific REP-prefixed instruction types
+ // Note: REP and REPE are the same prefix (0xF3)
instruction.Type = instruction.Type switch
{
InstructionType.MovsB => InstructionType.RepMovsB,
+ InstructionType.MovsW => InstructionType.RepMovsW,
InstructionType.MovsD => InstructionType.RepMovsD,
InstructionType.StosB => InstructionType.RepStosB,
+ InstructionType.StosW => InstructionType.RepStosW,
InstructionType.StosD => InstructionType.RepStosD,
InstructionType.LodsB => InstructionType.RepLodsB,
+ InstructionType.LodsW => InstructionType.RepLodsW,
InstructionType.LodsD => InstructionType.RepLodsD,
InstructionType.ScasB => InstructionType.RepScasB,
+ InstructionType.ScasW => InstructionType.RepScasW,
InstructionType.ScasD => InstructionType.RepScasD,
+ InstructionType.CmpsB => InstructionType.RepeCmpsB,
+ InstructionType.CmpsW => InstructionType.RepeCmpsW,
+ InstructionType.CmpsD => InstructionType.RepeCmpsD,
_ => instruction.Type // Keep original type for other instructions
};
}
@@ -177,8 +176,15 @@ public class InstructionDecoder
// Map instruction types with REPNE prefix to specific REPNE-prefixed instruction types
instruction.Type = instruction.Type switch
{
+ InstructionType.StosB => InstructionType.RepneStosB,
+ InstructionType.StosW => InstructionType.RepneStosW,
+ InstructionType.StosD => InstructionType.RepneStosD,
InstructionType.ScasB => InstructionType.RepneScasB,
+ InstructionType.ScasW => InstructionType.RepneScasW,
InstructionType.ScasD => InstructionType.RepneScasD,
+ InstructionType.CmpsB => InstructionType.RepneCmpsB,
+ InstructionType.CmpsW => InstructionType.RepneCmpsW,
+ InstructionType.CmpsD => InstructionType.RepneCmpsD,
_ => instruction.Type // Keep original type for other instructions
};
}
diff --git a/X86Disassembler/X86/PrefixDecoder.cs b/X86Disassembler/X86/PrefixDecoder.cs
index 7b5da9b..14ed32b 100644
--- a/X86Disassembler/X86/PrefixDecoder.cs
+++ b/X86Disassembler/X86/PrefixDecoder.cs
@@ -148,43 +148,4 @@ public class PrefixDecoder
{
return _repnePrefix;
}
-
- ///
- /// Applies the segment override prefix to the operands string if applicable
- ///
- /// The operands string
- /// The operands string with segment override applied
- public string ApplySegmentOverride(string operands)
- {
- if (_segmentOverridePrefix && !string.IsNullOrEmpty(operands))
- {
- // If the instruction has memory operands, add the segment override
- if (operands.Contains("["))
- {
- // Replace the first '[' with the segment override
- return operands.Replace("[", $"{_segmentOverride}:[" );
- }
- }
-
- return operands;
- }
-
- ///
- /// Applies the REP/REPNE prefix to the mnemonic if applicable
- ///
- /// The mnemonic
- /// The mnemonic with REP/REPNE prefix applied
- public string ApplyRepPrefix(string mnemonic)
- {
- if (_repnePrefix && !mnemonic.StartsWith("repne"))
- {
- return $"repne {mnemonic}";
- }
- else if (_repPrefix && !mnemonic.StartsWith("rep"))
- {
- return $"rep {mnemonic}";
- }
-
- return mnemonic;
- }
}
diff --git a/X86DisassemblerTests/InstructionTests/DebugHandlerRegistration.cs b/X86DisassemblerTests/InstructionTests/DebugHandlerRegistration.cs
index 6ed748d..3426f78 100644
--- a/X86DisassemblerTests/InstructionTests/DebugHandlerRegistration.cs
+++ b/X86DisassemblerTests/InstructionTests/DebugHandlerRegistration.cs
@@ -27,7 +27,7 @@ public class DebugHandlerRegistration
// Create a factory
byte[] codeBuffer = new byte[1];
var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length);
- var sut = new InstructionHandlerFactory(codeBuffer, decoder, codeBuffer.Length);
+ var sut = new InstructionHandlerFactory(decoder);
// Get the handlers registered in the factory
var handlers = (List)sut.GetType()
diff --git a/X86DisassemblerTests/InstructionTests/HandlerSelectionTests.cs b/X86DisassemblerTests/InstructionTests/HandlerSelectionTests.cs
index 2472b80..f87fec3 100644
--- a/X86DisassemblerTests/InstructionTests/HandlerSelectionTests.cs
+++ b/X86DisassemblerTests/InstructionTests/HandlerSelectionTests.cs
@@ -18,7 +18,7 @@ public class HandlerSelectionTests
// Arrange
byte[] codeBuffer = new byte[] {0x83, 0xC1, 0x04}; // ADD ecx, 0x04
var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length);
- var factory = new InstructionHandlerFactory(codeBuffer, decoder, codeBuffer.Length);
+ var factory = new InstructionHandlerFactory(decoder);
// Act
var handler = factory.GetHandler(0x83);
diff --git a/X86DisassemblerTests/InstructionTests/InstructionHandlerFactoryTests.cs b/X86DisassemblerTests/InstructionTests/InstructionHandlerFactoryTests.cs
index 5d3d51e..350fe3e 100644
--- a/X86DisassemblerTests/InstructionTests/InstructionHandlerFactoryTests.cs
+++ b/X86DisassemblerTests/InstructionTests/InstructionHandlerFactoryTests.cs
@@ -10,7 +10,7 @@ public class InstructionHandlerFactoryTests
public void Factory_ShouldNotContainDuplicates()
{
byte[] code = new byte[] {0xCC, 0xCC, 0xCC};
- var sut = new InstructionHandlerFactory(code, new InstructionDecoder(code, code.Length), code.Length);
+ var sut = new InstructionHandlerFactory(new InstructionDecoder(code, code.Length));
var handlers = (List) sut.GetType()
.GetField("_handlers", BindingFlags.Instance | BindingFlags.NonPublic)!
@@ -26,7 +26,7 @@ public class InstructionHandlerFactoryTests
public void Factory_ShouldContainAllKnownHandlers()
{
byte[] code = new byte[] {0xCC, 0xCC, 0xCC};
- var sut = new InstructionHandlerFactory(code, new InstructionDecoder(code, code.Length), code.Length);
+ var sut = new InstructionHandlerFactory(new InstructionDecoder(code, code.Length));
var handlers = (List) sut.GetType()
.GetField("_handlers", BindingFlags.Instance | BindingFlags.NonPublic)!