diff --git a/Cpp2IL.Core/ISIL/InstructionSetIndependentOpCode.cs b/Cpp2IL.Core/ISIL/InstructionSetIndependentOpCode.cs index dc83cfe7..de75395c 100644 --- a/Cpp2IL.Core/ISIL/InstructionSetIndependentOpCode.cs +++ b/Cpp2IL.Core/ISIL/InstructionSetIndependentOpCode.cs @@ -21,6 +21,7 @@ public class InstructionSetIndependentOpCode public static readonly InstructionSetIndependentOpCode Or = new(IsilMnemonic.Or, 3, InstructionSetIndependentOperand.OperandType.Any, InstructionSetIndependentOperand.OperandType.Any, InstructionSetIndependentOperand.OperandType.Any); public static readonly InstructionSetIndependentOpCode Xor = new(IsilMnemonic.Xor, 3, InstructionSetIndependentOperand.OperandType.Any, InstructionSetIndependentOperand.OperandType.Any, InstructionSetIndependentOperand.OperandType.Any); public static readonly InstructionSetIndependentOpCode Not = new(IsilMnemonic.Not, 1, InstructionSetIndependentOperand.OperandType.NotStack); + public static readonly InstructionSetIndependentOpCode Neg = new(IsilMnemonic.Neg, 1, InstructionSetIndependentOperand.OperandType.NotStack); public static readonly InstructionSetIndependentOpCode Compare = new(IsilMnemonic.Compare, 2, InstructionSetIndependentOperand.OperandType.Any, InstructionSetIndependentOperand.OperandType.Any); @@ -38,6 +39,8 @@ public class InstructionSetIndependentOpCode public static readonly InstructionSetIndependentOpCode JumpIfEqual = new(IsilMnemonic.JumpIfEqual, 1, InstructionSetIndependentOperand.OperandType.Instruction); public static readonly InstructionSetIndependentOpCode JumpIfNotEqual = new(IsilMnemonic.JumpIfNotEqual, 1, InstructionSetIndependentOperand.OperandType.Instruction); + public static readonly InstructionSetIndependentOpCode JumpIfSign = new(IsilMnemonic.JumpIfSign, 1, InstructionSetIndependentOperand.OperandType.Instruction); + public static readonly InstructionSetIndependentOpCode JumpIfNotSign = new(IsilMnemonic.JumpIfNotSign, 1, InstructionSetIndependentOperand.OperandType.Instruction); public static readonly InstructionSetIndependentOpCode JumpIfGreater = new(IsilMnemonic.JumpIfGreater, 1, InstructionSetIndependentOperand.OperandType.Instruction); public static readonly InstructionSetIndependentOpCode JumpIfLess = new(IsilMnemonic.JumpIfLess, 1, InstructionSetIndependentOperand.OperandType.Instruction); public static readonly InstructionSetIndependentOpCode JumpIfGreaterOrEqual = new(IsilMnemonic.JumpIfGreaterOrEqual, 1, InstructionSetIndependentOperand.OperandType.Instruction); diff --git a/Cpp2IL.Core/ISIL/IsilBuilder.cs b/Cpp2IL.Core/ISIL/IsilBuilder.cs index da9d74e5..ca94f17f 100644 --- a/Cpp2IL.Core/ISIL/IsilBuilder.cs +++ b/Cpp2IL.Core/ISIL/IsilBuilder.cs @@ -87,7 +87,9 @@ public void FixJumps() public void Or(ulong instructionAddress, InstructionSetIndependentOperand dest, InstructionSetIndependentOperand left, InstructionSetIndependentOperand right) => AddInstruction(new(InstructionSetIndependentOpCode.Or, instructionAddress, IsilFlowControl.Continue, dest, left, right)); public void Not(ulong instructionAddress, InstructionSetIndependentOperand src) => AddInstruction(new(InstructionSetIndependentOpCode.Not, instructionAddress, IsilFlowControl.Continue, src)); + public void Neg(ulong instructionAddress, InstructionSetIndependentOperand src) => AddInstruction(new(InstructionSetIndependentOpCode.Neg, instructionAddress, IsilFlowControl.Continue, src)); public void Multiply(ulong instructionAddress, InstructionSetIndependentOperand dest, InstructionSetIndependentOperand src1, InstructionSetIndependentOperand src2) => AddInstruction(new(InstructionSetIndependentOpCode.Multiply, instructionAddress, IsilFlowControl.Continue, dest, src1, src2)); + public void Divide(ulong instructionAddress, InstructionSetIndependentOperand dest, InstructionSetIndependentOperand src1, InstructionSetIndependentOperand src2) => AddInstruction(new(InstructionSetIndependentOpCode.Divide, instructionAddress, IsilFlowControl.Continue, dest, src1, src2)); public void Call(ulong instructionAddress, ulong dest, params InstructionSetIndependentOperand[] args) => AddInstruction(new(InstructionSetIndependentOpCode.Call, instructionAddress, IsilFlowControl.MethodCall, PrepareCallOperands(dest, args))); @@ -103,6 +105,10 @@ public void Return(ulong instructionAddress, InstructionSetIndependentOperand? r public void Goto(ulong instructionAddress, ulong target) => CreateJump(instructionAddress, target, InstructionSetIndependentOpCode.Goto, IsilFlowControl.UnconditionalJump); public void JumpIfEqual(ulong instructionAddress, ulong target) => CreateJump(instructionAddress, target, InstructionSetIndependentOpCode.JumpIfEqual, IsilFlowControl.ConditionalJump); + + public void JumpIfSign(ulong instructionAddress, ulong target) => CreateJump(instructionAddress, target, InstructionSetIndependentOpCode.JumpIfSign, IsilFlowControl.ConditionalJump); + + public void JumpIfNotSign(ulong instructionAddress, ulong target) => CreateJump(instructionAddress, target, InstructionSetIndependentOpCode.JumpIfNotSign, IsilFlowControl.ConditionalJump); public void JumpIfNotEqual(ulong instructionAddress, ulong target) => CreateJump(instructionAddress, target, InstructionSetIndependentOpCode.JumpIfNotEqual, IsilFlowControl.ConditionalJump); diff --git a/Cpp2IL.Core/ISIL/IsilMnemonic.cs b/Cpp2IL.Core/ISIL/IsilMnemonic.cs index 97612bc1..008025c6 100644 --- a/Cpp2IL.Core/ISIL/IsilMnemonic.cs +++ b/Cpp2IL.Core/ISIL/IsilMnemonic.cs @@ -17,6 +17,7 @@ public enum IsilMnemonic Or, Xor, Not, + Neg, Compare, ShiftStack, Push, @@ -29,6 +30,8 @@ public enum IsilMnemonic JumpIfGreaterOrEqual, JumpIfLess, JumpIfLessOrEqual, + JumpIfSign, + JumpIfNotSign, SignExtend, Interrupt, Nop, diff --git a/Cpp2IL.Core/InstructionSets/X86InstructionSet.cs b/Cpp2IL.Core/InstructionSets/X86InstructionSet.cs index bdba6d6f..cdb64007 100644 --- a/Cpp2IL.Core/InstructionSets/X86InstructionSet.cs +++ b/Cpp2IL.Core/InstructionSets/X86InstructionSet.cs @@ -70,6 +70,8 @@ private void ConvertInstructionStatement(Instruction instruction, IsilBuilder bu { case Mnemonic.Mov: case Mnemonic.Movzx: // For all intents and purposes we don't care about zero-extending + case Mnemonic.Movsx: // move with sign-extendign + case Mnemonic.Movsxd: // same 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 @@ -78,8 +80,69 @@ private void ConvertInstructionStatement(Instruction instruction, IsilBuilder bu 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 + case Mnemonic.Cvtps2pd: // same, but float to double + case Mnemonic.Cvttsd2si: // same, but double to integer + case Mnemonic.Movdqu: // DEST[127:0] := SRC[127:0] builder.Move(instruction.IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); break; + case Mnemonic.Cbw: // AX := sign-extend AL + builder.Move(instruction.IP, InstructionSetIndependentOperand.MakeRegister(X86Utils.GetRegisterName(Register.AX)), + InstructionSetIndependentOperand.MakeRegister(X86Utils.GetRegisterName(Register.AL))); + break; + case Mnemonic.Cwde: // EAX := sign-extend AX + builder.Move(instruction.IP, InstructionSetIndependentOperand.MakeRegister(X86Utils.GetRegisterName(Register.EAX)), + InstructionSetIndependentOperand.MakeRegister(X86Utils.GetRegisterName(Register.AX))); + break; + case Mnemonic.Cdqe: // RAX := sign-extend EAX + builder.Move(instruction.IP, InstructionSetIndependentOperand.MakeRegister(X86Utils.GetRegisterName(Register.RAX)), + InstructionSetIndependentOperand.MakeRegister(X86Utils.GetRegisterName(Register.EAX))); + break; + // it's very unsafe if there's been a jump to the next instruction here before. + case Mnemonic.Cwd: // Convert Word to Doubleword + { + // The CWD instruction copies the sign (bit 15) of the value in the AX register into every bit position in the DX register + var temp = InstructionSetIndependentOperand.MakeRegister("TEMP"); + builder.Move(instruction.IP, temp, InstructionSetIndependentOperand.MakeRegister(X86Utils.GetRegisterName(Register.AX))); // TEMP = AX + builder.ShiftRight(instruction.IP, temp, InstructionSetIndependentOperand.MakeImmediate(15)); // TEMP >>= 15 + builder.Compare(instruction.IP, temp, InstructionSetIndependentOperand.MakeImmediate(1)); // temp == 1 + builder.JumpIfNotEqual(instruction.IP, instruction.IP + 1); + // temp == 1 ? DX := ushort.Max (1111111111) or DX := 0 + builder.Move(instruction.IP, InstructionSetIndependentOperand.MakeRegister(X86Utils.GetRegisterName(Register.DX)), InstructionSetIndependentOperand.MakeImmediate(ushort.MaxValue)); + builder.Goto(instruction.IP, instruction.IP + 2); + builder.Move(instruction.IP + 1, InstructionSetIndependentOperand.MakeRegister(X86Utils.GetRegisterName(Register.DX)), InstructionSetIndependentOperand.MakeImmediate(0)); + builder.Nop(instruction.IP + 2); + break; + } + case Mnemonic.Cdq: // Convert Doubleword to Quadword + { + // The CDQ instruction copies the sign (bit 31) of the value in the EAX register into every bit position in the EDX register. + var temp = InstructionSetIndependentOperand.MakeRegister("TEMP"); + builder.Move(instruction.IP, temp, InstructionSetIndependentOperand.MakeRegister(X86Utils.GetRegisterName(Register.EAX))); // TEMP = EAX + builder.ShiftRight(instruction.IP, temp, InstructionSetIndependentOperand.MakeImmediate(31)); // TEMP >>= 31 + builder.Compare(instruction.IP, temp, InstructionSetIndependentOperand.MakeImmediate(1)); // temp == 1 + builder.JumpIfNotEqual(instruction.IP, instruction.IP + 1); + // temp == 1 ? EDX := uint.Max (1111111111) or EDX := 0 + builder.Move(instruction.IP, InstructionSetIndependentOperand.MakeRegister(X86Utils.GetRegisterName(Register.EDX)), InstructionSetIndependentOperand.MakeImmediate(uint.MaxValue)); + builder.Goto(instruction.IP, instruction.IP + 2); + builder.Move(instruction.IP + 1, InstructionSetIndependentOperand.MakeRegister(X86Utils.GetRegisterName(Register.EDX)), InstructionSetIndependentOperand.MakeImmediate(0)); + builder.Nop(instruction.IP + 2); + break; + } + case Mnemonic.Cqo: // same... + { + // The CQO instruction copies the sign (bit 63) of the value in the EAX register into every bit position in the RDX register. + var temp = InstructionSetIndependentOperand.MakeRegister("TEMP"); + builder.Move(instruction.IP, temp, InstructionSetIndependentOperand.MakeRegister(X86Utils.GetRegisterName(Register.RAX))); // TEMP = RAX + builder.ShiftRight(instruction.IP, temp, InstructionSetIndependentOperand.MakeImmediate(63)); // TEMP >>= 63 + builder.Compare(instruction.IP, temp, InstructionSetIndependentOperand.MakeImmediate(1)); // temp == 1 + builder.JumpIfNotEqual(instruction.IP, instruction.IP + 1); + // temp == 1 ? RDX := ulong.Max (1111111111) or RDX := 0 + builder.Move(instruction.IP, InstructionSetIndependentOperand.MakeRegister(X86Utils.GetRegisterName(Register.RDX)), InstructionSetIndependentOperand.MakeImmediate(ulong.MaxValue)); + builder.Goto(instruction.IP, instruction.IP + 2); + builder.Move(instruction.IP + 1, InstructionSetIndependentOperand.MakeRegister(X86Utils.GetRegisterName(Register.RDX)), InstructionSetIndependentOperand.MakeImmediate(0)); + builder.Nop(instruction.IP + 2); + break; + } case Mnemonic.Lea: builder.LoadAddress(instruction.IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); break; @@ -90,10 +153,12 @@ private void ConvertInstructionStatement(Instruction instruction, IsilBuilder bu else builder.Xor(instruction.IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); break; - case Mnemonic.Shl: + case Mnemonic.Shl: // unsigned shift + case Mnemonic.Sal: // signed shift builder.ShiftLeft(instruction.IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); break; - case Mnemonic.Shr: + case Mnemonic.Shr: // unsigned shift + case Mnemonic.Sar: // signed shift builder.ShiftRight(instruction.IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); break; case Mnemonic.And: @@ -105,7 +170,10 @@ private void ConvertInstructionStatement(Instruction instruction, IsilBuilder bu builder.Or(instruction.IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); break; case Mnemonic.Not: - builder.Not(instruction.IP, ConvertOperand(instruction, 0)); + builder.Neg(instruction.IP, ConvertOperand(instruction, 0)); + break; + case Mnemonic.Neg: // dest := -dest + builder.Neg(instruction.IP, ConvertOperand(instruction, 0)); break; case Mnemonic.Imul: if (instruction.OpCount == 1) @@ -147,6 +215,14 @@ private void ConvertInstructionStatement(Instruction instruction, IsilBuilder bu goto default; break; + + case Mnemonic.Divss: // Divide Scalar Single Precision Floating-Point Values. DEST[31:0] = DEST[31:0] / SRC[31:0] + builder.Divide(instruction.IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); + break; + case Mnemonic.Vdivss: // VEX Divide Scalar Single Precision Floating-Point Values. DEST[31:0] = SRC1[31:0] / SRC2[31:0] + builder.Divide(instruction.IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1), ConvertOperand(instruction, 2)); + break; + case Mnemonic.Ret: // TODO: Verify correctness of operation with Vectors. @@ -193,6 +269,7 @@ private void ConvertInstructionStatement(Instruction instruction, IsilBuilder bu 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; @@ -221,6 +298,7 @@ private void ConvertInstructionStatement(Instruction instruction, IsilBuilder bu else builder.Add(instruction.IP, dest, src1, src2); break; + } // The following pair of instructions does not update the Carry Flag (CF): case Mnemonic.Dec: builder.Subtract(instruction.IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 0), InstructionSetIndependentOperand.MakeImmediate(1)); @@ -228,6 +306,51 @@ private void ConvertInstructionStatement(Instruction instruction, IsilBuilder bu case Mnemonic.Inc: builder.Add(instruction.IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 0), InstructionSetIndependentOperand.MakeImmediate(1)); break; + + case Mnemonic.Shufps: // Packed Interleave Shuffle of Quadruplets of Single Precision Floating-Point Values + { + if (instruction.Op1Kind == OpKind.Memory) + goto default; + + var imm = instruction.Immediate8; + var src1 = X86Utils.GetRegisterName(instruction.Op0Register); + var src2 = X86Utils.GetRegisterName(instruction.Op1Register); + var dest = "XMM_TEMP"; + //TEMP_DEST[31:0] := Select4(SRC1[127:0], imm8[1:0]); + builder.Move(instruction.IP, ConvertVector(dest, 0), ConvertVector(src1, imm & 0b11)); + //TEMP_DEST[63:32] := Select4(SRC1[127:0], imm8[3:2]); + builder.Move(instruction.IP, ConvertVector(dest, 1), ConvertVector(src1, (imm >> 2) & 0b11)); + //TEMP_DEST[95:64] := Select4(SRC2[127:0], imm8[5:4]); + builder.Move(instruction.IP, ConvertVector(dest, 2), ConvertVector(src2, (imm >> 4) & 0b11)); + //TEMP_DEST[127:96] := Select4(SRC2[127:0], imm8[7:6]); + builder.Move(instruction.IP, ConvertVector(dest, 3), ConvertVector(src2, (imm >> 6) & 0b11)); + // where Select4(regSlice, imm) => regSlice.[imm switch => { 0 => 0..31, 1 => 32..63, 2 => 64..95, 3 => 96...127 }]; + builder.Move(instruction.IP, ConvertOperand(instruction, 0), InstructionSetIndependentOperand.MakeRegister(dest)); // DEST = TEMP_DEST + break; + + static InstructionSetIndependentOperand ConvertVector(string reg, int imm) => + InstructionSetIndependentOperand.MakeVectorElement(reg, IsilVectorRegisterElementOperand.VectorElementWidth.S, imm); + } + + case Mnemonic.Unpcklps : // Unpack and Interleave Low Packed Single Precision Floating-Point Values + { + if (instruction.Op1Kind == OpKind.Memory) + goto default; + + var src1 = X86Utils.GetRegisterName(instruction.Op0Register); + var src2 = X86Utils.GetRegisterName(instruction.Op1Register); + var dest = "XMM_TEMP"; + builder.Move(instruction.IP, ConvertVector(dest, 0), ConvertVector(src1, 0)); //TMP_DEST[31:0] := SRC1[31:0] + builder.Move(instruction.IP, ConvertVector(dest, 1), ConvertVector(src2, 0)); //TMP_DEST[63:32] := SRC2[31:0] + builder.Move(instruction.IP, ConvertVector(dest, 2), ConvertVector(src1, 1)); //TMP_DEST[95:64] := SRC1[63:32] + builder.Move(instruction.IP, ConvertVector(dest, 3), ConvertVector(src2, 1)); //TMP_DEST[127:96] := SRC2[63:32] + builder.Move(instruction.IP, ConvertOperand(instruction, 0), InstructionSetIndependentOperand.MakeRegister(dest)); // DEST = TEMP_DEST + break; + + static InstructionSetIndependentOperand ConvertVector(string reg, int imm) => + InstructionSetIndependentOperand.MakeVectorElement(reg, IsilVectorRegisterElementOperand.VectorElementWidth.S, imm); + } + case Mnemonic.Call: // We don't try and resolve which method is being called, but we do need to know how many parameters it has // I would hope that all of these methods have the same number of arguments, else how can they be inlined? @@ -297,9 +420,98 @@ private void ConvertInstructionStatement(Instruction instruction, IsilBuilder bu //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 + case Mnemonic.Comiss: //comiss is just a floating point compare dest[31:0] == src[31:0] + case Mnemonic.Ucomiss: // same, but unsigned builder.Compare(instruction.IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); break; + + case Mnemonic.Cmove: // move if condition + case Mnemonic.Cmovne: + case Mnemonic.Cmova: + case Mnemonic.Cmovg: + case Mnemonic.Cmovae: + case Mnemonic.Cmovge: + case Mnemonic.Cmovb: + case Mnemonic.Cmovl: + case Mnemonic.Cmovbe: + case Mnemonic.Cmovle: + case Mnemonic.Cmovs: + case Mnemonic.Cmovns: + switch (instruction.Mnemonic) + { + case Mnemonic.Cmove: // equals + builder.JumpIfNotEqual(instruction.IP, instruction.IP + 1); // skip if not eq + break; + case Mnemonic.Cmovne: // not equals + builder.JumpIfEqual(instruction.IP, instruction.IP + 1); // skip if eq + break; + case Mnemonic.Cmovs: // sign + builder.JumpIfNotSign(instruction.IP, instruction.IP + 1); // skip if not sign + break; + case Mnemonic.Cmovns: // not sign + builder.JumpIfSign(instruction.IP, instruction.IP + 1); // skip if sign + break; + case Mnemonic.Cmova: + case Mnemonic.Cmovg: // greater + builder.JumpIfLessOrEqual(instruction.IP, instruction.IP + 1); // skip if not gt + break; + case Mnemonic.Cmovae: + case Mnemonic.Cmovge: // greater or eq + builder.JumpIfLess(instruction.IP, instruction.IP + 1); // skip if not gt or eq + break; + case Mnemonic.Cmovb: + case Mnemonic.Cmovl: // less + builder.JumpIfGreaterOrEqual(instruction.IP, instruction.IP + 1); // skip if not lt + break; + case Mnemonic.Cmovbe: + case Mnemonic.Cmovle: // less or eq + builder.JumpIfGreater(instruction.IP, instruction.IP + 1); // skip if not lt or eq + break; + } + builder.Move(instruction.IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); // set if cond + builder.Nop(instruction.IP + 1); + break; + + case Mnemonic.Maxss: // dest < src ? src : dest + case Mnemonic.Minss: // dest > src ? src : dest + { + var dest = ConvertOperand(instruction, 0); + var src = ConvertOperand(instruction, 1); + builder.Compare(instruction.IP, dest, src); // compare dest & src + if (instruction.Mnemonic == Mnemonic.Maxss) + builder.JumpIfGreaterOrEqual(instruction.IP, instruction.IP + 1); // enter if dest < src + else + builder.JumpIfLessOrEqual(instruction.IP, instruction.IP + 1); // enter if dest > src + builder.Move(instruction.IP, dest, src); // dest = src + builder.Nop(instruction.IP + 1); // exit for IF + break; + } + + case Mnemonic.Cmpxchg: // compare and exchange + { + var accumulator = InstructionSetIndependentOperand.MakeRegister(instruction.Op1Register.GetSize() switch + { + 8 => X86Utils.GetRegisterName(Register.RAX), + 4 => X86Utils.GetRegisterName(Register.EAX), + 2 => X86Utils.GetRegisterName(Register.AX), + 1 => X86Utils.GetRegisterName(Register.AL), + _ => throw new NotSupportedException("unexpected behavior") + }); + var dest = ConvertOperand(instruction, 0); + var src = ConvertOperand(instruction, 1); + builder.Compare(instruction.IP, accumulator, dest); + builder.JumpIfNotEqual(instruction.IP, instruction.IP + 1); // if accumulator == dest + // SET ZF = 1 + builder.Move(instruction.IP, dest, src); // DEST = SRC + builder.Goto(instruction.IP, instruction.IP + 2); // END IF + // ELSE + // SET ZF = 0 + builder.Move(instruction.IP + 1, accumulator, dest); // accumulator = dest + + builder.Nop(instruction.IP + 2); // exit for IF + break; + } + case Mnemonic.Jmp: if (instruction.Op0Kind != OpKind.Register) { @@ -319,6 +531,11 @@ private void ConvertInstructionStatement(Instruction instruction, IsilBuilder bu break; } } + if (instruction.Op0Kind == OpKind.Register) // ex: jmp rax + { + builder.CallRegister(instruction.IP, ConvertOperand(instruction, 0), noReturn: true); + break; + } goto default; case Mnemonic.Je: @@ -339,7 +556,26 @@ private void ConvertInstructionStatement(Instruction instruction, IsilBuilder bu builder.JumpIfNotEqual(instruction.IP, jumpTarget); break; } + goto default; + case Mnemonic.Js: + if (instruction.Op0Kind != OpKind.Register) + { + var jumpTarget = instruction.NearBranchTarget; + + builder.JumpIfSign(instruction.IP, jumpTarget); + break; + } + + goto default; + case Mnemonic.Jns: + if (instruction.Op0Kind != OpKind.Register) + { + var jumpTarget = instruction.NearBranchTarget; + builder.JumpIfNotSign(instruction.IP, jumpTarget); + break; + } + goto default; case Mnemonic.Jg: case Mnemonic.Ja: @@ -393,6 +629,7 @@ private void ConvertInstructionStatement(Instruction instruction, IsilBuilder bu case Mnemonic.Int3: builder.Interrupt(instruction.IP); // We'll add it but eliminate later, can be used as a hint since compilers only emit it in normally unreachable code or in error handlers break; + case Mnemonic.Prefetchw: // Fetches the cache line containing the specified byte from memory to the 1st or 2nd level cache, invalidating other cached copies. 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.