diff --git a/X86Disassembler/X86/Handlers/Add/AddR8Rm8Handler.cs b/X86Disassembler/X86/Handlers/Add/AddR8Rm8Handler.cs
index b09233c..6e74d50 100644
--- a/X86Disassembler/X86/Handlers/Add/AddR8Rm8Handler.cs
+++ b/X86Disassembler/X86/Handlers/Add/AddR8Rm8Handler.cs
@@ -51,7 +51,7 @@ public class AddR8Rm8Handler : InstructionHandler
var (_, reg, _, sourceOperand) = ModRMDecoder.ReadModRM8();
// Create the destination register operand
- var destinationOperand = OperandFactory.CreateRegisterOperand(reg, 8);
+ var destinationOperand = OperandFactory.CreateRegisterOperand8(reg);
// Set the structured operands
instruction.StructuredOperands =
diff --git a/X86Disassembler/X86/Handlers/Add/AddRm8R8Handler.cs b/X86Disassembler/X86/Handlers/Add/AddRm8R8Handler.cs
index b7d17ed..3fbfc62 100644
--- a/X86Disassembler/X86/Handlers/Add/AddRm8R8Handler.cs
+++ b/X86Disassembler/X86/Handlers/Add/AddRm8R8Handler.cs
@@ -50,9 +50,8 @@ public class AddRm8R8Handler : InstructionHandler
// - The r/m field with mod specifies the destination operand (register or memory)
var (_, reg, _, destinationOperand) = ModRMDecoder.ReadModRM8();
- // Create the source register operand
- // For high registers, we need to set the IsHighRegister flag
- var sourceOperand = OperandFactory.CreateRegisterOperand(reg, 8);
+ // Create the source register operand using the 8-bit register type
+ var sourceOperand = OperandFactory.CreateRegisterOperand8(reg);
// Set the structured operands
instruction.StructuredOperands =
diff --git a/X86Disassembler/X86/Handlers/Or/OrRm8R8Handler.cs b/X86Disassembler/X86/Handlers/Or/OrRm8R8Handler.cs
index 71fd2f9..7ec77b6 100644
--- a/X86Disassembler/X86/Handlers/Or/OrRm8R8Handler.cs
+++ b/X86Disassembler/X86/Handlers/Or/OrRm8R8Handler.cs
@@ -56,8 +56,8 @@ public class OrRm8R8Handler : InstructionHandler
// Adjust the operand size to 8-bit
destinationOperand.Size = 8;
- // Create the source register operand (8-bit)
- var sourceOperand = OperandFactory.CreateRegisterOperand(reg, 8);
+ // Create the source register operand using the 8-bit register type
+ var sourceOperand = OperandFactory.CreateRegisterOperand8(reg);
// Set the structured operands
instruction.StructuredOperands =
diff --git a/X86Disassembler/X86/Handlers/Sub/SubR8Rm8Handler.cs b/X86Disassembler/X86/Handlers/Sub/SubR8Rm8Handler.cs
index f794a27..d704782 100644
--- a/X86Disassembler/X86/Handlers/Sub/SubR8Rm8Handler.cs
+++ b/X86Disassembler/X86/Handlers/Sub/SubR8Rm8Handler.cs
@@ -48,8 +48,8 @@ public class SubR8Rm8Handler : InstructionHandler
// Ensure the source operand has the correct size (8-bit)
sourceOperand.Size = 8;
- // Create the destination register operand
- var destinationOperand = OperandFactory.CreateRegisterOperand(reg, 8);
+ // Create the destination register operand using the 8-bit register type
+ var destinationOperand = OperandFactory.CreateRegisterOperand8(reg);
// Set the structured operands
instruction.StructuredOperands =
diff --git a/X86Disassembler/X86/Handlers/Sub/SubRm8R8Handler.cs b/X86Disassembler/X86/Handlers/Sub/SubRm8R8Handler.cs
index c8a47fc..3f15be1 100644
--- a/X86Disassembler/X86/Handlers/Sub/SubRm8R8Handler.cs
+++ b/X86Disassembler/X86/Handlers/Sub/SubRm8R8Handler.cs
@@ -43,8 +43,8 @@ public class SubRm8R8Handler : InstructionHandler
// Ensure the destination operand has the correct size (8-bit)
destinationOperand.Size = 8;
- // Create the source register operand
- var sourceOperand = OperandFactory.CreateRegisterOperand(reg, 8);
+ // Create the source register operand using the 8-bit register type
+ var sourceOperand = OperandFactory.CreateRegisterOperand8(reg);
// Set the structured operands
instruction.StructuredOperands =
diff --git a/X86Disassembler/X86/Handlers/Test/TestRegMem8Handler.cs b/X86Disassembler/X86/Handlers/Test/TestRegMem8Handler.cs
index 546bc6e..13db1db 100644
--- a/X86Disassembler/X86/Handlers/Test/TestRegMem8Handler.cs
+++ b/X86Disassembler/X86/Handlers/Test/TestRegMem8Handler.cs
@@ -49,14 +49,14 @@ public class TestRegMem8Handler : InstructionHandler
// Ensure the destination operand has the correct size (8-bit)
destOperand.Size = 8;
- // Create the register operand for the reg field (8-bit)
- var regOperand = OperandFactory.CreateRegisterOperand(reg, 8);
+ // Create the register operand for the reg field using the 8-bit register type
+ var regOperand = OperandFactory.CreateRegisterOperand8(reg);
// Set the structured operands based on addressing mode
if (mod == 3) // Direct register addressing
{
- // Create the register operand for the r/m field (8-bit)
- var rmOperand = OperandFactory.CreateRegisterOperand(rm, 8);
+ // Create the register operand for the r/m field using the 8-bit register type
+ var rmOperand = OperandFactory.CreateRegisterOperand8(rm);
// Set the structured operands
instruction.StructuredOperands =
diff --git a/X86Disassembler/X86/Handlers/Xor/XorR8Rm8Handler.cs b/X86Disassembler/X86/Handlers/Xor/XorR8Rm8Handler.cs
index 6c42bf8..490e691 100644
--- a/X86Disassembler/X86/Handlers/Xor/XorR8Rm8Handler.cs
+++ b/X86Disassembler/X86/Handlers/Xor/XorR8Rm8Handler.cs
@@ -43,8 +43,8 @@ public class XorR8Rm8Handler : InstructionHandler
// Ensure the source operand has the correct size (8-bit)
sourceOperand.Size = 8;
- // Create the destination register operand
- var destinationOperand = OperandFactory.CreateRegisterOperand(reg, 8);
+ // Create the destination register operand using the 8-bit register type
+ var destinationOperand = OperandFactory.CreateRegisterOperand8(reg);
// Set the structured operands
instruction.StructuredOperands =
diff --git a/X86Disassembler/X86/Handlers/Xor/XorRm8R8Handler.cs b/X86Disassembler/X86/Handlers/Xor/XorRm8R8Handler.cs
index e8d107b..49bc3f2 100644
--- a/X86Disassembler/X86/Handlers/Xor/XorRm8R8Handler.cs
+++ b/X86Disassembler/X86/Handlers/Xor/XorRm8R8Handler.cs
@@ -43,8 +43,8 @@ public class XorRm8R8Handler : InstructionHandler
// Ensure the destination operand has the correct size (8-bit)
destinationOperand.Size = 8;
- // Create the source register operand
- var sourceOperand = OperandFactory.CreateRegisterOperand(reg, 8);
+ // Create the source register operand using the 8-bit register type
+ var sourceOperand = OperandFactory.CreateRegisterOperand8(reg);
// Set the structured operands
instruction.StructuredOperands =
diff --git a/X86Disassembler/X86/ModRMDecoder.cs b/X86Disassembler/X86/ModRMDecoder.cs
index fd0e176..aa009f3 100644
--- a/X86Disassembler/X86/ModRMDecoder.cs
+++ b/X86Disassembler/X86/ModRMDecoder.cs
@@ -18,7 +18,6 @@ public class ModRMDecoder
private const byte SIB_BASE_MASK = 0x07; // 00000111b
// Register names for different sizes
- private static readonly string[] RegisterNames8 = {"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"};
private static readonly string[] RegisterNames16 = {"ax", "cx", "dx", "bx", "sp", "bp", "si", "di"};
private static readonly string[] RegisterNames32 = {"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"};
@@ -65,21 +64,15 @@ public class ModRMDecoder
}
///
- /// Maps the register index from the ModR/M byte to the RegisterIndex enum value for 8-bit high registers
+ /// 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 RegisterIndex enum value for 8-bit high registers
- private RegisterIndex MapModRMToHighRegister8Index(int modRMRegIndex)
+ /// The corresponding RegisterIndex8 enum value
+ private RegisterIndex8 MapModRMToRegisterIndex8(int modRMRegIndex)
{
- // For 8-bit high registers (AH, CH, DH, BH), the mapping is different
- return modRMRegIndex switch
- {
- 4 => RegisterIndex.A, // AH
- 5 => RegisterIndex.C, // CH
- 6 => RegisterIndex.D, // DH
- 7 => RegisterIndex.B, // BH
- _ => MapModRMToRegisterIndex(modRMRegIndex) // Fall back to normal mapping for other indices
- };
+ // 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;
}
///
@@ -255,7 +248,7 @@ public class ModRMDecoder
/// A tuple containing the mod, reg, rm fields and the decoded operand
public (byte mod, RegisterIndex reg, RegisterIndex rm, Operand operand) ReadModRM()
{
- return ReadModRMInternal(false, false);
+ return ReadModRMInternal(false);
}
///
@@ -264,29 +257,28 @@ public class ModRMDecoder
/// A tuple containing the mod, reg, rm fields and the decoded operand
public (byte mod, RegisterIndex reg, RegisterIndex rm, Operand operand) ReadModRM64()
{
- return ReadModRMInternal(true, false);
+ return ReadModRMInternal(true);
}
///
/// Reads and decodes a ModR/M byte for 8-bit operands
///
/// A tuple containing the mod, reg, rm fields and the decoded operand
- public (byte mod, RegisterIndex reg, RegisterIndex rm, Operand operand) ReadModRM8()
+ public (byte mod, RegisterIndex8 reg, RegisterIndex8 rm, Operand operand) ReadModRM8()
{
- return ReadModRMInternal(false, true);
+ return ReadModRM8Internal();
}
///
- /// Internal implementation for reading and decoding a ModR/M byte
+ /// Internal implementation for reading and decoding a ModR/M byte for standard 32-bit or 64-bit operands
///
/// True if the operand is 64-bit
- /// True if the operand is 8-bit
/// A tuple containing the mod, reg, rm fields and the decoded operand
- private (byte mod, RegisterIndex reg, RegisterIndex rm, Operand operand) ReadModRMInternal(bool is64Bit, bool is8Bit)
+ private (byte mod, RegisterIndex reg, RegisterIndex rm, Operand operand) ReadModRMInternal(bool is64Bit)
{
if (!_decoder.CanReadByte())
{
- return (0, RegisterIndex.A, RegisterIndex.A, OperandFactory.CreateRegisterOperand(RegisterIndex.A, is64Bit ? 64 : (is8Bit ? 8 : 32)));
+ return (0, RegisterIndex.A, RegisterIndex.A, OperandFactory.CreateRegisterOperand(RegisterIndex.A, is64Bit ? 64 : 32));
}
byte modRM = _decoder.ReadByte();
@@ -296,21 +288,52 @@ public class ModRMDecoder
byte regIndex = (byte)((modRM & REG_MASK) >> 3);
byte rmIndex = (byte)(modRM & RM_MASK);
- // For 8-bit registers with mod=3, we need to check if they are high registers
- bool isRmHighRegister = is8Bit && mod == 3 && rmIndex >= 4;
- bool isRegHighRegister = is8Bit && regIndex >= 4;
-
// Map the ModR/M register indices to RegisterIndex enum values
- RegisterIndex reg = isRegHighRegister ? MapModRMToHighRegister8Index(regIndex) : MapModRMToRegisterIndex(regIndex);
- RegisterIndex rm = isRmHighRegister ? MapModRMToHighRegister8Index(rmIndex) : MapModRMToRegisterIndex(rmIndex);
+ RegisterIndex reg = MapModRMToRegisterIndex(regIndex);
+ RegisterIndex rm = MapModRMToRegisterIndex(rmIndex);
// Create the operand based on the mod and rm fields
Operand operand = DecodeModRM(mod, rm, is64Bit);
-
- // For 8-bit operands, set the size to 8
- if (is8Bit)
+
+ return (mod, reg, rm, operand);
+ }
+
+ ///
+ /// Internal implementation for reading and decoding a ModR/M byte for 8-bit operands
+ ///
+ /// A tuple containing the mod, reg, rm fields and the decoded operand
+ private (byte mod, RegisterIndex8 reg, RegisterIndex8 rm, Operand operand) ReadModRM8Internal()
+ {
+ if (!_decoder.CanReadByte())
{
- operand.Size = 8;
+ return (0, RegisterIndex8.AL, RegisterIndex8.AL, OperandFactory.CreateRegisterOperand8(RegisterIndex8.AL));
+ }
+
+ byte modRM = _decoder.ReadByte();
+
+ // Extract fields from ModR/M byte
+ byte mod = (byte)((modRM & MOD_MASK) >> 6);
+ byte regIndex = (byte)((modRM & REG_MASK) >> 3);
+ byte rmIndex = (byte)(modRM & RM_MASK);
+
+ // Map the ModR/M register indices to RegisterIndex8 enum values
+ RegisterIndex8 reg = MapModRMToRegisterIndex8(regIndex);
+ RegisterIndex8 rm = MapModRMToRegisterIndex8(rmIndex);
+
+ // Create the operand based on the mod and rm fields
+ Operand operand;
+
+ if (mod == 3) // Register operand
+ {
+ // For register operands, create an 8-bit register operand
+ operand = OperandFactory.CreateRegisterOperand8(rm);
+ }
+ else // Memory operand
+ {
+ // For memory operands, we need to map the RegisterIndex8 to RegisterIndex for base registers
+ RegisterIndex rmRegIndex = MapRegister8ToBaseRegister(rm);
+ operand = DecodeModRM(mod, rmRegIndex, false);
+ operand.Size = 8; // Set size to 8 bits
}
return (mod, reg, rm, operand);
@@ -413,17 +436,48 @@ public class ModRMDecoder
/// Gets the register name based on the register index and size
///
/// The register index as RegisterIndex enum
- /// The register size (8, 16, or 32 bits)
+ /// The register size (16 or 32 bits)
/// The register name
public static string GetRegisterName(RegisterIndex regIndex, int size)
{
return size switch
{
- 8 => RegisterNames8[(int)regIndex],
16 => RegisterNames16[(int)regIndex],
32 => RegisterNames32[(int)regIndex],
64 => RegisterNames32[(int)regIndex], // For now, reuse 32-bit names for 64-bit
_ => "unknown"
};
}
+
+ ///
+ /// Gets the 8-bit register name based on the RegisterIndex8 enum value
+ ///
+ /// The register index as RegisterIndex8 enum
+ /// The 8-bit register name
+ public static string GetRegisterName(RegisterIndex8 regIndex8)
+ {
+ return regIndex8.ToString().ToLower();
+ }
+
+ ///
+ /// Maps a RegisterIndex8 enum value to the corresponding RegisterIndex enum value for base registers
+ ///
+ /// The RegisterIndex8 enum value
+ /// The corresponding RegisterIndex enum value
+ private 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
+ };
+ }
}
\ No newline at end of file
diff --git a/X86Disassembler/X86/Operands/OperandFactory.cs b/X86Disassembler/X86/Operands/OperandFactory.cs
index 788b7de..26cd0f3 100644
--- a/X86Disassembler/X86/Operands/OperandFactory.cs
+++ b/X86Disassembler/X86/Operands/OperandFactory.cs
@@ -16,6 +16,17 @@ public static class OperandFactory
return new RegisterOperand(register, size);
}
+ ///
+ /// Creates an 8-bit register operand using RegisterIndex8 enum
+ ///
+ /// The 8-bit register
+ /// A register operand for 8-bit registers
+ public static Register8Operand CreateRegisterOperand8(RegisterIndex8 register8)
+ {
+ // Create a new Register8Operand with the 8-bit register
+ return new Register8Operand(register8);
+ }
+
///
/// Creates an immediate value operand
///
diff --git a/X86Disassembler/X86/Operands/Register8Operand.cs b/X86Disassembler/X86/Operands/Register8Operand.cs
new file mode 100644
index 0000000..625c036
--- /dev/null
+++ b/X86Disassembler/X86/Operands/Register8Operand.cs
@@ -0,0 +1,31 @@
+namespace X86Disassembler.X86.Operands;
+
+///
+/// Represents an 8-bit register operand in an x86 instruction
+///
+public class Register8Operand : Operand
+{
+ ///
+ /// Gets or sets the 8-bit register
+ ///
+ public RegisterIndex8 Register { get; set; }
+
+ ///
+ /// Initializes a new instance of the Register8Operand class
+ ///
+ /// The 8-bit register
+ public Register8Operand(RegisterIndex8 register)
+ {
+ Type = OperandType.Register;
+ Register = register;
+ Size = 8; // Always 8 bits for this operand type
+ }
+
+ ///
+ /// Returns a string representation of this operand
+ ///
+ public override string ToString()
+ {
+ return ModRMDecoder.GetRegisterName(Register);
+ }
+}
diff --git a/X86Disassembler/X86/Operands/RegisterOperand.cs b/X86Disassembler/X86/Operands/RegisterOperand.cs
index e1cb221..bc335de 100644
--- a/X86Disassembler/X86/Operands/RegisterOperand.cs
+++ b/X86Disassembler/X86/Operands/RegisterOperand.cs
@@ -1,7 +1,7 @@
namespace X86Disassembler.X86.Operands;
///
-/// Represents a register operand in an x86 instruction
+/// Represents a standard register operand (16/32/64-bit) in an x86 instruction
///
public class RegisterOperand : Operand
{
@@ -14,7 +14,7 @@ public class RegisterOperand : Operand
/// Initializes a new instance of the RegisterOperand class
///
/// The register
- /// The size of the register in bits
+ /// The size of the register in bits (16, 32, or 64)
public RegisterOperand(RegisterIndex register, int size = 32)
{
Type = OperandType.Register;