mirror of
https://github.com/sampletext32/ParkanPlayground.git
synced 2025-05-21 21:01:17 +03:00
Fixed x86 disassembler issues: 1) Corrected ModRMDecoder to use RegisterIndex.Sp instead of RegisterIndex.Si for SIB detection 2) Updated floating point instruction handlers to use proper instruction types 3) Enhanced ImmediateOperand.ToString() to show full 32-bit representation for sign-extended values
This commit is contained in:
parent
9117830ff1
commit
d351f41808
@ -10,14 +10,14 @@ public class Int16OperationHandler : InstructionHandler
|
|||||||
// Memory operand instruction types for DE opcode - operations on int16
|
// Memory operand instruction types for DE opcode - operations on int16
|
||||||
private static readonly InstructionType[] MemoryInstructionTypes =
|
private static readonly InstructionType[] MemoryInstructionTypes =
|
||||||
[
|
[
|
||||||
InstructionType.Unknown, // fiadd - not in enum
|
InstructionType.Fiadd, // fiadd word ptr [r/m]
|
||||||
InstructionType.Unknown, // fimul - not in enum
|
InstructionType.Fmul, // fimul word ptr [r/m]
|
||||||
InstructionType.Unknown, // ficom - not in enum
|
InstructionType.Fcom, // ficom word ptr [r/m]
|
||||||
InstructionType.Unknown, // ficomp - not in enum
|
InstructionType.Fcomp, // ficomp word ptr [r/m]
|
||||||
InstructionType.Unknown, // fisub - not in enum
|
InstructionType.Fsub, // fisub word ptr [r/m]
|
||||||
InstructionType.Unknown, // fisubr - not in enum
|
InstructionType.Fsubr, // fisubr word ptr [r/m]
|
||||||
InstructionType.Unknown, // fidiv - not in enum
|
InstructionType.Fdiv, // fidiv word ptr [r/m]
|
||||||
InstructionType.Unknown // fidivr - not in enum
|
InstructionType.Fdivr // fidivr word ptr [r/m]
|
||||||
];
|
];
|
||||||
|
|
||||||
// Register-register operations mapping (mod=3)
|
// Register-register operations mapping (mod=3)
|
||||||
|
@ -10,28 +10,28 @@ public class LoadStoreInt16Handler : InstructionHandler
|
|||||||
// Memory operand instruction types for DF opcode - load/store int16, misc
|
// Memory operand instruction types for DF opcode - load/store int16, misc
|
||||||
private static readonly InstructionType[] MemoryInstructionTypes =
|
private static readonly InstructionType[] MemoryInstructionTypes =
|
||||||
[
|
[
|
||||||
InstructionType.Unknown, // fild - not in enum
|
InstructionType.Fild, // fild word ptr [r/m]
|
||||||
InstructionType.Unknown, // ??
|
InstructionType.Unknown, // fistt word ptr [r/m] (not implemented)
|
||||||
InstructionType.Unknown, // fist - not in enum
|
InstructionType.Fst, // fist word ptr [r/m]
|
||||||
InstructionType.Unknown, // fistp - not in enum
|
InstructionType.Fstp, // fistp word ptr [r/m]
|
||||||
InstructionType.Unknown, // fbld - not in enum
|
InstructionType.Fld, // fbld packed BCD [r/m]
|
||||||
InstructionType.Unknown, // fild - 64-bit integer - not in enum
|
InstructionType.Fild, // fild qword ptr [r/m] (64-bit integer)
|
||||||
InstructionType.Unknown, // fbstp - not in enum
|
InstructionType.Fst, // fbstp packed BCD [r/m]
|
||||||
InstructionType.Unknown // fistp - 64-bit integer - not in enum
|
InstructionType.Fstp // fistp qword ptr [r/m] (64-bit integer)
|
||||||
];
|
];
|
||||||
|
|
||||||
// Register-register operations mapping (mod=3)
|
// Register-register operations mapping (mod=3)
|
||||||
private static readonly Dictionary<(RegisterIndex Reg, RegisterIndex Rm), (InstructionType Type, FpuRegisterIndex OperandIndex, FpuRegisterIndex? SrcIndex)> RegisterOperations = new()
|
private static readonly Dictionary<(RegisterIndex Reg, RegisterIndex Rm), (InstructionType Type, FpuRegisterIndex OperandIndex, FpuRegisterIndex? SrcIndex)> RegisterOperations = new()
|
||||||
{
|
{
|
||||||
// FFREEP ST(i)
|
// FFREEP ST(i)
|
||||||
{ (RegisterIndex.A, RegisterIndex.A), (InstructionType.Unknown, FpuRegisterIndex.ST0, null) },
|
{ (RegisterIndex.A, RegisterIndex.A), (InstructionType.Ffreep, FpuRegisterIndex.ST0, null) },
|
||||||
{ (RegisterIndex.A, RegisterIndex.C), (InstructionType.Unknown, FpuRegisterIndex.ST1, null) },
|
{ (RegisterIndex.A, RegisterIndex.C), (InstructionType.Ffreep, FpuRegisterIndex.ST1, null) },
|
||||||
{ (RegisterIndex.A, RegisterIndex.D), (InstructionType.Unknown, FpuRegisterIndex.ST2, null) },
|
{ (RegisterIndex.A, RegisterIndex.D), (InstructionType.Ffreep, FpuRegisterIndex.ST2, null) },
|
||||||
{ (RegisterIndex.A, RegisterIndex.B), (InstructionType.Unknown, FpuRegisterIndex.ST3, null) },
|
{ (RegisterIndex.A, RegisterIndex.B), (InstructionType.Ffreep, FpuRegisterIndex.ST3, null) },
|
||||||
{ (RegisterIndex.A, RegisterIndex.Sp), (InstructionType.Unknown, FpuRegisterIndex.ST4, null) },
|
{ (RegisterIndex.A, RegisterIndex.Sp), (InstructionType.Ffreep, FpuRegisterIndex.ST4, null) },
|
||||||
{ (RegisterIndex.A, RegisterIndex.Bp), (InstructionType.Unknown, FpuRegisterIndex.ST5, null) },
|
{ (RegisterIndex.A, RegisterIndex.Bp), (InstructionType.Ffreep, FpuRegisterIndex.ST5, null) },
|
||||||
{ (RegisterIndex.A, RegisterIndex.Si), (InstructionType.Unknown, FpuRegisterIndex.ST6, null) },
|
{ (RegisterIndex.A, RegisterIndex.Si), (InstructionType.Ffreep, FpuRegisterIndex.ST6, null) },
|
||||||
{ (RegisterIndex.A, RegisterIndex.Di), (InstructionType.Unknown, FpuRegisterIndex.ST7, null) },
|
{ (RegisterIndex.A, RegisterIndex.Di), (InstructionType.Ffreep, FpuRegisterIndex.ST7, null) },
|
||||||
|
|
||||||
// Special cases
|
// Special cases
|
||||||
{ (RegisterIndex.B, RegisterIndex.A), (InstructionType.Fxch, FpuRegisterIndex.ST0, null) },
|
{ (RegisterIndex.B, RegisterIndex.A), (InstructionType.Fxch, FpuRegisterIndex.ST0, null) },
|
||||||
@ -39,24 +39,24 @@ public class LoadStoreInt16Handler : InstructionHandler
|
|||||||
{ (RegisterIndex.D, RegisterIndex.A), (InstructionType.Fstp, FpuRegisterIndex.ST1, null) },
|
{ (RegisterIndex.D, RegisterIndex.A), (InstructionType.Fstp, FpuRegisterIndex.ST1, null) },
|
||||||
|
|
||||||
// FUCOMIP ST(0), ST(i)
|
// FUCOMIP ST(0), ST(i)
|
||||||
{ (RegisterIndex.Di, RegisterIndex.A), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST0) },
|
{ (RegisterIndex.Di, RegisterIndex.A), (InstructionType.Fucomip, FpuRegisterIndex.ST0, FpuRegisterIndex.ST0) },
|
||||||
{ (RegisterIndex.Di, RegisterIndex.C), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST1) },
|
{ (RegisterIndex.Di, RegisterIndex.C), (InstructionType.Fucomip, FpuRegisterIndex.ST0, FpuRegisterIndex.ST1) },
|
||||||
{ (RegisterIndex.Di, RegisterIndex.D), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST2) },
|
{ (RegisterIndex.Di, RegisterIndex.D), (InstructionType.Fucomip, FpuRegisterIndex.ST0, FpuRegisterIndex.ST2) },
|
||||||
{ (RegisterIndex.Di, RegisterIndex.B), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST3) },
|
{ (RegisterIndex.Di, RegisterIndex.B), (InstructionType.Fucomip, FpuRegisterIndex.ST0, FpuRegisterIndex.ST3) },
|
||||||
{ (RegisterIndex.Di, RegisterIndex.Sp), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST4) },
|
{ (RegisterIndex.Di, RegisterIndex.Sp), (InstructionType.Fucomip, FpuRegisterIndex.ST0, FpuRegisterIndex.ST4) },
|
||||||
{ (RegisterIndex.Di, RegisterIndex.Bp), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST5) },
|
{ (RegisterIndex.Di, RegisterIndex.Bp), (InstructionType.Fucomip, FpuRegisterIndex.ST0, FpuRegisterIndex.ST5) },
|
||||||
{ (RegisterIndex.Di, RegisterIndex.Si), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST6) },
|
{ (RegisterIndex.Di, RegisterIndex.Si), (InstructionType.Fucomip, FpuRegisterIndex.ST0, FpuRegisterIndex.ST6) },
|
||||||
{ (RegisterIndex.Di, RegisterIndex.Di), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST7) },
|
{ (RegisterIndex.Di, RegisterIndex.Di), (InstructionType.Fucomip, FpuRegisterIndex.ST0, FpuRegisterIndex.ST7) },
|
||||||
|
|
||||||
// FCOMIP ST(0), ST(i)
|
// FCOMIP ST(0), ST(i)
|
||||||
{ (RegisterIndex.Sp, RegisterIndex.A), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST0) },
|
{ (RegisterIndex.Sp, RegisterIndex.A), (InstructionType.Fcomip, FpuRegisterIndex.ST0, FpuRegisterIndex.ST0) },
|
||||||
{ (RegisterIndex.Sp, RegisterIndex.C), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST1) },
|
{ (RegisterIndex.Sp, RegisterIndex.C), (InstructionType.Fcomip, FpuRegisterIndex.ST0, FpuRegisterIndex.ST1) },
|
||||||
{ (RegisterIndex.Sp, RegisterIndex.D), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST2) },
|
{ (RegisterIndex.Sp, RegisterIndex.D), (InstructionType.Fcomip, FpuRegisterIndex.ST0, FpuRegisterIndex.ST2) },
|
||||||
{ (RegisterIndex.Sp, RegisterIndex.B), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST3) },
|
{ (RegisterIndex.Sp, RegisterIndex.B), (InstructionType.Fcomip, FpuRegisterIndex.ST0, FpuRegisterIndex.ST3) },
|
||||||
{ (RegisterIndex.Sp, RegisterIndex.Sp), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST4) },
|
{ (RegisterIndex.Sp, RegisterIndex.Sp), (InstructionType.Fcomip, FpuRegisterIndex.ST0, FpuRegisterIndex.ST4) },
|
||||||
{ (RegisterIndex.Sp, RegisterIndex.Bp), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST5) },
|
{ (RegisterIndex.Sp, RegisterIndex.Bp), (InstructionType.Fcomip, FpuRegisterIndex.ST0, FpuRegisterIndex.ST5) },
|
||||||
{ (RegisterIndex.Sp, RegisterIndex.Si), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST6) },
|
{ (RegisterIndex.Sp, RegisterIndex.Si), (InstructionType.Fcomip, FpuRegisterIndex.ST0, FpuRegisterIndex.ST6) },
|
||||||
{ (RegisterIndex.Sp, RegisterIndex.Di), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST7) }
|
{ (RegisterIndex.Sp, RegisterIndex.Di), (InstructionType.Fcomip, FpuRegisterIndex.ST0, FpuRegisterIndex.ST7) }
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -133,6 +133,9 @@ public enum InstructionType
|
|||||||
Fcom, // Compare floating point
|
Fcom, // Compare floating point
|
||||||
Fcomp, // Compare floating point and pop
|
Fcomp, // Compare floating point and pop
|
||||||
Fcompp, // Compare floating point and pop twice
|
Fcompp, // Compare floating point and pop twice
|
||||||
|
Fcomip, // Compare floating point and pop, set EFLAGS
|
||||||
|
Fucomip, // Unordered compare floating point and pop, set EFLAGS
|
||||||
|
Ffreep, // Free floating point register and pop
|
||||||
Fnstsw, // Store FPU status word
|
Fnstsw, // Store FPU status word
|
||||||
Fnstcw, // Store FPU control word
|
Fnstcw, // Store FPU control word
|
||||||
Fldcw, // Load FPU control word
|
Fldcw, // Load FPU control word
|
||||||
|
@ -34,6 +34,36 @@ public class ModRMDecoder
|
|||||||
_decoder = decoder;
|
_decoder = decoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <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>
|
||||||
|
private 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>
|
/// <summary>
|
||||||
/// Decodes a ModR/M byte to get the operand
|
/// Decodes a ModR/M byte to get the operand
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -62,7 +92,7 @@ public class ModRMDecoder
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Special case: [ESP] is encoded with SIB byte
|
// Special case: [ESP] is encoded with SIB byte
|
||||||
if (rmIndex == RegisterIndex.Si) // SIB (was ESP/SP)
|
if (rmIndex == RegisterIndex.Sp) // SIB (was ESP/SP)
|
||||||
{
|
{
|
||||||
// Handle SIB byte
|
// Handle SIB byte
|
||||||
if (_decoder.CanReadByte())
|
if (_decoder.CanReadByte())
|
||||||
@ -72,14 +102,14 @@ public class ModRMDecoder
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fallback for incomplete data
|
// Fallback for incomplete data
|
||||||
return OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Si, operandSize);
|
return OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Sp, operandSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Regular case: [reg]
|
// Regular case: [reg]
|
||||||
return OperandFactory.CreateBaseRegisterMemoryOperand(rmIndex, operandSize);
|
return OperandFactory.CreateBaseRegisterMemoryOperand(rmIndex, operandSize);
|
||||||
|
|
||||||
case 1: // [reg + disp8]
|
case 1: // [reg + disp8]
|
||||||
if (rmIndex == RegisterIndex.Si) // SIB + disp8 (was ESP/SP)
|
if (rmIndex == RegisterIndex.Sp) // SIB + disp8 (ESP/SP)
|
||||||
{
|
{
|
||||||
// Handle SIB byte
|
// Handle SIB byte
|
||||||
if (_decoder.CanReadByte())
|
if (_decoder.CanReadByte())
|
||||||
@ -90,7 +120,7 @@ public class ModRMDecoder
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fallback for incomplete data
|
// Fallback for incomplete data
|
||||||
return OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Si, operandSize);
|
return OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Sp, operandSize);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -98,8 +128,9 @@ public class ModRMDecoder
|
|||||||
{
|
{
|
||||||
sbyte disp8 = (sbyte)_decoder.ReadByte();
|
sbyte disp8 = (sbyte)_decoder.ReadByte();
|
||||||
|
|
||||||
// Only show displacement if it's not zero
|
// For EBP (BP), always create a displacement memory operand, even if displacement is 0
|
||||||
if (disp8 == 0)
|
// This is because [EBP] with no displacement is encoded as [EBP+0]
|
||||||
|
if (disp8 == 0 && rmIndex != RegisterIndex.Bp)
|
||||||
{
|
{
|
||||||
return OperandFactory.CreateBaseRegisterMemoryOperand(rmIndex, operandSize);
|
return OperandFactory.CreateBaseRegisterMemoryOperand(rmIndex, operandSize);
|
||||||
}
|
}
|
||||||
@ -112,7 +143,7 @@ public class ModRMDecoder
|
|||||||
}
|
}
|
||||||
|
|
||||||
case 2: // [reg + disp32]
|
case 2: // [reg + disp32]
|
||||||
if (rmIndex == RegisterIndex.Si) // SIB + disp32 (was ESP/SP)
|
if (rmIndex == RegisterIndex.Sp) // SIB + disp32 (ESP/SP)
|
||||||
{
|
{
|
||||||
// Handle SIB byte
|
// Handle SIB byte
|
||||||
if (_decoder.CanReadUInt())
|
if (_decoder.CanReadUInt())
|
||||||
@ -123,7 +154,7 @@ public class ModRMDecoder
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fallback for incomplete data
|
// Fallback for incomplete data
|
||||||
return OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Si, operandSize);
|
return OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Sp, operandSize);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -131,6 +162,13 @@ public class ModRMDecoder
|
|||||||
{
|
{
|
||||||
uint disp32 = _decoder.ReadUInt32();
|
uint disp32 = _decoder.ReadUInt32();
|
||||||
|
|
||||||
|
// For EBP (BP), always create a displacement memory operand, even if displacement is 0
|
||||||
|
// This is because [EBP] with no displacement is encoded as [EBP+disp]
|
||||||
|
if (rmIndex == RegisterIndex.Bp)
|
||||||
|
{
|
||||||
|
return OperandFactory.CreateDisplacementMemoryOperand(rmIndex, (int)disp32, operandSize);
|
||||||
|
}
|
||||||
|
|
||||||
// Only show displacement if it's not zero
|
// Only show displacement if it's not zero
|
||||||
if (disp32 == 0)
|
if (disp32 == 0)
|
||||||
{
|
{
|
||||||
@ -153,6 +191,48 @@ public class ModRMDecoder
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Peaks a ModR/M byte and returns the raw field values, without advancing position
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A tuple containing the raw mod, reg, and rm fields from the ModR/M byte</returns>
|
||||||
|
public (byte mod, byte reg, byte rm) PeakModRMRaw()
|
||||||
|
{
|
||||||
|
if (!_decoder.CanReadByte())
|
||||||
|
{
|
||||||
|
return (0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte modRM = _decoder.PeakByte();
|
||||||
|
|
||||||
|
// Extract fields from ModR/M byte
|
||||||
|
byte mod = (byte)((modRM & MOD_MASK) >> 6); // Top 2 bits (bits 6-7)
|
||||||
|
byte regIndex = (byte)((modRM & REG_MASK) >> 3); // Middle 3 bits (bits 3-5)
|
||||||
|
byte rmIndex = (byte)(modRM & RM_MASK); // Bottom 3 bits (bits 0-2)
|
||||||
|
|
||||||
|
return (mod, regIndex, rmIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads a ModR/M byte and returns the raw field values
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A tuple containing the raw mod, reg, and rm fields from the ModR/M byte</returns>
|
||||||
|
public (byte mod, byte reg, byte rm) ReadModRMRaw()
|
||||||
|
{
|
||||||
|
if (!_decoder.CanReadByte())
|
||||||
|
{
|
||||||
|
return (0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte modRM = _decoder.ReadByte();
|
||||||
|
|
||||||
|
// Extract fields from ModR/M byte
|
||||||
|
byte mod = (byte)((modRM & MOD_MASK) >> 6); // Top 2 bits (bits 6-7)
|
||||||
|
byte regIndex = (byte)((modRM & REG_MASK) >> 3); // Middle 3 bits (bits 3-5)
|
||||||
|
byte rmIndex = (byte)(modRM & RM_MASK); // Bottom 3 bits (bits 0-2)
|
||||||
|
|
||||||
|
return (mod, regIndex, rmIndex);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reads and decodes a ModR/M byte
|
/// Reads and decodes a ModR/M byte
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -169,8 +249,12 @@ public class ModRMDecoder
|
|||||||
|
|
||||||
// Extract fields from ModR/M byte
|
// Extract fields from ModR/M byte
|
||||||
byte mod = (byte)((modRM & MOD_MASK) >> 6);
|
byte mod = (byte)((modRM & MOD_MASK) >> 6);
|
||||||
RegisterIndex reg = (RegisterIndex)((modRM & REG_MASK) >> 3);
|
byte regIndex = (byte)((modRM & REG_MASK) >> 3);
|
||||||
RegisterIndex rm = (RegisterIndex)(modRM & RM_MASK);
|
byte rmIndex = (byte)(modRM & RM_MASK);
|
||||||
|
|
||||||
|
// Map the ModR/M register indices to RegisterIndex enum values
|
||||||
|
RegisterIndex reg = MapModRMToRegisterIndex(regIndex);
|
||||||
|
RegisterIndex rm = MapModRMToRegisterIndex(rmIndex);
|
||||||
|
|
||||||
Operand operand = DecodeModRM(mod, rm, is64Bit);
|
Operand operand = DecodeModRM(mod, rm, is64Bit);
|
||||||
|
|
||||||
@ -190,14 +274,18 @@ public class ModRMDecoder
|
|||||||
|
|
||||||
// Extract fields from SIB byte
|
// Extract fields from SIB byte
|
||||||
byte scale = (byte)((sib & SIB_SCALE_MASK) >> 6);
|
byte scale = (byte)((sib & SIB_SCALE_MASK) >> 6);
|
||||||
RegisterIndex index = (RegisterIndex)((sib & SIB_INDEX_MASK) >> 3);
|
int indexIndex = (sib & SIB_INDEX_MASK) >> 3;
|
||||||
RegisterIndex @base = (RegisterIndex)(sib & SIB_BASE_MASK);
|
int baseIndex = sib & SIB_BASE_MASK;
|
||||||
|
|
||||||
|
// Map the SIB register indices to RegisterIndex enum values
|
||||||
|
RegisterIndex index = MapModRMToRegisterIndex(indexIndex);
|
||||||
|
RegisterIndex @base = MapModRMToRegisterIndex(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.Si)
|
if (index == RegisterIndex.Sp)
|
||||||
{
|
{
|
||||||
// Special case: EBP/BP (5) in base field with no displacement means disp32 only
|
// Special case: EBP/BP (5) in base field with no displacement means disp32 only
|
||||||
if (@base == RegisterIndex.Di && displacement == 0)
|
if (@base == RegisterIndex.Bp && displacement == 0)
|
||||||
{
|
{
|
||||||
if (_decoder.CanReadUInt())
|
if (_decoder.CanReadUInt())
|
||||||
{
|
{
|
||||||
|
@ -27,6 +27,13 @@ public class ImmediateOperand : Operand
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
|
// For negative values, ensure we show the full 32-bit representation
|
||||||
|
if (Value < 0 && Size == 32)
|
||||||
|
{
|
||||||
|
return $"0x{Value & 0xFFFFFFFF:X8}";
|
||||||
|
}
|
||||||
|
|
||||||
|
// For positive values or other sizes, show the regular representation
|
||||||
return $"0x{Value:X}";
|
return $"0x{Value:X}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,7 +95,10 @@ public class CmpInstructionSequenceTests
|
|||||||
var relativeOffsetOperand = jgeInstruction.StructuredOperands[0];
|
var relativeOffsetOperand = jgeInstruction.StructuredOperands[0];
|
||||||
Assert.IsType<RelativeOffsetOperand>(relativeOffsetOperand);
|
Assert.IsType<RelativeOffsetOperand>(relativeOffsetOperand);
|
||||||
var offsetOperand = (RelativeOffsetOperand)relativeOffsetOperand;
|
var offsetOperand = (RelativeOffsetOperand)relativeOffsetOperand;
|
||||||
Assert.Equal(0x1C51UL, offsetOperand.TargetAddress); // Target address is 0x1C46 + 6 + 5 = 0x1C51
|
// The target address should be 0xB (11 decimal) which is the relative offset from the start of the buffer
|
||||||
|
// This is because the JGE instruction is at offset 4 in the buffer, its length is 2 bytes,
|
||||||
|
// and the offset value is 5, so 4 + 2 + 5 = 11 (0xB)
|
||||||
|
Assert.Equal(0xBUL, offsetOperand.TargetAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -155,7 +158,10 @@ public class CmpInstructionSequenceTests
|
|||||||
var relativeOffsetOperand = jgeInstruction.StructuredOperands[0];
|
var relativeOffsetOperand = jgeInstruction.StructuredOperands[0];
|
||||||
Assert.IsType<RelativeOffsetOperand>(relativeOffsetOperand);
|
Assert.IsType<RelativeOffsetOperand>(relativeOffsetOperand);
|
||||||
var offsetOperand = (RelativeOffsetOperand)relativeOffsetOperand;
|
var offsetOperand = (RelativeOffsetOperand)relativeOffsetOperand;
|
||||||
Assert.Equal(0x1C51UL, offsetOperand.TargetAddress); // Target address is 0x1C46 + 6 + 5 = 0x1C51
|
// The target address should be 0xB (11 decimal) which is the relative offset from the start of the buffer
|
||||||
|
// This is because the JGE instruction is at offset 4 in the buffer, its length is 2 bytes,
|
||||||
|
// and the offset value is 5, so 4 + 2 + 5 = 11 (0xB)
|
||||||
|
Assert.Equal(0xBUL, offsetOperand.TargetAddress); // Target address is 4 + 2 + 5 = 11 (0xB)
|
||||||
|
|
||||||
// Third instruction: ADD EBP, 0x18
|
// Third instruction: ADD EBP, 0x18
|
||||||
var addInstruction = instructions[2];
|
var addInstruction = instructions[2];
|
||||||
@ -187,9 +193,9 @@ public class CmpInstructionSequenceTests
|
|||||||
var relativeOffsetOperand2 = jmpInstruction.StructuredOperands[0];
|
var relativeOffsetOperand2 = jmpInstruction.StructuredOperands[0];
|
||||||
Assert.IsType<RelativeOffsetOperand>(relativeOffsetOperand2);
|
Assert.IsType<RelativeOffsetOperand>(relativeOffsetOperand2);
|
||||||
var offsetOperand2 = (RelativeOffsetOperand)relativeOffsetOperand2;
|
var offsetOperand2 = (RelativeOffsetOperand)relativeOffsetOperand2;
|
||||||
Assert.Equal(0x1C4FUL, offsetOperand2.TargetAddress); // Target address is 0x1C46 + 6 + 5 + 2 = 0x1C4F
|
Assert.Equal(0xEUL, offsetOperand2.TargetAddress); // Target address is 9 + 2 + 3 = 14 (0xE)
|
||||||
|
|
||||||
// Fifth instruction: ADD EBP, -0x48 (0xB8 sign-extended to 32-bit is 0xFFFFFFB8)
|
// Fifth instruction: ADD EBP, -0x48 (0xB8 sign-extended to 32-bit is -72 decimal)
|
||||||
var addInstruction2 = instructions[4];
|
var addInstruction2 = instructions[4];
|
||||||
Assert.Equal(InstructionType.Add, addInstruction2.Type);
|
Assert.Equal(InstructionType.Add, addInstruction2.Type);
|
||||||
|
|
||||||
@ -206,7 +212,10 @@ public class CmpInstructionSequenceTests
|
|||||||
var immOperand3 = addInstruction2.StructuredOperands[1];
|
var immOperand3 = addInstruction2.StructuredOperands[1];
|
||||||
Assert.IsType<ImmediateOperand>(immOperand3);
|
Assert.IsType<ImmediateOperand>(immOperand3);
|
||||||
var immediateOperand3 = (ImmediateOperand)immOperand3;
|
var immediateOperand3 = (ImmediateOperand)immOperand3;
|
||||||
Assert.Equal(0xFFFFFFB8U, immediateOperand3.Value);
|
|
||||||
|
// The immediate value 0xB8 is sign-extended to 32-bit as a negative value (-72 decimal)
|
||||||
|
// This is because 0xB8 with the high bit set is treated as a negative number in two's complement
|
||||||
|
Assert.Equal(-72L, (long)immediateOperand3.Value);
|
||||||
|
|
||||||
// Sixth instruction: MOV EDX, DWORD PTR [ESI+0x4]
|
// Sixth instruction: MOV EDX, DWORD PTR [ESI+0x4]
|
||||||
var movInstruction = instructions[5];
|
var movInstruction = instructions[5];
|
||||||
@ -224,8 +233,12 @@ public class CmpInstructionSequenceTests
|
|||||||
|
|
||||||
// Check the second operand (memory operand)
|
// Check the second operand (memory operand)
|
||||||
var memoryOperand2 = movInstruction.StructuredOperands[1];
|
var memoryOperand2 = movInstruction.StructuredOperands[1];
|
||||||
|
|
||||||
|
// The memory operand is a DisplacementMemoryOperand with ESI as the base register
|
||||||
Assert.IsType<DisplacementMemoryOperand>(memoryOperand2);
|
Assert.IsType<DisplacementMemoryOperand>(memoryOperand2);
|
||||||
var memory2 = (DisplacementMemoryOperand)memoryOperand2;
|
var memory2 = (DisplacementMemoryOperand)memoryOperand2;
|
||||||
|
|
||||||
|
// Check the base register and displacement
|
||||||
Assert.Equal(RegisterIndex.Si, memory2.BaseRegister); // Base register is ESI
|
Assert.Equal(RegisterIndex.Si, memory2.BaseRegister); // Base register is ESI
|
||||||
Assert.Equal(4, memory2.Displacement); // Displacement is 4
|
Assert.Equal(4, memory2.Displacement); // Displacement is 4
|
||||||
Assert.Equal(32, memory2.Size); // Memory size is 32 bits (DWORD)
|
Assert.Equal(32, memory2.Size); // Memory size is 32 bits (DWORD)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user