diff --git a/X86Disassembler/X86/Handlers/Ret/Retf16Handler.cs b/X86Disassembler/X86/Handlers/Ret/Retf16Handler.cs
new file mode 100644
index 0000000..8edf8bd
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Ret/Retf16Handler.cs
@@ -0,0 +1,47 @@
+using X86Disassembler.X86.Operands;
+
+namespace X86Disassembler.X86.Handlers.Ret;
+
+///
+/// Handler for RETF instruction with operand size prefix (0xCB with 0x66 prefix)
+///
+public class Retf16Handler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the Retf16Handler class
+ ///
+ /// The instruction decoder that owns this handler
+ public Retf16Handler(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)
+ {
+ // RETF with operand size prefix is encoded as 0xCB with 0x66 prefix
+ // Only handle when the operand size prefix IS present
+ return opcode == 0xCB && Decoder.HasOperandSizePrefix();
+ }
+
+ ///
+ /// Decodes a RETF instruction with operand size 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.Retf;
+
+ // RETF has no operands
+ instruction.StructuredOperands = [];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Ret/RetfHandler.cs b/X86Disassembler/X86/Handlers/Ret/RetfHandler.cs
new file mode 100644
index 0000000..dc6a83f
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Ret/RetfHandler.cs
@@ -0,0 +1,48 @@
+using X86Disassembler.X86.Operands;
+
+namespace X86Disassembler.X86.Handlers.Ret;
+
+///
+/// Handler for RETF instruction (0xCB)
+///
+public class RetfHandler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the RetfHandler class
+ ///
+ /// The instruction decoder that owns this handler
+ public RetfHandler(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)
+ {
+ // RETF is encoded as 0xCB
+ // Only handle when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return opcode == 0xCB && !Decoder.HasOperandSizePrefix();
+ }
+
+ ///
+ /// Decodes a RETF 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.Retf;
+
+ // RETF has no operands
+ instruction.StructuredOperands = [];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Ret/RetfImm16Handler.cs b/X86Disassembler/X86/Handlers/Ret/RetfImm16Handler.cs
new file mode 100644
index 0000000..f785f1a
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Ret/RetfImm16Handler.cs
@@ -0,0 +1,60 @@
+using X86Disassembler.X86.Operands;
+
+namespace X86Disassembler.X86.Handlers.Ret;
+
+///
+/// Handler for RETF imm16 instruction with operand size prefix (0xCA with 0x66 prefix)
+///
+public class RetfImm16Handler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the RetfImm16Handler class
+ ///
+ /// The instruction decoder that owns this handler
+ public RetfImm16Handler(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)
+ {
+ // RETF imm16 with operand size prefix is encoded as 0xCA with 0x66 prefix
+ // Only handle when the operand size prefix IS present
+ return opcode == 0xCA && Decoder.HasOperandSizePrefix();
+ }
+
+ ///
+ /// Decodes a RETF imm16 instruction with operand size 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.Retf;
+
+ // Check if we can read the immediate word
+ if (!Decoder.CanReadUShort())
+ return false;
+
+ // Read the immediate word (number of bytes to pop from stack)
+ ushort imm16 = Decoder.ReadUInt16();
+
+ // Create an immediate operand for the pop count
+ var immOperand = OperandFactory.CreateImmediateOperand(imm16, 16);
+
+ // Set the structured operands
+ instruction.StructuredOperands =
+ [
+ immOperand
+ ];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/Ret/RetfImmHandler.cs b/X86Disassembler/X86/Handlers/Ret/RetfImmHandler.cs
new file mode 100644
index 0000000..e21ed4a
--- /dev/null
+++ b/X86Disassembler/X86/Handlers/Ret/RetfImmHandler.cs
@@ -0,0 +1,61 @@
+using X86Disassembler.X86.Operands;
+
+namespace X86Disassembler.X86.Handlers.Ret;
+
+///
+/// Handler for RETF imm16 instruction (0xCA)
+///
+public class RetfImmHandler : InstructionHandler
+{
+ ///
+ /// Initializes a new instance of the RetfImmHandler class
+ ///
+ /// The instruction decoder that owns this handler
+ public RetfImmHandler(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)
+ {
+ // RETF imm16 is encoded as 0xCA
+ // Only handle when the operand size prefix is NOT present
+ // This ensures 16-bit handlers get priority when the prefix is present
+ return opcode == 0xCA && !Decoder.HasOperandSizePrefix();
+ }
+
+ ///
+ /// Decodes a RETF 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.Retf;
+
+ // Check if we can read the immediate word
+ if (!Decoder.CanReadUShort())
+ return false;
+
+ // Read the immediate word (number of bytes to pop from stack)
+ ushort imm16 = Decoder.ReadUInt16();
+
+ // Create an immediate operand for the pop count
+ var immOperand = OperandFactory.CreateImmediateOperand(imm16, 16);
+
+ // Set the structured operands
+ instruction.StructuredOperands =
+ [
+ immOperand
+ ];
+
+ return true;
+ }
+}
diff --git a/X86Disassembler/X86/Handlers/String/StringInstructionHandler.cs b/X86Disassembler/X86/Handlers/String/StringInstructionHandler.cs
index 376d6db..9816780 100644
--- a/X86Disassembler/X86/Handlers/String/StringInstructionHandler.cs
+++ b/X86Disassembler/X86/Handlers/String/StringInstructionHandler.cs
@@ -3,47 +3,67 @@ namespace X86Disassembler.X86.Handlers.String;
using Operands;
///
-/// Handler for string instructions (MOVS, STOS, LODS, SCAS) with and without REP/REPNE prefixes
+/// Handler for string instructions (MOVS, CMPS, STOS, LODS, SCAS)
+/// The REP/REPNE prefixes are handled by the InstructionDecoder class
///
public class StringInstructionHandler : InstructionHandler
{
- // Dictionary mapping opcodes to their instruction types and operand factories
- private static readonly Dictionary CreateOperands)> StringInstructions = new()
+ // Dictionary mapping opcodes to their instruction types and operand factories for 32-bit mode (default)
+ private static readonly Dictionary CreateOperands)> StringInstructions32 = new()
{
+ // MOVS instructions
{ 0xA4, (InstructionType.MovsB, () =>
[
- OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 8, "es"),
- OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Si, 8, "ds")
+ OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Di, "es"),
+ OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Si, "ds")
]) }, // MOVSB
{ 0xA5, (InstructionType.MovsD, () =>
[
OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 32, "es"),
OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Si, 32, "ds")
- ]) }, // MOVSD
+ ]) }, // MOVSD
+
+ // CMPS instructions
+ { 0xA6, (InstructionType.CmpsB, () =>
+ [
+ OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Si, "ds"),
+ OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Di, "es")
+ ]) }, // CMPSB
+ { 0xA7, (InstructionType.CmpsD, () =>
+ [
+ OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Si, 32, "ds"),
+ OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 32, "es")
+ ]) }, // CMPSD
+
+ // STOS instructions
{ 0xAA, (InstructionType.StosB, () =>
[
- OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 8, "es"),
- OperandFactory.CreateRegisterOperand(RegisterIndex.A, 8)
+ OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Di, "es"),
+ OperandFactory.CreateRegisterOperand8(RegisterIndex8.AL)
]) }, // STOSB
{ 0xAB, (InstructionType.StosD, () =>
[
OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 32, "es"),
OperandFactory.CreateRegisterOperand(RegisterIndex.A, 32)
]) }, // STOSD
+
+ // LODS instructions
{ 0xAC, (InstructionType.LodsB, () =>
[
- OperandFactory.CreateRegisterOperand(RegisterIndex.A, 8),
- OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Si, 8, "ds")
+ OperandFactory.CreateRegisterOperand8(RegisterIndex8.AL),
+ OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Si, "ds")
]) }, // LODSB
{ 0xAD, (InstructionType.LodsD, () =>
[
OperandFactory.CreateRegisterOperand(RegisterIndex.A, 32),
OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Si, 32, "ds")
]) }, // LODSD
+
+ // SCAS instructions
{ 0xAE, (InstructionType.ScasB, () =>
[
- OperandFactory.CreateRegisterOperand(RegisterIndex.A, 8),
- OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 8, "es")
+ OperandFactory.CreateRegisterOperand8(RegisterIndex8.AL),
+ OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Di, "es")
]) }, // SCASB
{ 0xAF, (InstructionType.ScasD, () =>
[
@@ -52,28 +72,68 @@ public class StringInstructionHandler : InstructionHandler
]) } // SCASD
};
- // REP/REPNE prefix opcodes
- private const byte REP_PREFIX = 0xF3;
- private const byte REPNE_PREFIX = 0xF2;
-
- // Dictionary mapping base instruction types to their REP-prefixed versions
- private static readonly Dictionary RepPrefixMap = new()
+ // Dictionary mapping opcodes to their instruction types and operand factories for 16-bit mode (with operand size prefix)
+ private static readonly Dictionary CreateOperands)> StringInstructions16 = new()
{
- { InstructionType.MovsB, InstructionType.RepMovsB },
- { InstructionType.MovsD, InstructionType.RepMovsD },
- { InstructionType.StosB, InstructionType.RepStosB },
- { InstructionType.StosD, InstructionType.RepStosD },
- { InstructionType.LodsB, InstructionType.RepLodsB },
- { InstructionType.LodsD, InstructionType.RepLodsD },
- { InstructionType.ScasB, InstructionType.RepScasB },
- { InstructionType.ScasD, InstructionType.RepScasD }
- };
-
- // Dictionary mapping base instruction types to their REPNE-prefixed versions
- private static readonly Dictionary RepnePrefixMap = new()
- {
- { InstructionType.ScasB, InstructionType.RepneScasB },
- { InstructionType.ScasD, InstructionType.RepneScasD }
+ // MOVS instructions
+ { 0xA4, (InstructionType.MovsB, () =>
+ [
+ OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Di, "es"),
+ OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Si, "ds")
+ ]) }, // MOVSB (same for 16-bit)
+ { 0xA5, (InstructionType.MovsW, () =>
+ [
+ OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 16, "es"),
+ OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Si, 16, "ds")
+ ]) }, // MOVSW
+
+ // CMPS instructions
+ { 0xA6, (InstructionType.CmpsB, () =>
+ [
+ OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Si, "ds"),
+ OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Di, "es")
+ ]) }, // CMPSB (same for 16-bit)
+ { 0xA7, (InstructionType.CmpsW, () =>
+ [
+ OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Si, 16, "ds"),
+ OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 16, "es")
+ ]) }, // CMPSW
+
+ // STOS instructions
+ { 0xAA, (InstructionType.StosB, () =>
+ [
+ OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Di, "es"),
+ OperandFactory.CreateRegisterOperand8(RegisterIndex8.AL)
+ ]) }, // STOSB (same for 16-bit)
+ { 0xAB, (InstructionType.StosW, () =>
+ [
+ OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 16, "es"),
+ OperandFactory.CreateRegisterOperand(RegisterIndex.A, 16)
+ ]) }, // STOSW
+
+ // LODS instructions
+ { 0xAC, (InstructionType.LodsB, () =>
+ [
+ OperandFactory.CreateRegisterOperand8(RegisterIndex8.AL),
+ OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Si, "ds")
+ ]) }, // LODSB (same for 16-bit)
+ { 0xAD, (InstructionType.LodsW, () =>
+ [
+ OperandFactory.CreateRegisterOperand(RegisterIndex.A, 16),
+ OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Si, 16, "ds")
+ ]) }, // LODSW
+
+ // SCAS instructions
+ { 0xAE, (InstructionType.ScasB, () =>
+ [
+ OperandFactory.CreateRegisterOperand8(RegisterIndex8.AL),
+ OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Di, "es")
+ ]) }, // SCASB (same for 16-bit)
+ { 0xAF, (InstructionType.ScasW, () =>
+ [
+ OperandFactory.CreateRegisterOperand(RegisterIndex.A, 16),
+ OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 16, "es")
+ ]) } // SCASW
};
///
@@ -92,27 +152,8 @@ public class StringInstructionHandler : InstructionHandler
/// True if this handler can handle the opcode
public override bool CanHandle(byte opcode)
{
- // Check if the opcode is a string instruction
- if (StringInstructions.ContainsKey(opcode))
- {
- return true;
- }
-
- // Check if the opcode is a REP/REPNE prefix followed by a string instruction
- if (opcode != REP_PREFIX && opcode != REPNE_PREFIX)
- {
- return false;
- }
-
- // Check if we can read the next byte
- if (!Decoder.CanReadByte())
- {
- return false;
- }
-
- // Check if the next byte is a string instruction
- byte nextByte = Decoder.PeakByte();
- return StringInstructions.ContainsKey(nextByte);
+ // Check if the opcode is a string instruction in either 16-bit or 32-bit mode
+ return StringInstructions32.ContainsKey(opcode);
}
///
@@ -123,59 +164,19 @@ public class StringInstructionHandler : InstructionHandler
/// True if the instruction was successfully decoded
public override bool Decode(byte opcode, Instruction instruction)
{
- // Check if this is a REP/REPNE prefix
- bool hasRepPrefix = opcode == REP_PREFIX || opcode == REPNE_PREFIX;
+ // Select the appropriate dictionary based on operand size prefix
+ var instructionsDict = Decoder.HasOperandSizePrefix()
+ ? StringInstructions16
+ : StringInstructions32;
- // If this is a REP/REPNE prefix, get the actual string instruction opcode
- byte stringOpcode = opcode;
-
- if (hasRepPrefix)
- {
- // Read the next byte (the actual string instruction opcode)
- if (!Decoder.CanReadByte())
- {
- return false;
- }
-
- stringOpcode = Decoder.ReadByte();
-
- if (!StringInstructions.ContainsKey(stringOpcode))
- {
- return false;
- }
- }
-
// Get the instruction type and operands for the string instruction
- if (StringInstructions.TryGetValue(stringOpcode, out var instructionInfo))
+ if (instructionsDict.TryGetValue(opcode, out var instructionInfo))
{
- // Set the instruction type based on whether there's a REP/REPNE prefix
- if (hasRepPrefix)
- {
- // Determine the appropriate prefixed instruction type based on the prefix
- if (opcode == REP_PREFIX)
- {
- // Use the REP prefix map to get the prefixed instruction type
- instruction.Type = RepPrefixMap.TryGetValue(instructionInfo.Type, out var repType)
- ? repType
- : instructionInfo.Type;
- }
- else // REPNE prefix
- {
- // Use the REPNE prefix map to get the prefixed instruction type
- instruction.Type = RepnePrefixMap.TryGetValue(instructionInfo.Type, out var repneType)
- ? repneType
- : instructionInfo.Type;
- }
- }
- else
- {
- // No prefix, use the original instruction type
- instruction.Type = instructionInfo.Type;
- }
+ // Set the instruction type
+ instruction.Type = instructionInfo.Type;
// Create and set the structured operands
instruction.StructuredOperands = instructionInfo.CreateOperands().ToList();
-
return true;
}
diff --git a/X86Disassembler/X86/InstructionType.cs b/X86Disassembler/X86/InstructionType.cs
index 91ef202..25999f1 100644
--- a/X86Disassembler/X86/InstructionType.cs
+++ b/X86Disassembler/X86/InstructionType.cs
@@ -101,9 +101,6 @@ public enum InstructionType
// Lods = LodsD, // Alias for LodsD - removed alias to avoid switch expression issues
// REP prefixed instructions
- Rep, // REP prefix
- RepE, // REPE/REPZ prefix
- RepNE, // REPNE/REPNZ prefix
// RepneScas = RepNE, // Alias for RepNE - removed alias to avoid switch expression issues
RepMovsB, // REP MOVSB
RepMovsW, // REP MOVSW
diff --git a/X86Disassembler/X86/ModRMDecoder.cs b/X86Disassembler/X86/ModRMDecoder.cs
index bab564f..66ca3bb 100644
--- a/X86Disassembler/X86/ModRMDecoder.cs
+++ b/X86Disassembler/X86/ModRMDecoder.cs
@@ -271,8 +271,8 @@ public class ModRMDecoder
byte rmIndex = (byte)(modRM & Constants.RM_MASK);
// Map the ModR/M register indices to RegisterIndex enum values
- RegisterIndex reg = RegisterMapper.MapModRMToRegisterIndex(regIndex);
- RegisterIndex rm = RegisterMapper.MapModRMToRegisterIndex(rmIndex);
+ RegisterIndex reg = (RegisterIndex)regIndex;
+ RegisterIndex rm = (RegisterIndex)rmIndex;
// Create the operand based on the mod and rm fields
Operand operand = DecodeModRM(mod, rm, is64Bit);
@@ -299,8 +299,8 @@ public class ModRMDecoder
byte rmIndex = (byte)(modRM & Constants.RM_MASK);
// Map the ModR/M register indices to RegisterIndex8 enum values
- RegisterIndex8 reg = RegisterMapper.MapModRMToRegisterIndex8(regIndex);
- RegisterIndex8 rm = RegisterMapper.MapModRMToRegisterIndex8(rmIndex);
+ RegisterIndex8 reg = (RegisterIndex8)regIndex;
+ RegisterIndex8 rm = (RegisterIndex8)rmIndex;
// Create the operand based on the mod and rm fields
Operand operand;
@@ -315,7 +315,7 @@ public class ModRMDecoder
// For memory operands, we need to map the RegisterIndex8 to RegisterIndex for base registers
// The rmIndex is the raw value from the ModR/M byte, not the mapped RegisterIndex8
// This is important because we need to check if it's 4 (ESP) for SIB byte
- RegisterIndex rmRegIndex = RegisterMapper.MapModRMToRegisterIndex(rmIndex);
+ RegisterIndex rmRegIndex = (RegisterIndex)rmIndex;
// Use the DecodeModRM8 method to get an 8-bit memory operand
operand = DecodeModRM8(mod, rmRegIndex);
diff --git a/X86Disassembler/X86/RegisterMapper.cs b/X86Disassembler/X86/RegisterMapper.cs
index ad4f95a..ef51d99 100644
--- a/X86Disassembler/X86/RegisterMapper.cs
+++ b/X86Disassembler/X86/RegisterMapper.cs
@@ -1,76 +1,10 @@
namespace X86Disassembler.X86;
-using Operands;
-
///
/// Handles mapping between register indices and register enums
///
public static class RegisterMapper
{
- ///
- /// Maps the register index from the ModR/M byte to the RegisterIndex enum value
- ///
- /// The register index from the ModR/M byte (0-7)
- /// The corresponding RegisterIndex enum value
- public static RegisterIndex MapModRMToRegisterIndex(int modRMRegIndex)
- {
- // The mapping from ModR/M 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)
- return modRMRegIndex 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 to EAX
- };
- }
-
- ///
- /// Maps the register index from the ModR/M byte to the RegisterIndex8 enum value
- ///
- /// The register index from the ModR/M byte (0-7)
- /// The corresponding RegisterIndex8 enum value
- public static RegisterIndex8 MapModRMToRegisterIndex8(int modRMRegIndex)
- {
- // The mapping from ModR/M register index to RegisterIndex8 enum is direct:
- // 0 -> AL, 1 -> CL, 2 -> DL, 3 -> BL, 4 -> AH, 5 -> CH, 6 -> DH, 7 -> BH
- return (RegisterIndex8)modRMRegIndex;
- }
-
- ///
- /// Maps a RegisterIndex8 enum value to the corresponding RegisterIndex enum value for base registers
- ///
- /// The RegisterIndex8 enum value
- /// The corresponding RegisterIndex enum value
- public static RegisterIndex MapRegister8ToBaseRegister(RegisterIndex8 regIndex8)
- {
- // Map 8-bit register indices to their corresponding 32-bit register indices
- return regIndex8 switch
- {
- RegisterIndex8.AL => RegisterIndex.A,
- RegisterIndex8.CL => RegisterIndex.C,
- RegisterIndex8.DL => RegisterIndex.D,
- RegisterIndex8.BL => RegisterIndex.B,
- RegisterIndex8.AH => RegisterIndex.A,
- RegisterIndex8.CH => RegisterIndex.C,
- RegisterIndex8.DH => RegisterIndex.D,
- RegisterIndex8.BH => RegisterIndex.B,
- _ => RegisterIndex.A // Default to EAX
- };
- }
-
///
/// Gets the register name based on the register index and size
///
diff --git a/X86Disassembler/X86/SIBDecoder.cs b/X86Disassembler/X86/SIBDecoder.cs
index 7432d38..82b3a0b 100644
--- a/X86Disassembler/X86/SIBDecoder.cs
+++ b/X86Disassembler/X86/SIBDecoder.cs
@@ -34,8 +34,8 @@ public class SIBDecoder
int baseIndex = sib & Constants.SIB_BASE_MASK;
// Map the SIB register indices to RegisterIndex enum values
- RegisterIndex index = RegisterMapper.MapModRMToRegisterIndex(indexIndex);
- RegisterIndex @base = RegisterMapper.MapModRMToRegisterIndex(baseIndex);
+ RegisterIndex index = (RegisterIndex)indexIndex;
+ RegisterIndex @base = (RegisterIndex)baseIndex;
// Special case: ESP/SP (4) in index field means no index register
if (index == RegisterIndex.Sp)
diff --git a/X86DisassemblerTests/InstructionTests/Int3InstructionTests.cs b/X86DisassemblerTests/InstructionTests/Int3InstructionTests.cs
index 95a1b09..1c89ca7 100644
--- a/X86DisassemblerTests/InstructionTests/Int3InstructionTests.cs
+++ b/X86DisassemblerTests/InstructionTests/Int3InstructionTests.cs
@@ -24,7 +24,7 @@ public class Int3InstructionTests
// Assert
Assert.NotNull(instruction);
- Assert.Equal(InstructionType.Int, instruction.Type);
+ Assert.Equal(InstructionType.Int3, instruction.Type);
// Check that we have no operands
Assert.Empty(instruction.StructuredOperands);
diff --git a/X86DisassemblerTests/InstructionTests/StringInstructionHandlerTests.cs b/X86DisassemblerTests/InstructionTests/StringInstructionHandlerTests.cs
index f87601a..f78f46d 100644
--- a/X86DisassemblerTests/InstructionTests/StringInstructionHandlerTests.cs
+++ b/X86DisassemblerTests/InstructionTests/StringInstructionHandlerTests.cs
@@ -154,9 +154,9 @@ public class StringInstructionHandlerTests
// Check the second operand (AL)
var alOperand = instruction.StructuredOperands[1];
- Assert.IsType(alOperand);
- var registerOperand = (RegisterOperand)alOperand;
- Assert.Equal(RegisterIndex.A, registerOperand.Register);
+ Assert.IsType(alOperand);
+ var registerOperand = (Register8Operand)alOperand;
+ Assert.Equal(RegisterIndex8.AL, registerOperand.Register);
Assert.Equal(8, registerOperand.Size); // Validate that it's an 8-bit register (AL)
}
@@ -223,9 +223,9 @@ public class StringInstructionHandlerTests
// Check the first operand (AL)
var alOperand = instruction.StructuredOperands[0];
- Assert.IsType(alOperand);
- var registerOperand = (RegisterOperand)alOperand;
- Assert.Equal(RegisterIndex.A, registerOperand.Register);
+ Assert.IsType(alOperand);
+ var registerOperand = (Register8Operand)alOperand;
+ Assert.Equal(RegisterIndex8.AL, registerOperand.Register);
Assert.Equal(8, registerOperand.Size); // Validate that it's an 8-bit register (AL)
// Check the second operand (memory operand)
diff --git a/X86DisassemblerTests/TestData/ret_tests.csv b/X86DisassemblerTests/TestData/ret_tests.csv
index b0feb18..6231c4b 100644
--- a/X86DisassemblerTests/TestData/ret_tests.csv
+++ b/X86DisassemblerTests/TestData/ret_tests.csv
@@ -16,8 +16,8 @@ C2FFFF;[{ "Type": "Ret", "Operands": ["0xFFFF"] }]
CB;[{ "Type": "Retf", "Operands": [] }]
# RETF imm16 (opcode CA) - Far return to calling procedure and pop imm16 bytes from stack
-CA0000;[{ "Type": "Retf", "Operands": ["0x0000"] }]
-CA0400;[{ "Type": "Retf", "Operands": ["0x0004"] }]
-CA0800;[{ "Type": "Retf", "Operands": ["0x0008"] }]
-CA1000;[{ "Type": "Retf", "Operands": ["0x0010"] }]
+CA0000;[{ "Type": "Retf", "Operands": ["0x00"] }]
+CA0400;[{ "Type": "Retf", "Operands": ["0x04"] }]
+CA0800;[{ "Type": "Retf", "Operands": ["0x08"] }]
+CA1000;[{ "Type": "Retf", "Operands": ["0x10"] }]
CAFFFF;[{ "Type": "Retf", "Operands": ["0xFFFF"] }]
diff --git a/X86DisassemblerTests/TestData/sbb_tests.csv b/X86DisassemblerTests/TestData/sbb_tests.csv
index ab30f0a..69f7565 100644
--- a/X86DisassemblerTests/TestData/sbb_tests.csv
+++ b/X86DisassemblerTests/TestData/sbb_tests.csv
@@ -12,7 +12,7 @@ RawBytes;Instructions
83D842;[{ "Type": "Sbb", "Operands": ["eax", "0x42"] }]
# SBB with memory operands
-811C2578563412;[{ "Type": "Sbb", "Operands": ["dword ptr [eax]", "0x12345678"] }]
+811878563412;[{ "Type": "Sbb", "Operands": ["dword ptr [eax]", "0x12345678"] }]
# SBB r/m32, r32 (opcode 19)
19D8;[{ "Type": "Sbb", "Operands": ["eax", "ebx"] }]
diff --git a/X86DisassemblerTests/TestData/string_tests.csv b/X86DisassemblerTests/TestData/string_tests.csv
index 54d567a..57cf024 100644
--- a/X86DisassemblerTests/TestData/string_tests.csv
+++ b/X86DisassemblerTests/TestData/string_tests.csv
@@ -18,9 +18,9 @@ AF;[{ "Type": "ScasD", "Operands": ["eax", "dword ptr es:[edi]"] }]
66AF;[{ "Type": "ScasW", "Operands": ["ax", "word ptr es:[edi]"] }]
# LODS - Load string
-AC;[{ "Type": "LodsB", "Operands": ["al", "byte ptr es:[esi]"] }]
-AD;[{ "Type": "LodsD", "Operands": ["eax", "dword ptr es:[esi]"] }]
-66AD;[{ "Type": "LodsW", "Operands": ["ax", "byte ptr es:[esi]"] }]
+AC;[{ "Type": "LodsB", "Operands": ["al", "byte ptr ds:[esi]"] }]
+AD;[{ "Type": "LodsD", "Operands": ["eax", "dword ptr ds:[esi]"] }]
+66AD;[{ "Type": "LodsW", "Operands": ["ax", "byte ptr ds:[esi]"] }]
# STOS - Store string
AA;[{ "Type": "StosB", "Operands": ["byte ptr es:[edi]", "al"] }]