From 671f78c1c6709ef5406a7acdb286dd713e171503 Mon Sep 17 00:00:00 2001 From: Sam Byass Date: Mon, 12 Aug 2024 14:50:43 +0100 Subject: [PATCH] Core: ISIL: Implement some more x86 stuff --- .../ISIL/InstructionSetIndependentOpCode.cs | 1 + Cpp2IL.Core/ISIL/IsilBuilder.cs | 1 + Cpp2IL.Core/ISIL/IsilMnemonic.cs | 1 + .../InstructionSets/X86InstructionSet.cs | 60 ++++++++++++++++++- 4 files changed, 62 insertions(+), 1 deletion(-) diff --git a/Cpp2IL.Core/ISIL/InstructionSetIndependentOpCode.cs b/Cpp2IL.Core/ISIL/InstructionSetIndependentOpCode.cs index 77a569fc..70529867 100644 --- a/Cpp2IL.Core/ISIL/InstructionSetIndependentOpCode.cs +++ b/Cpp2IL.Core/ISIL/InstructionSetIndependentOpCode.cs @@ -42,6 +42,7 @@ public class InstructionSetIndependentOpCode public static readonly InstructionSetIndependentOpCode JumpIfLessOrEqual = new(IsilMnemonic.JumpIfLessOrEqual, 1, InstructionSetIndependentOperand.OperandType.Instruction); public static readonly InstructionSetIndependentOpCode Interrupt = new(IsilMnemonic.Interrupt, 0); + public static readonly InstructionSetIndependentOpCode Nop = new(IsilMnemonic.Nop, 0); public static readonly InstructionSetIndependentOpCode NotImplemented = new(IsilMnemonic.NotImplemented, 1, InstructionSetIndependentOperand.OperandType.Immediate); diff --git a/Cpp2IL.Core/ISIL/IsilBuilder.cs b/Cpp2IL.Core/ISIL/IsilBuilder.cs index 22cf7b55..25ef91bd 100644 --- a/Cpp2IL.Core/ISIL/IsilBuilder.cs +++ b/Cpp2IL.Core/ISIL/IsilBuilder.cs @@ -125,6 +125,7 @@ private void CreateJump(ulong instructionAddress, ulong target, InstructionSetIn public void Invalid(ulong instructionAddress, string text) => AddInstruction(new(InstructionSetIndependentOpCode.Invalid, instructionAddress, IsilFlowControl.Continue, InstructionSetIndependentOperand.MakeImmediate(text))); public void Interrupt(ulong instructionAddress) => AddInstruction(new(InstructionSetIndependentOpCode.Interrupt, instructionAddress, IsilFlowControl.Interrupt)); + public void Nop(ulong instructionAddress) => AddInstruction(new(InstructionSetIndependentOpCode.Nop, instructionAddress, IsilFlowControl.Continue)); private InstructionSetIndependentOperand[] PrepareCallOperands(ulong dest, InstructionSetIndependentOperand[] args) { diff --git a/Cpp2IL.Core/ISIL/IsilMnemonic.cs b/Cpp2IL.Core/ISIL/IsilMnemonic.cs index 4ccc7892..97612bc1 100644 --- a/Cpp2IL.Core/ISIL/IsilMnemonic.cs +++ b/Cpp2IL.Core/ISIL/IsilMnemonic.cs @@ -31,6 +31,7 @@ public enum IsilMnemonic JumpIfLessOrEqual, SignExtend, Interrupt, + Nop, NotImplemented, Invalid, } diff --git a/Cpp2IL.Core/InstructionSets/X86InstructionSet.cs b/Cpp2IL.Core/InstructionSets/X86InstructionSet.cs index 3c844adc..c9794a5f 100644 --- a/Cpp2IL.Core/InstructionSets/X86InstructionSet.cs +++ b/Cpp2IL.Core/InstructionSets/X86InstructionSet.cs @@ -66,12 +66,22 @@ private void ConvertInstructionStatement(Instruction instruction, IsilBuilder bu switch (instruction.Mnemonic) { case Mnemonic.Mov: + case Mnemonic.Movzx: //For all intents and purposes we don't care about zero-extending + case Mnemonic.Movaps: //Movaps is basically just a mov but with the potential future detail that the size is dependent on reg size + case Mnemonic.Movups: //Movaps but unaligned + case Mnemonic.Movss: //Same as movaps but for floats + case Mnemonic.Movd: //Mov but specifically dword + case Mnemonic.Movq: //Mov but specifically qword + case Mnemonic.Movsd: //Mov but specifically double + case Mnemonic.Movdqa: //Movaps but multiple integers at once in theory + case Mnemonic.Cvtdq2ps: //Technically a convert double to single, but for analysis purposes we can just treat it as a move builder.Move(instruction.IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); break; case Mnemonic.Lea: builder.LoadAddress(instruction.IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); break; case Mnemonic.Xor: + case Mnemonic.Xorps: //xorps is just floating point xor if (instruction.Op0Kind == OpKind.Register && instruction.Op1Kind == OpKind.Register && instruction.Op0Register == instruction.Op1Register) builder.Move(instruction.IP, ConvertOperand(instruction, 0), InstructionSetIndependentOperand.MakeImmediate(0)); else @@ -84,9 +94,11 @@ private void ConvertInstructionStatement(Instruction instruction, IsilBuilder bu builder.ShiftRight(instruction.IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); break; case Mnemonic.And: + case Mnemonic.Andps: //Floating point and builder.And(instruction.IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); break; case Mnemonic.Or: + case Mnemonic.Orps: //Floating point or builder.Or(instruction.IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); break; case Mnemonic.Not: @@ -120,6 +132,16 @@ private void ConvertInstructionStatement(Instruction instruction, IsilBuilder bu else if (instruction.OpCount == 3) builder.Multiply(instruction.IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1), ConvertOperand(instruction, 2)); else builder.Multiply(instruction.IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); break; + case Mnemonic.Mulss: + case Mnemonic.Vmulss: + if (instruction.OpCount == 3) + builder.Multiply(instruction.IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1), ConvertOperand(instruction, 2)); + else if (instruction.OpCount == 2) + builder.Multiply(instruction.IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); + else + goto default; + + break; case Mnemonic.Ret: if (context.IsVoid) builder.Return(instruction.IP); @@ -156,6 +178,34 @@ private void ConvertInstructionStatement(Instruction instruction, IsilBuilder bu builder.Add(instruction.IP, left, left, right); break; + case Mnemonic.Addss: + case Mnemonic.Subss: + //Addss and subss are just floating point add/sub, but we don't need to handle the stack stuff + //But we do need to handle 2 vs 3 operand forms + InstructionSetIndependentOperand dest; + InstructionSetIndependentOperand src1; + InstructionSetIndependentOperand src2; + + if (instruction.OpCount == 3) + { + //dest, src1, src2 + dest = ConvertOperand(instruction, 0); + src1 = ConvertOperand(instruction, 1); + src2 = ConvertOperand(instruction, 2); + } else if (instruction.OpCount == 2) + { + //DestAndSrc1, Src2 + dest = ConvertOperand(instruction, 0); + src1 = dest; + src2 = ConvertOperand(instruction, 1); + } else + goto default; + + if (instruction.Mnemonic == Mnemonic.Subss) + builder.Subtract(instruction.IP, dest, src1, src2); + else + builder.Add(instruction.IP, dest, src1, src2); + break; case Mnemonic.Dec: case Mnemonic.Inc: // no CF @@ -222,8 +272,11 @@ private void ConvertInstructionStatement(Instruction instruction, IsilBuilder bu builder.Compare(instruction.IP, ConvertOperand(instruction, 0), InstructionSetIndependentOperand.MakeImmediate(0)); break; } - goto default; + + //Fall through to cmp, as test is just a cmp that doesn't set flags + goto case Mnemonic.Cmp; case Mnemonic.Cmp: + case Mnemonic.Comiss: //comiss is just a floating point compare builder.Compare(instruction.IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); break; case Mnemonic.Jmp: @@ -312,6 +365,11 @@ private void ConvertInstructionStatement(Instruction instruction, IsilBuilder bu case Mnemonic.Int3: builder.Interrupt(instruction.IP); // We'll add it but eliminate later break; + case Mnemonic.Nop: + //While this is literally a nop and there's in theory no point emitting anything for it, it could be used as a jump target. + //So we'll emit an ISIL nop for it. + builder.Nop(instruction.IP); + break; default: builder.NotImplemented(instruction.IP, FormatInstruction(instruction)); break;