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:
@ -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);
|
||||
|
||||
|
@ -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];
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user