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;