0
mirror of https://github.com/sampletext32/ParkanPlayground.git synced 2025-06-19 16:08:02 +03:00

Fixed TEST instruction handlers and tests. Updated TestImmWithRm8Handler and TestImmWithRm32Handler to properly check opcode in CanHandle and validate reg field in Decode. Improved test cases to use InstructionDecoder directly.

This commit is contained in:
bird_egop
2025-04-12 21:21:03 +03:00
parent bf5fcdd2ff
commit fe0b04f5a1
10 changed files with 330 additions and 74 deletions

View File

@ -23,18 +23,9 @@ public class TestImmWithRm32Handler : Group3BaseHandler
/// <returns>True if this handler can decode the opcode</returns>
public override bool CanHandle(byte opcode)
{
if (opcode != 0xF7)
return false;
// Check if the reg field of the ModR/M byte is 0 (TEST)
int position = Decoder.GetPosition();
if (position >= Length)
return false;
byte modRM = CodeBuffer[position];
byte reg = (byte)((modRM & 0x38) >> 3);
return reg == 0; // 0 = TEST
// This handler only handles opcode 0xF7
// The reg field check (for TEST operation) will be done in the Decode method
return opcode == 0xF7;
}
/// <summary>
@ -45,9 +36,6 @@ public class TestImmWithRm32Handler : Group3BaseHandler
/// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction)
{
// Set the mnemonic
instruction.Mnemonic = "test";
int position = Decoder.GetPosition();
if (position >= Length)
@ -57,15 +45,36 @@ public class TestImmWithRm32Handler : Group3BaseHandler
// Read the ModR/M byte
byte modRM = CodeBuffer[position++];
Decoder.SetPosition(position);
// Extract the fields from the ModR/M byte
byte mod = (byte)((modRM & 0xC0) >> 6);
byte reg = (byte)((modRM & 0x38) >> 3); // Should be 0 for TEST
byte rm = (byte)(modRM & 0x07);
// Decode the destination operand
string destOperand = _modRMDecoder.DecodeModRM(mod, rm, false);
// Check if the reg field is 0 (TEST operation)
if (reg != 0)
{
return false; // Not a TEST instruction
}
// Set the mnemonic
instruction.Mnemonic = "test";
Decoder.SetPosition(position);
// Get the operand based on the addressing mode
string destOperand;
// For direct register addressing (mod == 3), the r/m field specifies a register
if (mod == 3)
{
destOperand = GetRegister32(rm);
}
else
{
// Use the ModR/M decoder for memory addressing
destOperand = _modRMDecoder.DecodeModRM(mod, rm, false);
}
// Read the immediate value
if (position + 3 >= Length)
@ -73,6 +82,7 @@ public class TestImmWithRm32Handler : Group3BaseHandler
return false;
}
// Read the immediate value using BitConverter
uint imm32 = BitConverter.ToUInt32(CodeBuffer, position);
Decoder.SetPosition(position + 4);

View File

@ -23,18 +23,9 @@ public class TestImmWithRm8Handler : Group3BaseHandler
/// <returns>True if this handler can decode the opcode</returns>
public override bool CanHandle(byte opcode)
{
if (opcode != 0xF6)
return false;
// Check if the reg field of the ModR/M byte is 0 (TEST)
int position = Decoder.GetPosition();
if (position >= Length)
return false;
byte modRM = CodeBuffer[position];
byte reg = (byte)((modRM & 0x38) >> 3);
return reg == 0; // 0 = TEST
// This handler only handles opcode 0xF6
// The reg field check (for TEST operation) will be done in the Decode method
return opcode == 0xF6;
}
/// <summary>
@ -45,9 +36,6 @@ public class TestImmWithRm8Handler : Group3BaseHandler
/// <returns>True if the instruction was successfully decoded</returns>
public override bool Decode(byte opcode, Instruction instruction)
{
// Set the mnemonic
instruction.Mnemonic = "test";
int position = Decoder.GetPosition();
if (position >= Length)
@ -57,20 +45,29 @@ public class TestImmWithRm8Handler : Group3BaseHandler
// Read the ModR/M byte
byte modRM = CodeBuffer[position++];
Decoder.SetPosition(position);
// Extract the fields from the ModR/M byte
byte mod = (byte)((modRM & 0xC0) >> 6);
byte reg = (byte)((modRM & 0x38) >> 3); // Should be 0 for TEST
byte rm = (byte)(modRM & 0x07);
// Decode the destination operand
// Check if the reg field is 0 (TEST operation)
if (reg != 0)
{
return false; // Not a TEST instruction
}
// Set the mnemonic
instruction.Mnemonic = "test";
Decoder.SetPosition(position);
// Get the operand based on the addressing mode
string destOperand;
// Special case for direct register addressing (mod == 3)
// For direct register addressing (mod == 3), the r/m field specifies a register
if (mod == 3)
{
// Get the register name based on the rm field
destOperand = GetRegister8(rm);
}
else
@ -93,15 +90,4 @@ public class TestImmWithRm8Handler : Group3BaseHandler
return true;
}
/// <summary>
/// Gets the 8-bit register name for the given register index
/// </summary>
/// <param name="reg">The register index</param>
/// <returns>The register name</returns>
private static new string GetRegister8(byte reg)
{
string[] registerNames = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" };
return registerNames[reg & 0x07];
}
}

View File

@ -39,13 +39,20 @@ public class TestEaxImmHandler : InstructionHandler
int position = Decoder.GetPosition();
if (position + 4 > Length)
if (position + 3 >= Length)
{
return false;
}
// Read the immediate value
uint imm32 = BitConverter.ToUInt32(CodeBuffer, position);
// Read the immediate value - x86 is little-endian, so we need to read the bytes in the correct order
byte b0 = CodeBuffer[position];
byte b1 = CodeBuffer[position + 1];
byte b2 = CodeBuffer[position + 2];
byte b3 = CodeBuffer[position + 3];
// Combine the bytes to form a 32-bit immediate value
uint imm32 = (uint)(b0 | (b1 << 8) | (b2 << 16) | (b3 << 24));
Decoder.SetPosition(position + 4);
// Set the operands

View File

@ -57,14 +57,30 @@ public class TestRegMem8Handler : InstructionHandler
byte reg = (byte)((modRM & 0x38) >> 3);
byte rm = (byte)(modRM & 0x07);
// Decode the destination operand
string destOperand = _modRMDecoder.DecodeModRM(mod, rm, true);
// Get the source register
string srcReg = GetRegister8(reg);
// Set the operands
instruction.Operands = $"{destOperand}, {srcReg}";
// For direct register addressing (mod == 3), the r/m field specifies a register
if (mod == 3)
{
// Get the register names
string rmReg = GetRegister8(rm);
string regReg = GetRegister8(reg);
// Set the operands (TEST r/m8, r8)
// In x86 assembly, the TEST instruction has the operand order r/m8, r8
// According to Ghidra and standard x86 assembly convention, it should be TEST CL,AL
// where CL is the r/m operand and AL is the reg operand
instruction.Operands = $"{rmReg}, {regReg}";
}
else
{
// Decode the memory operand
string memOperand = _modRMDecoder.DecodeModRM(mod, rm, true);
// Get the register name
string regReg = GetRegister8(reg);
// Set the operands (TEST r/m8, r8)
instruction.Operands = $"{memOperand}, {regReg}";
}
return true;
}

View File

@ -57,14 +57,30 @@ public class TestRegMemHandler : InstructionHandler
byte reg = (byte)((modRM & 0x38) >> 3);
byte rm = (byte)(modRM & 0x07);
// Decode the destination operand
string destOperand = _modRMDecoder.DecodeModRM(mod, rm, false);
// Get the source register
string srcReg = GetRegister32(reg);
// Set the operands
instruction.Operands = $"{destOperand}, {srcReg}";
// For direct register addressing (mod == 3), the r/m field specifies a register
if (mod == 3)
{
// Get the register names
string rmReg = GetRegister32(rm);
string regReg = GetRegister32(reg);
// Set the operands (TEST r/m32, r32)
// In x86 assembly, the TEST instruction has the operand order r/m32, r32
// According to Ghidra and standard x86 assembly convention, it should be TEST ECX,EAX
// where ECX is the r/m operand and EAX is the reg operand
instruction.Operands = $"{rmReg}, {regReg}";
}
else
{
// Decode the memory operand
string memOperand = _modRMDecoder.DecodeModRM(mod, rm, false);
// Get the register name
string regReg = GetRegister32(reg);
// Set the operands (TEST r/m32, r32)
instruction.Operands = $"{memOperand}, {regReg}";
}
return true;
}