0
mirror of https://github.com/sampletext32/ParkanPlayground.git synced 2025-05-19 11:51:17 +03:00
This commit is contained in:
bird_egop 2025-04-17 22:54:19 +03:00
parent 4d2db05a07
commit df453b930f
14 changed files with 340 additions and 192 deletions

View File

@ -0,0 +1,47 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Ret;
/// <summary>
/// Handler for RETF instruction with operand size prefix (0xCB with 0x66 prefix)
/// </summary>
public class Retf16Handler : InstructionHandler
{
/// <summary>
/// Initializes a new instance of the Retf16Handler class
/// </summary>
/// <param name="decoder">The instruction decoder that owns this handler</param>
public Retf16Handler(InstructionDecoder decoder)
: base(decoder)
{
}
/// <summary>
/// Checks if this handler can decode the given opcode
/// </summary>
/// <param name="opcode">The opcode to check</param>
/// <returns>True if this handler can decode the opcode</returns>
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();
}
/// <summary>
/// Decodes a RETF instruction with operand size prefix
/// </summary>
/// <param name="opcode">The opcode of the instruction</param>
/// <param name="instruction">The instruction object to populate</param>
/// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction)
{
// Set the instruction type
instruction.Type = InstructionType.Retf;
// RETF has no operands
instruction.StructuredOperands = [];
return true;
}
}

View File

@ -0,0 +1,48 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Ret;
/// <summary>
/// Handler for RETF instruction (0xCB)
/// </summary>
public class RetfHandler : InstructionHandler
{
/// <summary>
/// Initializes a new instance of the RetfHandler class
/// </summary>
/// <param name="decoder">The instruction decoder that owns this handler</param>
public RetfHandler(InstructionDecoder decoder)
: base(decoder)
{
}
/// <summary>
/// Checks if this handler can decode the given opcode
/// </summary>
/// <param name="opcode">The opcode to check</param>
/// <returns>True if this handler can decode the opcode</returns>
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();
}
/// <summary>
/// Decodes a RETF instruction
/// </summary>
/// <param name="opcode">The opcode of the instruction</param>
/// <param name="instruction">The instruction object to populate</param>
/// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction)
{
// Set the instruction type
instruction.Type = InstructionType.Retf;
// RETF has no operands
instruction.StructuredOperands = [];
return true;
}
}

View File

@ -0,0 +1,60 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Ret;
/// <summary>
/// Handler for RETF imm16 instruction with operand size prefix (0xCA with 0x66 prefix)
/// </summary>
public class RetfImm16Handler : InstructionHandler
{
/// <summary>
/// Initializes a new instance of the RetfImm16Handler class
/// </summary>
/// <param name="decoder">The instruction decoder that owns this handler</param>
public RetfImm16Handler(InstructionDecoder decoder)
: base(decoder)
{
}
/// <summary>
/// Checks if this handler can decode the given opcode
/// </summary>
/// <param name="opcode">The opcode to check</param>
/// <returns>True if this handler can decode the opcode</returns>
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();
}
/// <summary>
/// Decodes a RETF imm16 instruction with operand size prefix
/// </summary>
/// <param name="opcode">The opcode of the instruction</param>
/// <param name="instruction">The instruction object to populate</param>
/// <returns>True if the instruction was successfully decoded</returns>
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;
}
}

View File

@ -0,0 +1,61 @@
using X86Disassembler.X86.Operands;
namespace X86Disassembler.X86.Handlers.Ret;
/// <summary>
/// Handler for RETF imm16 instruction (0xCA)
/// </summary>
public class RetfImmHandler : InstructionHandler
{
/// <summary>
/// Initializes a new instance of the RetfImmHandler class
/// </summary>
/// <param name="decoder">The instruction decoder that owns this handler</param>
public RetfImmHandler(InstructionDecoder decoder)
: base(decoder)
{
}
/// <summary>
/// Checks if this handler can decode the given opcode
/// </summary>
/// <param name="opcode">The opcode to check</param>
/// <returns>True if this handler can decode the opcode</returns>
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();
}
/// <summary>
/// Decodes a RETF imm16 instruction
/// </summary>
/// <param name="opcode">The opcode of the instruction</param>
/// <param name="instruction">The instruction object to populate</param>
/// <returns>True if the instruction was successfully decoded</returns>
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;
}
}

View File

@ -3,47 +3,67 @@ namespace X86Disassembler.X86.Handlers.String;
using Operands; using Operands;
/// <summary> /// <summary>
/// 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
/// </summary> /// </summary>
public class StringInstructionHandler : InstructionHandler public class StringInstructionHandler : InstructionHandler
{ {
// Dictionary mapping opcodes to their instruction types and operand factories // Dictionary mapping opcodes to their instruction types and operand factories for 32-bit mode (default)
private static readonly Dictionary<byte, (InstructionType Type, Func<Operand[]> CreateOperands)> StringInstructions = new() private static readonly Dictionary<byte, (InstructionType Type, Func<Operand[]> CreateOperands)> StringInstructions32 = new()
{ {
// MOVS instructions
{ 0xA4, (InstructionType.MovsB, () => { 0xA4, (InstructionType.MovsB, () =>
[ [
OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 8, "es"), OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Di, "es"),
OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Si, 8, "ds") OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Si, "ds")
]) }, // MOVSB ]) }, // MOVSB
{ 0xA5, (InstructionType.MovsD, () => { 0xA5, (InstructionType.MovsD, () =>
[ [
OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 32, "es"), OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 32, "es"),
OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Si, 32, "ds") 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, () => { 0xAA, (InstructionType.StosB, () =>
[ [
OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 8, "es"), OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Di, "es"),
OperandFactory.CreateRegisterOperand(RegisterIndex.A, 8) OperandFactory.CreateRegisterOperand8(RegisterIndex8.AL)
]) }, // STOSB ]) }, // STOSB
{ 0xAB, (InstructionType.StosD, () => { 0xAB, (InstructionType.StosD, () =>
[ [
OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 32, "es"), OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 32, "es"),
OperandFactory.CreateRegisterOperand(RegisterIndex.A, 32) OperandFactory.CreateRegisterOperand(RegisterIndex.A, 32)
]) }, // STOSD ]) }, // STOSD
// LODS instructions
{ 0xAC, (InstructionType.LodsB, () => { 0xAC, (InstructionType.LodsB, () =>
[ [
OperandFactory.CreateRegisterOperand(RegisterIndex.A, 8), OperandFactory.CreateRegisterOperand8(RegisterIndex8.AL),
OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Si, 8, "ds") OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Si, "ds")
]) }, // LODSB ]) }, // LODSB
{ 0xAD, (InstructionType.LodsD, () => { 0xAD, (InstructionType.LodsD, () =>
[ [
OperandFactory.CreateRegisterOperand(RegisterIndex.A, 32), OperandFactory.CreateRegisterOperand(RegisterIndex.A, 32),
OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Si, 32, "ds") OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Si, 32, "ds")
]) }, // LODSD ]) }, // LODSD
// SCAS instructions
{ 0xAE, (InstructionType.ScasB, () => { 0xAE, (InstructionType.ScasB, () =>
[ [
OperandFactory.CreateRegisterOperand(RegisterIndex.A, 8), OperandFactory.CreateRegisterOperand8(RegisterIndex8.AL),
OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 8, "es") OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Di, "es")
]) }, // SCASB ]) }, // SCASB
{ 0xAF, (InstructionType.ScasD, () => { 0xAF, (InstructionType.ScasD, () =>
[ [
@ -52,28 +72,68 @@ public class StringInstructionHandler : InstructionHandler
]) } // SCASD ]) } // SCASD
}; };
// REP/REPNE prefix opcodes // Dictionary mapping opcodes to their instruction types and operand factories for 16-bit mode (with operand size prefix)
private const byte REP_PREFIX = 0xF3; private static readonly Dictionary<byte, (InstructionType Type, Func<Operand[]> CreateOperands)> StringInstructions16 = new()
private const byte REPNE_PREFIX = 0xF2;
// Dictionary mapping base instruction types to their REP-prefixed versions
private static readonly Dictionary<InstructionType, InstructionType> RepPrefixMap = new()
{ {
{ InstructionType.MovsB, InstructionType.RepMovsB }, // MOVS instructions
{ InstructionType.MovsD, InstructionType.RepMovsD }, { 0xA4, (InstructionType.MovsB, () =>
{ InstructionType.StosB, InstructionType.RepStosB }, [
{ InstructionType.StosD, InstructionType.RepStosD }, OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Di, "es"),
{ InstructionType.LodsB, InstructionType.RepLodsB }, OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Si, "ds")
{ InstructionType.LodsD, InstructionType.RepLodsD }, ]) }, // MOVSB (same for 16-bit)
{ InstructionType.ScasB, InstructionType.RepScasB }, { 0xA5, (InstructionType.MovsW, () =>
{ InstructionType.ScasD, InstructionType.RepScasD } [
}; OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 16, "es"),
OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Si, 16, "ds")
]) }, // MOVSW
// Dictionary mapping base instruction types to their REPNE-prefixed versions // CMPS instructions
private static readonly Dictionary<InstructionType, InstructionType> RepnePrefixMap = new() { 0xA6, (InstructionType.CmpsB, () =>
{ [
{ InstructionType.ScasB, InstructionType.RepneScasB }, OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Si, "ds"),
{ InstructionType.ScasD, InstructionType.RepneScasD } 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
}; };
/// <summary> /// <summary>
@ -92,27 +152,8 @@ public class StringInstructionHandler : InstructionHandler
/// <returns>True if this handler can handle the opcode</returns> /// <returns>True if this handler can handle the opcode</returns>
public override bool CanHandle(byte opcode) public override bool CanHandle(byte opcode)
{ {
// Check if the opcode is a string instruction // Check if the opcode is a string instruction in either 16-bit or 32-bit mode
if (StringInstructions.ContainsKey(opcode)) return StringInstructions32.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);
} }
/// <summary> /// <summary>
@ -123,59 +164,19 @@ public class StringInstructionHandler : InstructionHandler
/// <returns>True if the instruction was successfully decoded</returns> /// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction) public override bool Decode(byte opcode, Instruction instruction)
{ {
// Check if this is a REP/REPNE prefix // Select the appropriate dictionary based on operand size prefix
bool hasRepPrefix = opcode == REP_PREFIX || opcode == REPNE_PREFIX; var instructionsDict = Decoder.HasOperandSizePrefix()
? StringInstructions16
// If this is a REP/REPNE prefix, get the actual string instruction opcode : StringInstructions32;
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 // 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 // Set the instruction type
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; instruction.Type = instructionInfo.Type;
}
// Create and set the structured operands // Create and set the structured operands
instruction.StructuredOperands = instructionInfo.CreateOperands().ToList(); instruction.StructuredOperands = instructionInfo.CreateOperands().ToList();
return true; return true;
} }

View File

@ -101,9 +101,6 @@ public enum InstructionType
// Lods = LodsD, // Alias for LodsD - removed alias to avoid switch expression issues // Lods = LodsD, // Alias for LodsD - removed alias to avoid switch expression issues
// REP prefixed instructions // 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 // RepneScas = RepNE, // Alias for RepNE - removed alias to avoid switch expression issues
RepMovsB, // REP MOVSB RepMovsB, // REP MOVSB
RepMovsW, // REP MOVSW RepMovsW, // REP MOVSW

View File

@ -271,8 +271,8 @@ public class ModRMDecoder
byte rmIndex = (byte)(modRM & Constants.RM_MASK); byte rmIndex = (byte)(modRM & Constants.RM_MASK);
// Map the ModR/M register indices to RegisterIndex enum values // Map the ModR/M register indices to RegisterIndex enum values
RegisterIndex reg = RegisterMapper.MapModRMToRegisterIndex(regIndex); RegisterIndex reg = (RegisterIndex)regIndex;
RegisterIndex rm = RegisterMapper.MapModRMToRegisterIndex(rmIndex); RegisterIndex rm = (RegisterIndex)rmIndex;
// Create the operand based on the mod and rm fields // Create the operand based on the mod and rm fields
Operand operand = DecodeModRM(mod, rm, is64Bit); Operand operand = DecodeModRM(mod, rm, is64Bit);
@ -299,8 +299,8 @@ public class ModRMDecoder
byte rmIndex = (byte)(modRM & Constants.RM_MASK); byte rmIndex = (byte)(modRM & Constants.RM_MASK);
// Map the ModR/M register indices to RegisterIndex8 enum values // Map the ModR/M register indices to RegisterIndex8 enum values
RegisterIndex8 reg = RegisterMapper.MapModRMToRegisterIndex8(regIndex); RegisterIndex8 reg = (RegisterIndex8)regIndex;
RegisterIndex8 rm = RegisterMapper.MapModRMToRegisterIndex8(rmIndex); RegisterIndex8 rm = (RegisterIndex8)rmIndex;
// Create the operand based on the mod and rm fields // Create the operand based on the mod and rm fields
Operand operand; Operand operand;
@ -315,7 +315,7 @@ public class ModRMDecoder
// For memory operands, we need to map the RegisterIndex8 to RegisterIndex for base registers // 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 // 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 // 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 // Use the DecodeModRM8 method to get an 8-bit memory operand
operand = DecodeModRM8(mod, rmRegIndex); operand = DecodeModRM8(mod, rmRegIndex);

View File

@ -1,76 +1,10 @@
namespace X86Disassembler.X86; namespace X86Disassembler.X86;
using Operands;
/// <summary> /// <summary>
/// Handles mapping between register indices and register enums /// Handles mapping between register indices and register enums
/// </summary> /// </summary>
public static class RegisterMapper public static class RegisterMapper
{ {
/// <summary>
/// Maps the register index from the ModR/M byte to the RegisterIndex enum value
/// </summary>
/// <param name="modRMRegIndex">The register index from the ModR/M byte (0-7)</param>
/// <returns>The corresponding RegisterIndex enum value</returns>
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
};
}
/// <summary>
/// Maps the register index from the ModR/M byte to the RegisterIndex8 enum value
/// </summary>
/// <param name="modRMRegIndex">The register index from the ModR/M byte (0-7)</param>
/// <returns>The corresponding RegisterIndex8 enum value</returns>
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;
}
/// <summary>
/// Maps a RegisterIndex8 enum value to the corresponding RegisterIndex enum value for base registers
/// </summary>
/// <param name="regIndex8">The RegisterIndex8 enum value</param>
/// <returns>The corresponding RegisterIndex enum value</returns>
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
};
}
/// <summary> /// <summary>
/// Gets the register name based on the register index and size /// Gets the register name based on the register index and size
/// </summary> /// </summary>

View File

@ -34,8 +34,8 @@ public class SIBDecoder
int baseIndex = sib & Constants.SIB_BASE_MASK; int baseIndex = sib & Constants.SIB_BASE_MASK;
// Map the SIB register indices to RegisterIndex enum values // Map the SIB register indices to RegisterIndex enum values
RegisterIndex index = RegisterMapper.MapModRMToRegisterIndex(indexIndex); RegisterIndex index = (RegisterIndex)indexIndex;
RegisterIndex @base = RegisterMapper.MapModRMToRegisterIndex(baseIndex); RegisterIndex @base = (RegisterIndex)baseIndex;
// Special case: ESP/SP (4) in index field means no index register // Special case: ESP/SP (4) in index field means no index register
if (index == RegisterIndex.Sp) if (index == RegisterIndex.Sp)

View File

@ -24,7 +24,7 @@ public class Int3InstructionTests
// Assert // Assert
Assert.NotNull(instruction); Assert.NotNull(instruction);
Assert.Equal(InstructionType.Int, instruction.Type); Assert.Equal(InstructionType.Int3, instruction.Type);
// Check that we have no operands // Check that we have no operands
Assert.Empty(instruction.StructuredOperands); Assert.Empty(instruction.StructuredOperands);

View File

@ -154,9 +154,9 @@ public class StringInstructionHandlerTests
// Check the second operand (AL) // Check the second operand (AL)
var alOperand = instruction.StructuredOperands[1]; var alOperand = instruction.StructuredOperands[1];
Assert.IsType<RegisterOperand>(alOperand); Assert.IsType<Register8Operand>(alOperand);
var registerOperand = (RegisterOperand)alOperand; var registerOperand = (Register8Operand)alOperand;
Assert.Equal(RegisterIndex.A, registerOperand.Register); Assert.Equal(RegisterIndex8.AL, registerOperand.Register);
Assert.Equal(8, registerOperand.Size); // Validate that it's an 8-bit register (AL) 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) // Check the first operand (AL)
var alOperand = instruction.StructuredOperands[0]; var alOperand = instruction.StructuredOperands[0];
Assert.IsType<RegisterOperand>(alOperand); Assert.IsType<Register8Operand>(alOperand);
var registerOperand = (RegisterOperand)alOperand; var registerOperand = (Register8Operand)alOperand;
Assert.Equal(RegisterIndex.A, registerOperand.Register); Assert.Equal(RegisterIndex8.AL, registerOperand.Register);
Assert.Equal(8, registerOperand.Size); // Validate that it's an 8-bit register (AL) Assert.Equal(8, registerOperand.Size); // Validate that it's an 8-bit register (AL)
// Check the second operand (memory operand) // Check the second operand (memory operand)

View File

@ -16,8 +16,8 @@ C2FFFF;[{ "Type": "Ret", "Operands": ["0xFFFF"] }]
CB;[{ "Type": "Retf", "Operands": [] }] CB;[{ "Type": "Retf", "Operands": [] }]
# RETF imm16 (opcode CA) - Far return to calling procedure and pop imm16 bytes from stack # RETF imm16 (opcode CA) - Far return to calling procedure and pop imm16 bytes from stack
CA0000;[{ "Type": "Retf", "Operands": ["0x0000"] }] CA0000;[{ "Type": "Retf", "Operands": ["0x00"] }]
CA0400;[{ "Type": "Retf", "Operands": ["0x0004"] }] CA0400;[{ "Type": "Retf", "Operands": ["0x04"] }]
CA0800;[{ "Type": "Retf", "Operands": ["0x0008"] }] CA0800;[{ "Type": "Retf", "Operands": ["0x08"] }]
CA1000;[{ "Type": "Retf", "Operands": ["0x0010"] }] CA1000;[{ "Type": "Retf", "Operands": ["0x10"] }]
CAFFFF;[{ "Type": "Retf", "Operands": ["0xFFFF"] }] CAFFFF;[{ "Type": "Retf", "Operands": ["0xFFFF"] }]

Can't render this file because it contains an unexpected character in line 6 and column 7.

View File

@ -12,7 +12,7 @@ RawBytes;Instructions
83D842;[{ "Type": "Sbb", "Operands": ["eax", "0x42"] }] 83D842;[{ "Type": "Sbb", "Operands": ["eax", "0x42"] }]
# SBB with memory operands # 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) # SBB r/m32, r32 (opcode 19)
19D8;[{ "Type": "Sbb", "Operands": ["eax", "ebx"] }] 19D8;[{ "Type": "Sbb", "Operands": ["eax", "ebx"] }]

Can't render this file because it contains an unexpected character in line 6 and column 11.

View File

@ -18,9 +18,9 @@ AF;[{ "Type": "ScasD", "Operands": ["eax", "dword ptr es:[edi]"] }]
66AF;[{ "Type": "ScasW", "Operands": ["ax", "word ptr es:[edi]"] }] 66AF;[{ "Type": "ScasW", "Operands": ["ax", "word ptr es:[edi]"] }]
# LODS - Load string # LODS - Load string
AC;[{ "Type": "LodsB", "Operands": ["al", "byte ptr es:[esi]"] }] AC;[{ "Type": "LodsB", "Operands": ["al", "byte ptr ds:[esi]"] }]
AD;[{ "Type": "LodsD", "Operands": ["eax", "dword ptr es:[esi]"] }] AD;[{ "Type": "LodsD", "Operands": ["eax", "dword ptr ds:[esi]"] }]
66AD;[{ "Type": "LodsW", "Operands": ["ax", "byte ptr es:[esi]"] }] 66AD;[{ "Type": "LodsW", "Operands": ["ax", "byte ptr ds:[esi]"] }]
# STOS - Store string # STOS - Store string
AA;[{ "Type": "StosB", "Operands": ["byte ptr es:[edi]", "al"] }] AA;[{ "Type": "StosB", "Operands": ["byte ptr es:[edi]", "al"] }]

Can't render this file because it contains an unexpected character in line 6 and column 7.