• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SamboyCoding / Cpp2IL / 17216182984

25 Aug 2025 05:35PM UTC coverage: 30.38% (-4.0%) from 34.352%
17216182984

Pull #481

github

web-flow
Merge b82763a24 into d5260685f
Pull Request #481: Decompiler

1804 of 7561 branches covered (23.86%)

Branch coverage included in aggregate %.

100 of 1839 new or added lines in 29 files covered. (5.44%)

41 existing lines in 6 files now uncovered.

4093 of 11850 relevant lines covered (34.54%)

165575.01 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.13
/Cpp2IL.Core/InstructionSets/X86InstructionSet.cs
1
using System;
2
using System.Collections.Generic;
3
using System.Linq;
4
using Cpp2IL.Core.Api;
5
using Cpp2IL.Core.Extensions;
6
using Cpp2IL.Core.Il2CppApiFunctions;
7
using Cpp2IL.Core.Model.Contexts;
8
using Cpp2IL.Core.Utils;
9
using Iced.Intel;
10
using LibCpp2IL.BinaryStructures;
11

12
namespace Cpp2IL.Core.InstructionSets;
13

14
// This is honestly an X64InstructionSet by all means. Everything here screams "I AM X64".
15
public class X86InstructionSet : Cpp2IlInstructionSet
16
{
17
    private static readonly MasmFormatter Formatter = new();
×
18
    private static readonly StringOutput Output = new();
×
19

20
    private static string FormatInstructionInternal(Instruction instruction)
21
    {
22
        Formatter.Format(instruction, Output);
×
23
        return Output.ToStringAndReset();
×
24
    }
25

26
    public static string FormatInstruction(Instruction instruction)
27
    {
28
        lock (Formatter)
×
29
        {
30
            return FormatInstructionInternal(instruction);
×
31
        }
32
    }
×
33

34
    public override Memory<byte> GetRawBytesForMethod(MethodAnalysisContext context, bool isAttributeGenerator) => X86Utils.GetRawManagedOrCaCacheGenMethodBody(context.UnderlyingPointer, isAttributeGenerator);
723,126✔
35

36
    public override BaseKeyFunctionAddresses CreateKeyFunctionAddressesInstance() => new X86KeyFunctionAddresses();
×
37

38
    public override string PrintAssembly(MethodAnalysisContext context)
39
    {
40
        lock (Formatter)
×
41
        {
42
            var insns = X86Utils.Iterate(X86Utils.GetRawManagedOrCaCacheGenMethodBody(context.UnderlyingPointer, false), context.UnderlyingPointer);
×
43

44
            return string.Join("\n", insns.Select(FormatInstructionInternal));
×
45
        }
46
    }
×
47

48
    public override List<ISIL.Instruction> GetIsilFromMethod(MethodAnalysisContext context)
49
    {
NEW
50
        var instructions = new List<ISIL.Instruction>();
×
NEW
51
        var addresses = new List<ulong>();
×
52

53
        foreach (var instruction in X86Utils.Iterate(context))
×
NEW
54
            ConvertInstructionStatement(instruction, instructions, addresses, context);
×
55

56
        // Add return if the function doesn't end with one already
NEW
57
        if (instructions.Count > 0 && instructions[^1].OpCode != ISIL.OpCode.Return)
×
58
        {
NEW
59
            var index = instructions[^1].Index + 1;
×
60

NEW
61
            if (context.IsVoid)
×
NEW
62
                instructions.Add(new ISIL.Instruction(index, ISIL.OpCode.Return));
×
NEW
63
            else if (context.Definition?.RawReturnType?.Type is Il2CppTypeEnum.IL2CPP_TYPE_R4 or Il2CppTypeEnum.IL2CPP_TYPE_R8)
×
NEW
64
                instructions.Add(new ISIL.Instruction(index, ISIL.OpCode.Return, new ISIL.Register(null, "xmm0")));
×
65
            else
NEW
66
                instructions.Add(new ISIL.Instruction(index, ISIL.OpCode.Return, new ISIL.Register(null, "rax")));
×
67
        }
68

69
        // fix branches
NEW
70
        for (var i = 0; i < instructions.Count; i++)
×
71
        {
NEW
72
            var instruction = instructions[i];
×
73

NEW
74
            if (instruction.OpCode != ISIL.OpCode.Jump && instruction.OpCode != ISIL.OpCode.ConditionalJump)
×
75
                continue;
76

NEW
77
            var targetAddress = (ulong)instruction.Operands[0];
×
NEW
78
            var targetIndex = addresses.FindIndex(addr => addr == targetAddress);
×
79

NEW
80
            if (targetIndex == -1)
×
81
            {
NEW
82
                instruction.OpCode = ISIL.OpCode.Invalid;
×
NEW
83
                instruction.Operands = [$"Jump target not found in method: 0x{targetAddress:X4}"];
×
NEW
84
                continue;
×
85
            }
86

NEW
87
            var targetInstruction = instructions[targetIndex];
×
88

NEW
89
            instruction.Operands[0] = targetInstruction;
×
90
        }
91

NEW
92
        return instructions;
×
93
    }
94

95
    public override List<object> GetParameterOperandsFromMethod(MethodAnalysisContext context)
96
    {
NEW
97
        return X64CallingConventionResolver.ResolveForManaged(context).ToList();
×
98
    }
99

100
    private void ConvertInstructionStatement(Instruction instruction, List<ISIL.Instruction> instructions, List<ulong> addresses, MethodAnalysisContext context)
101
    {
102
        var callNoReturn = false;
×
103
        int operandSize;
104

105
        ISIL.Instruction Add(ulong address, ISIL.OpCode opCode, params object[] operands)
106
        {
NEW
107
            addresses.Add(address);
×
NEW
108
            var newInstruction = new ISIL.Instruction(instructions.Count, opCode, operands);
×
NEW
109
            instructions.Add(newInstruction);
×
NEW
110
            return newInstruction;
×
111
        }
112

UNCOV
113
        switch (instruction.Mnemonic)
×
114
        {
115
            case Mnemonic.Mov:
116
            case Mnemonic.Movzx: // For all intents and purposes we don't care about zero-extending
117
            case Mnemonic.Movsx: // move with sign-extendign
118
            case Mnemonic.Movsxd: // same
119
            case Mnemonic.Movaps: // Movaps is basically just a mov but with the potential future detail that the size is dependent on reg size
120
            case Mnemonic.Movups: // Movaps but unaligned
121
            case Mnemonic.Movss: // Same as movaps but for floats
122
            case Mnemonic.Movd: // Mov but specifically dword
123
            case Mnemonic.Movq: // Mov but specifically qword
124
            case Mnemonic.Movsd: // Mov but specifically double
125
            case Mnemonic.Movdqa: // Movaps but multiple integers at once in theory
126
            case Mnemonic.Cvtdq2ps: // Technically a convert double to single, but for analysis purposes we can just treat it as a move
127
            case Mnemonic.Cvtps2pd: // same, but float to double
128
            case Mnemonic.Cvttsd2si: // same, but double to integer
129
            case Mnemonic.Movdqu: // DEST[127:0] := SRC[127:0]
NEW
130
                Add(instruction.IP, ISIL.OpCode.Move, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1));
×
131
                break;
×
132
            case Mnemonic.Cbw: // AX := sign-extend AL
NEW
133
                Add(instruction.IP, ISIL.OpCode.Move, new ISIL.Register(null, X86Utils.GetRegisterName(Register.AX)),
×
NEW
134
                    new ISIL.Register(null, X86Utils.GetRegisterName(Register.AL)));
×
UNCOV
135
                break;
×
136
            case Mnemonic.Cwde: // EAX := sign-extend AX
NEW
137
                Add(instruction.IP, ISIL.OpCode.Move, new ISIL.Register(null, X86Utils.GetRegisterName(Register.EAX)),
×
NEW
138
                    new ISIL.Register(null, X86Utils.GetRegisterName(Register.AX)));
×
UNCOV
139
                break;
×
140
            case Mnemonic.Cdqe: // RAX := sign-extend EAX
NEW
141
                Add(instruction.IP, ISIL.OpCode.Move, new ISIL.Register(null, X86Utils.GetRegisterName(Register.RAX)),
×
NEW
142
                    new ISIL.Register(null, X86Utils.GetRegisterName(Register.EAX)));
×
UNCOV
143
                break;
×
144
            // it's very unsafe if there's been a jump to the next instruction here before.
145
            case Mnemonic.Cwd: // Convert Word to Doubleword
146
                {
147
                    // The CWD instruction copies the sign (bit 15) of the value in the AX register into every bit position in the DX register
NEW
148
                    var temp = new ISIL.Register(null, "TEMP");
×
NEW
149
                    Add(instruction.IP, ISIL.OpCode.Move, temp, new ISIL.Register(null, X86Utils.GetRegisterName(Register.AX))); // TEMP = AX
×
NEW
150
                    Add(instruction.IP, ISIL.OpCode.ShiftRight, temp, temp, 15); // TEMP >>= 15
×
NEW
151
                    Add(instruction.IP, ISIL.OpCode.CheckEqual, temp, temp, 1); // temp == 1
×
NEW
152
                    Add(instruction.IP, ISIL.OpCode.Not, temp, temp); // temp = !temp
×
NEW
153
                    Add(instruction.IP, ISIL.OpCode.ConditionalJump, instruction.IP + 1, temp);
×
154
                    // temp == 1 ? DX := ushort.Max (1111111111) or DX := 0
NEW
155
                    Add(instruction.IP, ISIL.OpCode.Move, new ISIL.Register(null, X86Utils.GetRegisterName(Register.DX)), ushort.MaxValue);
×
NEW
156
                    Add(instruction.IP, ISIL.OpCode.Jump, instruction.IP + 2);
×
NEW
157
                    Add(instruction.IP + 1, ISIL.OpCode.Move, new ISIL.Register(null, X86Utils.GetRegisterName(Register.DX)), 0);
×
NEW
158
                    Add(instruction.IP + 2, ISIL.OpCode.Nop);
×
NEW
159
                    break;
×
160
                }
161
            case Mnemonic.Cdq: // Convert Doubleword to Quadword
162
                {
163
                    // The CDQ instruction copies the sign (bit 31) of the value in the EAX register into every bit position in the EDX register.
NEW
164
                    var temp = new ISIL.Register(null, "TEMP");
×
NEW
165
                    Add(instruction.IP, ISIL.OpCode.Move, temp, new ISIL.Register(null, X86Utils.GetRegisterName(Register.EAX))); // TEMP = EAX
×
NEW
166
                    Add(instruction.IP, ISIL.OpCode.ShiftRight, temp, temp, 31); // TEMP >>= 31
×
NEW
167
                    Add(instruction.IP, ISIL.OpCode.CheckEqual, temp, temp, 1); // temp == 1
×
NEW
168
                    Add(instruction.IP, ISIL.OpCode.Not, temp, temp); // temp = !temp
×
NEW
169
                    Add(instruction.IP, ISIL.OpCode.ConditionalJump, instruction.IP + 1, temp);
×
170
                    // temp == 1 ? EDX := uint.Max (1111111111) or EDX := 0
NEW
171
                    Add(instruction.IP, ISIL.OpCode.Move, new ISIL.Register(null, X86Utils.GetRegisterName(Register.EDX)), uint.MaxValue);
×
NEW
172
                    Add(instruction.IP, ISIL.OpCode.Jump, instruction.IP + 2);
×
NEW
173
                    Add(instruction.IP + 1, ISIL.OpCode.Move, new ISIL.Register(null, X86Utils.GetRegisterName(Register.EDX)), 0);
×
NEW
174
                    Add(instruction.IP + 2, ISIL.OpCode.Nop);
×
NEW
175
                    break;
×
176
                }
177
            case Mnemonic.Cqo: // same...
178
                {
179
                    // The CQO instruction copies the sign (bit 63) of the value in the EAX register into every bit position in the RDX register.
NEW
180
                    var temp = new ISIL.Register(null, "TEMP");
×
NEW
181
                    Add(instruction.IP, ISIL.OpCode.Move, temp, new ISIL.Register(null, X86Utils.GetRegisterName(Register.RAX))); // TEMP = RAX
×
NEW
182
                    Add(instruction.IP, ISIL.OpCode.ShiftRight, temp, temp, 63); // TEMP >>= 63
×
NEW
183
                    Add(instruction.IP, ISIL.OpCode.CheckEqual, temp, temp, 1); // temp == 1
×
NEW
184
                    Add(instruction.IP, ISIL.OpCode.Not, temp, temp); // temp = !temp
×
NEW
185
                    Add(instruction.IP, ISIL.OpCode.ConditionalJump, instruction.IP + 1, temp);
×
186
                    // temp == 1 ? RDX := ulong.Max (1111111111) or RDX := 0
NEW
187
                    Add(instruction.IP, ISIL.OpCode.Move, new ISIL.Register(null, X86Utils.GetRegisterName(Register.RDX)), ulong.MaxValue);
×
NEW
188
                    Add(instruction.IP, ISIL.OpCode.Jump, instruction.IP + 2);
×
NEW
189
                    Add(instruction.IP + 1, ISIL.OpCode.Move, new ISIL.Register(null, X86Utils.GetRegisterName(Register.RDX)), 0);
×
NEW
190
                    Add(instruction.IP + 2, ISIL.OpCode.Nop);
×
NEW
191
                    break;
×
192
                }
193
            case Mnemonic.Lea:
NEW
194
                Add(instruction.IP, ISIL.OpCode.Move, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1, true));
×
195
                break;
×
196
            case Mnemonic.Xor:
197
            case Mnemonic.Xorps: //xorps is just floating point xor
198
                if (instruction.Op0Kind == OpKind.Register && instruction.Op1Kind == OpKind.Register && instruction.Op0Register == instruction.Op1Register)
×
NEW
199
                    Add(instruction.IP, ISIL.OpCode.Move, ConvertOperand(instruction, 0), 0);
×
200
                else
NEW
201
                    Add(instruction.IP, ISIL.OpCode.Xor, ConvertOperand(instruction, 0), ConvertOperand(instruction, 0), ConvertOperand(instruction, 1));
×
202
                break;
×
203
            case Mnemonic.Shl: // unsigned shift
204
            case Mnemonic.Sal: // signed shift
NEW
205
                Add(instruction.IP, ISIL.OpCode.ShiftLeft, ConvertOperand(instruction, 0), ConvertOperand(instruction, 0), ConvertOperand(instruction, 1));
×
206
                break;
×
207
            case Mnemonic.Shr: // unsigned shift
208
            case Mnemonic.Sar: // signed shift
NEW
209
                Add(instruction.IP, ISIL.OpCode.ShiftRight, ConvertOperand(instruction, 0), ConvertOperand(instruction, 0), ConvertOperand(instruction, 1));
×
210
                break;
×
211
            case Mnemonic.And:
212
            case Mnemonic.Andps: //Floating point and
NEW
213
                Add(instruction.IP, ISIL.OpCode.And, ConvertOperand(instruction, 0), ConvertOperand(instruction, 0), ConvertOperand(instruction, 1));
×
214
                break;
×
215
            case Mnemonic.Or:
216
            case Mnemonic.Orps: //Floating point or
NEW
217
                Add(instruction.IP, ISIL.OpCode.Or, ConvertOperand(instruction, 0), ConvertOperand(instruction, 0), ConvertOperand(instruction, 1));
×
218
                break;
×
219
            case Mnemonic.Not:
NEW
220
                Add(instruction.IP, ISIL.OpCode.Not, ConvertOperand(instruction, 0), ConvertOperand(instruction, 0));
×
221
                break;
×
222
            case Mnemonic.Neg: // dest := -dest
NEW
223
                Add(instruction.IP, ISIL.OpCode.Negate, ConvertOperand(instruction, 0), ConvertOperand(instruction, 0));
×
224
                break;
×
225
            case Mnemonic.Imul:
226
                if (instruction.OpCount == 1)
×
227
                {
228
                    int opSize = instruction.Op0Kind == OpKind.Register ? instruction.Op0Register.GetSize() : instruction.MemorySize.GetSize();
×
229
                    switch (opSize) // TODO: I don't know how to work with dual registers here, I left hints though
230
                    {
231
                        case 1: // Op0 * AL -> AX
NEW
232
                            Add(instruction.IP, ISIL.OpCode.Multiply, Register.AX.MakeIndependent(), ConvertOperand(instruction, 0), Register.AL.MakeIndependent());
×
233
                            return;
×
234
                        case 2: // Op0 * AX -> DX:AX
235

236
                            break;
237
                        case 4: // Op0 * EAX -> EDX:EAX
238

239
                            break;
240
                        case 8: // Op0 * RAX -> RDX:RAX
241

242
                            break;
243
                        default: // prob 0, I think fallback to architecture alignment would be good here(issue: idk how to find out arch alignment)
244

245
                            break;
246
                    }
247

248
                    // if got to here, it didn't work
249
                    goto default;
250
                }
NEW
251
                else if (instruction.OpCount == 3) Add(instruction.IP, ISIL.OpCode.Multiply, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1), ConvertOperand(instruction, 2));
×
NEW
252
                else Add(instruction.IP, ISIL.OpCode.Multiply, ConvertOperand(instruction, 0), ConvertOperand(instruction, 0), ConvertOperand(instruction, 1));
×
253

254
                break;
×
255
            case Mnemonic.Mulss:
256
            case Mnemonic.Vmulss:
257
                if (instruction.OpCount == 3)
×
NEW
258
                    Add(instruction.IP, ISIL.OpCode.Multiply, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1), ConvertOperand(instruction, 2));
×
259
                else if (instruction.OpCount == 2)
×
NEW
260
                    Add(instruction.IP, ISIL.OpCode.Multiply, ConvertOperand(instruction, 0), ConvertOperand(instruction, 0), ConvertOperand(instruction, 1));
×
261
                else
262
                    goto default;
263

264
                break;
265

266
            case Mnemonic.Divss: // Divide Scalar Single Precision Floating-Point Values. DEST[31:0] = DEST[31:0] / SRC[31:0]
NEW
267
                Add(instruction.IP, ISIL.OpCode.Divide, ConvertOperand(instruction, 0), ConvertOperand(instruction, 0), ConvertOperand(instruction, 1));
×
268
                break;
×
269
            case Mnemonic.Vdivss: // VEX Divide Scalar Single Precision Floating-Point Values. DEST[31:0] = SRC1[31:0] / SRC2[31:0]
NEW
270
                Add(instruction.IP, ISIL.OpCode.Divide, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1), ConvertOperand(instruction, 2));
×
271
                break;
×
272

273
            case Mnemonic.Ret:
274
                // TODO: Verify correctness of operation with Vectors.
275

276
                // On x32, this will require better engineering since ulongs are handled somehow differently (return in 2 registers, I think?)
277
                // The x64 prototype should work.
278
                // Are st* registers even used in il2cpp games?
279

280
                if (context.IsVoid)
×
NEW
281
                    Add(instruction.IP, ISIL.OpCode.Return);
×
282
                else if (context.Definition?.RawReturnType?.Type is Il2CppTypeEnum.IL2CPP_TYPE_R4 or Il2CppTypeEnum.IL2CPP_TYPE_R8)
×
NEW
283
                    Add(instruction.IP, ISIL.OpCode.Return, new ISIL.Register(null, "xmm0"));
×
284
                else
NEW
285
                    Add(instruction.IP, ISIL.OpCode.Return, new ISIL.Register(null, "rax"));
×
286
                break;
×
287
            case Mnemonic.Push:
288
                operandSize = instruction.Op0Kind == OpKind.Register ? instruction.Op0Register.GetSize() : instruction.MemorySize.GetSize();
×
NEW
289
                Add(instruction.IP, ISIL.OpCode.ShiftStack, -operandSize);
×
NEW
290
                Add(instruction.IP, ISIL.OpCode.Move, new ISIL.StackOffset(0), ConvertOperand(instruction, 0));
×
UNCOV
291
                break;
×
292
            case Mnemonic.Pop:
293
                operandSize = instruction.Op0Kind == OpKind.Register ? instruction.Op0Register.GetSize() : instruction.MemorySize.GetSize();
×
NEW
294
                Add(instruction.IP, ISIL.OpCode.Move, ConvertOperand(instruction, 0), new ISIL.StackOffset(0));
×
NEW
295
                Add(instruction.IP, ISIL.OpCode.ShiftStack, operandSize);
×
UNCOV
296
                break;
×
297
            case Mnemonic.Sub:
298
            case Mnemonic.Add:
299
                var isSubtract = instruction.Mnemonic == Mnemonic.Sub;
×
300

301
                // Special case - stack shift
302
                if (instruction.Op0Register == Register.RSP && instruction.Op1Kind.IsImmediate())
×
303
                {
304
                    var amount = (int)instruction.GetImmediate(1);
×
NEW
305
                    Add(instruction.IP, ISIL.OpCode.ShiftStack, isSubtract ? -amount : amount);
×
306
                    break;
×
307
                }
308

309
                var left = ConvertOperand(instruction, 0);
×
310
                var right = ConvertOperand(instruction, 1);
×
311
                if (isSubtract)
×
NEW
312
                    Add(instruction.IP, ISIL.OpCode.Subtract, left, left, right);
×
313
                else
NEW
314
                    Add(instruction.IP, ISIL.OpCode.Add, left, left, right);
×
315

316
                break;
×
317
            case Mnemonic.Addss:
318
            case Mnemonic.Subss:
319
                {
320
                    // Addss and subss are just floating point add/sub, but we don't need to handle the stack stuff
321
                    // But we do need to handle 2 vs 3 operand forms
322
                    object dest;
323
                    object src1;
324
                    object src2;
325

NEW
326
                    if (instruction.OpCount == 3)
×
327
                    {
328
                        //dest, src1, src2
NEW
329
                        dest = ConvertOperand(instruction, 0);
×
NEW
330
                        src1 = ConvertOperand(instruction, 1);
×
NEW
331
                        src2 = ConvertOperand(instruction, 2);
×
332
                    }
NEW
333
                    else if (instruction.OpCount == 2)
×
334
                    {
335
                        //DestAndSrc1, Src2
NEW
336
                        dest = ConvertOperand(instruction, 0);
×
NEW
337
                        src1 = dest;
×
NEW
338
                        src2 = ConvertOperand(instruction, 1);
×
339
                    }
340
                    else
341
                        goto default;
342

NEW
343
                    if (instruction.Mnemonic == Mnemonic.Subss)
×
NEW
344
                        Add(instruction.IP, ISIL.OpCode.Subtract, dest, src1, src2);
×
345
                    else
NEW
346
                        Add(instruction.IP, ISIL.OpCode.Add, dest, src1, src2);
×
NEW
347
                    break;
×
348
                }
349
            // The following pair of instructions does not update the Carry Flag (CF):
350
            case Mnemonic.Dec:
NEW
351
                Add(instruction.IP, ISIL.OpCode.Subtract, ConvertOperand(instruction, 0), ConvertOperand(instruction, 0), 1);
×
352
                break;
×
353
            case Mnemonic.Inc:
NEW
354
                Add(instruction.IP, ISIL.OpCode.Add, ConvertOperand(instruction, 0), ConvertOperand(instruction, 0), 1);
×
355
                break;
×
356

357
            case Mnemonic.Shufps: // Packed Interleave Shuffle of Quadruplets of Single Precision Floating-Point Values
358
                {
NEW
359
                    if (instruction.Op1Kind == OpKind.Memory)
×
360
                        goto default;
361

NEW
362
                    var imm = instruction.Immediate8;
×
NEW
363
                    var src1 = X86Utils.GetRegisterName(instruction.Op0Register);
×
NEW
364
                    var src2 = X86Utils.GetRegisterName(instruction.Op1Register);
×
365

366
                    // Element selection
NEW
367
                    Add(instruction.IP, ISIL.OpCode.Move,
×
NEW
368
                        new ISIL.Register(null, "XMM_TEMP" + "_0"),
×
NEW
369
                        new ISIL.Register(null, $"{src1}_{imm & 0b11}"));
×
370

NEW
371
                    Add(instruction.IP, ISIL.OpCode.Move,
×
NEW
372
                        new ISIL.Register(null, "XMM_TEMP" + "_1"),
×
NEW
373
                        new ISIL.Register(null, $"{src1}_{(imm >> 2) & 0b11}"));
×
374

NEW
375
                    Add(instruction.IP, ISIL.OpCode.Move,
×
NEW
376
                        new ISIL.Register(null, "XMM_TEMP" + "_2"),
×
NEW
377
                        new ISIL.Register(null, $"{src2}_{(imm >> 4) & 0b11}"));
×
378

NEW
379
                    Add(instruction.IP, ISIL.OpCode.Move,
×
NEW
380
                        new ISIL.Register(null, "XMM_TEMP" + "_3"),
×
NEW
381
                        new ISIL.Register(null, $"{src2}_{(imm >> 6) & 0b11}"));
×
382

NEW
383
                    Add(instruction.IP, ISIL.OpCode.Move,
×
NEW
384
                        ConvertOperand(instruction, 0),
×
NEW
385
                        new ISIL.Register(null, "XMM_TEMP"));
×
386

NEW
387
                    break;
×
388
                }
389

390
            case Mnemonic.Unpcklps: // Unpack and Interleave Low Packed Single Precision Floating-Point Values
391
                {
NEW
392
                    if (instruction.Op1Kind == OpKind.Memory)
×
393
                        goto default;
394

NEW
395
                    var src1 = X86Utils.GetRegisterName(instruction.Op0Register);
×
NEW
396
                    var src2 = X86Utils.GetRegisterName(instruction.Op1Register);
×
397

398
                    // Interleaving lanes
NEW
399
                    Add(instruction.IP, ISIL.OpCode.Move,
×
NEW
400
                        new ISIL.Register(null, (string?)"XMM_TEMP" + "_0"),
×
NEW
401
                        new ISIL.Register(null, $"{src1}_0")); // SRC1[31:0]
×
402

NEW
403
                    Add(instruction.IP, ISIL.OpCode.Move,
×
NEW
404
                        new ISIL.Register(null, (string?)"XMM_TEMP" + "_1"),
×
NEW
405
                        new ISIL.Register(null, $"{src2}_0")); // SRC2[31:0]
×
406

NEW
407
                    Add(instruction.IP, ISIL.OpCode.Move,
×
NEW
408
                        new ISIL.Register(null, (string?)"XMM_TEMP" + "_2"),
×
NEW
409
                        new ISIL.Register(null, $"{src1}_1")); // SRC1[63:32]
×
410

NEW
411
                    Add(instruction.IP, ISIL.OpCode.Move,
×
NEW
412
                        new ISIL.Register(null, (string?)"XMM_TEMP" + "_3"),
×
NEW
413
                        new ISIL.Register(null, $"{src2}_1")); // SRC2[63:32]
×
414

NEW
415
                    Add(instruction.IP, ISIL.OpCode.Move,
×
NEW
416
                        ConvertOperand(instruction, 0),
×
NEW
417
                        new ISIL.Register(null, (string?)"XMM_TEMP"));
×
418

NEW
419
                    break;
×
420
                }
421

422
            case Mnemonic.Call:
423
                // We don't try and resolve which method is being called, but we do need to know how many parameters it has
424
                // I would hope that all of these methods have the same number of arguments, else how can they be inlined?
425

426
                var target = instruction.NearBranchTarget;
×
427

NEW
428
                if (instruction.Op0Kind == OpKind.Register || instruction.Op0Kind == OpKind.Memory)
×
429
                {
NEW
430
                    Add(instruction.IP, ISIL.OpCode.IndirectCall, ConvertOperand(instruction, 0));
×
431
                }
432
                else if (context.AppContext.MethodsByAddress.TryGetValue(target, out var possibleMethods))
×
433
                {
434
                    if (possibleMethods.Count == 1)
×
435
                    {
436
                        ISIL.Instruction call;
437

NEW
438
                        if (possibleMethods[0].IsVoid)
×
NEW
439
                            call = Add(instruction.IP, ISIL.OpCode.CallVoid, target);
×
440
                        else
NEW
441
                            call = Add(instruction.IP, ISIL.OpCode.Call, target, new ISIL.Register(null, "eax") /* return value */);
×
442

NEW
443
                        call.Operands.AddRange(X64CallingConventionResolver.ResolveForManaged(possibleMethods[0]));
×
444
                    }
445
                    else
446
                    {
447
                        MethodAnalysisContext ctx = null!;
×
448
                        var lpars = -1;
×
449

450
                        // Very naive approach, folds with structs in parameters if GCC is used:
451
                        foreach (var method in possibleMethods)
×
452
                        {
453
                            var pars = method.Parameters.Count;
×
454
                            if (method.IsStatic) pars++;
×
455
                            if (pars > lpars)
×
456
                            {
457
                                lpars = pars;
×
458
                                ctx = method;
×
459
                            }
460
                        }
461

462
                        // On post-analysis, you can discard methods according to the registers used, see X64CallingConventionResolver.
463
                        // This is less effective on GCC because MSVC doesn't overlap registers.
464

465
                        ISIL.Instruction call;
466

NEW
467
                        if (ctx.IsVoid)
×
NEW
468
                            call = Add(instruction.IP, ISIL.OpCode.CallVoid, target);
×
469
                        else
NEW
470
                            call = Add(instruction.IP, ISIL.OpCode.Call, target, new ISIL.Register(null, "eax") /* return value */);
×
471

NEW
472
                        call.Operands.AddRange(X64CallingConventionResolver.ResolveForManaged(ctx));
×
473
                    }
474
                }
475
                else
476
                {
477
                    // This isn't a managed method, so for now we don't know its parameter count.
478
                    // This will need to be rewritten if we ever stumble upon an unmanaged method that accepts more than 4 parameters.
479
                    // These can be converted to dedicated ISIL instructions for specific API functions at a later stage. (by a post-processing step)
480

NEW
481
                    var call = Add(instruction.IP, ISIL.OpCode.Call, target, new ISIL.Register(null, "eax") /* return value */);
×
NEW
482
                    call.Operands.AddRange(X64CallingConventionResolver.ResolveForUnmanaged(context.AppContext, target));
×
483
                }
484

485
                if (callNoReturn)
×
486
                {
487
                    // Our function decided to jump into a thunk or do a funny return.
488
                    // We will insert a return after the call.
489
                    // According to common sense, such callee must have the same return value as the caller, unless it's __noreturn.
490
                    // I hope someone else will catch up on this and figure out non-returning functions.
491

492
                    // TODO: Determine whether a function is an actual thunk and it's *technically better* to duplicate code for it, or if it's a regular retcall.
493
                    // Basic implementation may use context.AppContext.MethodsByAddress, but this doesn't catch thunks only.
494
                    // For example, SWDT often calls gc::GarbageCollector::SetWriteBarrier through a long jmp chain. That's a whole function, not just a thunk.
495

496
                    goto case Mnemonic.Ret;
×
497
                }
498

499
                break;
500
            case Mnemonic.Test:
501
                if (instruction.Op0Kind == OpKind.Register && instruction.Op1Kind == OpKind.Register && instruction.Op0Register == instruction.Op1Register)
×
502
                {
NEW
503
                    AddCompareInstruction(instruction.IP, ConvertOperand(instruction, 0), 0);
×
504
                    break;
×
505
                }
506

507
                //Fall through to cmp, as test is just a cmp that doesn't set flags
508
                goto case Mnemonic.Cmp;
509
            case Mnemonic.Cmp:
510
            case Mnemonic.Comiss: //comiss is just a floating point compare dest[31:0] == src[31:0]
511
            case Mnemonic.Ucomiss: // same, but unsigned
NEW
512
                AddCompareInstruction(instruction.IP, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1));
×
513
                break;
×
514

515
            case Mnemonic.Cmove: // move if condition
516
            case Mnemonic.Cmovne:
517
            case Mnemonic.Cmova:
518
            case Mnemonic.Cmovg:
519
            case Mnemonic.Cmovae:
520
            case Mnemonic.Cmovge:
521
            case Mnemonic.Cmovb:
522
            case Mnemonic.Cmovl:
523
            case Mnemonic.Cmovbe:
524
            case Mnemonic.Cmovle:
525
            case Mnemonic.Cmovs:
526
            case Mnemonic.Cmovns:
UNCOV
527
                switch (instruction.Mnemonic)
×
528
                {
529
                    case Mnemonic.Cmove: // equals
NEW
530
                        Add(instruction.IP, ISIL.OpCode.Not, new ISIL.Register(null, "TEMP"), new ISIL.Register(null, "ZF")); // TEMP = !ZF
×
NEW
531
                        Add(instruction.IP, ISIL.OpCode.ConditionalJump, instruction.IP + 1, new ISIL.Register(null, "TEMP")); // skip if not eq
×
UNCOV
532
                        break;
×
533
                    case Mnemonic.Cmovne: // not equals
NEW
534
                        Add(instruction.IP, ISIL.OpCode.ConditionalJump, instruction.IP + 1, new ISIL.Register(null, "ZF")); // skip if eq
×
535
                        break;
×
536
                    case Mnemonic.Cmovs: // sign
NEW
537
                        Add(instruction.IP, ISIL.OpCode.Not, new ISIL.Register(null, "TEMP"), new ISIL.Register(null, "SF")); // TEMP = !SF
×
NEW
538
                        Add(instruction.IP, ISIL.OpCode.ConditionalJump, instruction.IP + 1, new ISIL.Register(null, "TEMP")); // skip if not sign
×
UNCOV
539
                        break;
×
540
                    case Mnemonic.Cmovns: // not sign
NEW
541
                        Add(instruction.IP, ISIL.OpCode.ConditionalJump, instruction.IP + 1, new ISIL.Register(null, "SF")); // skip if sign
×
542
                        break;
×
543
                    case Mnemonic.Cmova:
544
                    case Mnemonic.Cmovg: // greater
NEW
545
                        var temp = new ISIL.Register(null, "TEMP");
×
NEW
546
                        Add(instruction.IP, ISIL.OpCode.CheckEqual, temp, new ISIL.Register(null, "SF"), new ISIL.Register(null, "OF")); // TEMP = SF == OF
×
NEW
547
                        Add(instruction.IP, ISIL.OpCode.Not, temp, temp); // TEMP = !TEMP
×
NEW
548
                        Add(instruction.IP, ISIL.OpCode.Or, temp, temp, new ISIL.Register(null, "ZF")); // TEMP = TEMP || ZF
×
NEW
549
                        Add(instruction.IP, ISIL.OpCode.ConditionalJump, instruction.IP + 1, temp); // skip if not gt
×
UNCOV
550
                        break;
×
551
                    case Mnemonic.Cmovae:
552
                    case Mnemonic.Cmovge: // greater or eq
NEW
553
                        temp = new ISIL.Register(null, "TEMP");
×
NEW
554
                        Add(instruction.IP, ISIL.OpCode.CheckEqual, temp, new ISIL.Register(null, "SF"), new ISIL.Register(null, "OF")); // TEMP = SF == OF
×
NEW
555
                        Add(instruction.IP, ISIL.OpCode.Not, temp, temp); // TEMP = !TEMP
×
NEW
556
                        Add(instruction.IP, ISIL.OpCode.ConditionalJump, instruction.IP + 1, temp); // skip if not gt or eq
×
UNCOV
557
                        break;
×
558
                    case Mnemonic.Cmovb:
559
                    case Mnemonic.Cmovl: // less
NEW
560
                        temp = new ISIL.Register(null, "TEMP");
×
NEW
561
                        Add(instruction.IP, ISIL.OpCode.CheckEqual, temp, new ISIL.Register(null, "SF"), new ISIL.Register(null, "OF")); // TEMP = SF == OF
×
NEW
562
                        Add(instruction.IP, ISIL.OpCode.ConditionalJump, instruction.IP + 1, temp); // skip if not lt
×
UNCOV
563
                        break;
×
564
                    case Mnemonic.Cmovbe:
565
                    case Mnemonic.Cmovle: // less or eq
NEW
566
                        temp = new ISIL.Register(null, "TEMP");
×
NEW
567
                        var temp2 = new ISIL.Register(null, "TEMP2");
×
NEW
568
                        Add(instruction.IP, ISIL.OpCode.CheckEqual, temp, new ISIL.Register(null, "SF"), new ISIL.Register(null, "OF")); // TEMP = SF == OF
×
NEW
569
                        Add(instruction.IP, ISIL.OpCode.Not, temp2, new ISIL.Register(null, "ZF")); // TEMP2 = !ZF
×
NEW
570
                        Add(instruction.IP, ISIL.OpCode.And, temp, temp, temp2); // TEMP = TEMP && TEMP2
×
NEW
571
                        Add(instruction.IP, ISIL.OpCode.ConditionalJump, instruction.IP + 1, temp); // skip if not lt or eq
×
572
                        break;
573
                }
NEW
574
                Add(instruction.IP, ISIL.OpCode.Move, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); // set if cond
×
NEW
575
                Add(instruction.IP + 1, ISIL.OpCode.Nop);
×
UNCOV
576
                break;
×
577

578
            case Mnemonic.Maxss: // dest < src ? src : dest
579
            case Mnemonic.Minss: // dest > src ? src : dest
580
                {
NEW
581
                    var dest = ConvertOperand(instruction, 0);
×
NEW
582
                    var src = ConvertOperand(instruction, 1);
×
NEW
583
                    AddCompareInstruction(instruction.IP, dest, src); // compare dest & src
×
NEW
584
                    if (instruction.Mnemonic == Mnemonic.Maxss)
×
585
                    {
NEW
586
                        var temp = new ISIL.Register(null, "TEMP");
×
NEW
587
                        Add(instruction.IP, ISIL.OpCode.CheckEqual, temp, new ISIL.Register(null, "SF"), new ISIL.Register(null, "OF")); // TEMP = SF == OF
×
NEW
588
                        Add(instruction.IP, ISIL.OpCode.ConditionalJump, instruction.IP + 1, temp); // enter if dest < src
×
589
                    }
590
                    else
591
                    {
NEW
592
                        var temp = new ISIL.Register(null, "TEMP");
×
NEW
593
                        Add(instruction.IP, ISIL.OpCode.CheckEqual, temp, new ISIL.Register(null, "SF"), new ISIL.Register(null, "OF")); // TEMP = SF == OF
×
NEW
594
                        Add(instruction.IP, ISIL.OpCode.Not, temp, temp); // TEMP = !TEMP
×
NEW
595
                        Add(instruction.IP, ISIL.OpCode.Or, temp, temp, new ISIL.Register(null, "ZF")); // TEMP = TEMP || ZF
×
NEW
596
                        Add(instruction.IP, ISIL.OpCode.ConditionalJump, instruction.IP + 1, temp); // enter if dest > src
×
597
                    }
598

NEW
599
                    Add(instruction.IP, ISIL.OpCode.Move, dest, src); // dest = src
×
NEW
600
                    Add(instruction.IP + 1, ISIL.OpCode.Nop); // exit for IF
×
NEW
601
                    break;
×
602
                }
603

604
            case Mnemonic.Cmpxchg: // compare and exchange
605
                {
NEW
606
                    var accumulator = new ISIL.Register(null, instruction.Op1Register.GetSize() switch
×
NEW
607
                    {
×
NEW
608
                        8 => X86Utils.GetRegisterName(Register.RAX),
×
NEW
609
                        4 => X86Utils.GetRegisterName(Register.EAX),
×
NEW
610
                        2 => X86Utils.GetRegisterName(Register.AX),
×
NEW
611
                        1 => X86Utils.GetRegisterName(Register.AL),
×
NEW
612
                        _ => throw new NotSupportedException("unexpected behavior")
×
NEW
613
                    });
×
NEW
614
                    var dest = ConvertOperand(instruction, 0);
×
NEW
615
                    var src = ConvertOperand(instruction, 1);
×
NEW
616
                    AddCompareInstruction(instruction.IP, accumulator, dest); // compare dest & accumulator
×
NEW
617
                    Add(instruction.IP, ISIL.OpCode.Not, new ISIL.Register(null, "TEMP"), new ISIL.Register(null, "ZF")); // TEMP = !ZF
×
NEW
618
                    Add(instruction.IP, ISIL.OpCode.ConditionalJump, instruction.IP + 1, new ISIL.Register(null, "TEMP")); // if accumulator == dest
×
619
                                                                                                                           // SET ZF = 1
NEW
620
                    Add(instruction.IP, ISIL.OpCode.Move, dest, src); // DEST = SRC
×
NEW
621
                    Add(instruction.IP, ISIL.OpCode.Jump, instruction.IP + 2); // END IF
×
622
                                                                               // ELSE
623
                                                                               // SET ZF = 0
NEW
624
                    Add(instruction.IP + 1, ISIL.OpCode.Move, accumulator, dest); // accumulator = dest
×
625

NEW
626
                    Add(instruction.IP + 2, ISIL.OpCode.Nop); // exit for IF
×
NEW
627
                    break;
×
628
                }
629

630
            case Mnemonic.Jmp:
631
                if (instruction.Op0Kind != OpKind.Register)
×
632
                {
633
                    var jumpTarget = instruction.NearBranchTarget;
×
634

635
                    var methodEnd = instruction.IP + (ulong)context.RawBytes.Length;
×
636
                    var methodStart = context.UnderlyingPointer;
×
637

638
                    if (jumpTarget < methodStart || jumpTarget > methodEnd)
×
639
                    {
640
                        callNoReturn = true;
×
641
                        goto case Mnemonic.Call;
×
642
                    }
643
                    else
644
                    {
NEW
645
                        Add(instruction.IP, ISIL.OpCode.Jump, jumpTarget);
×
646
                        break;
×
647
                    }
648
                }
649
                if (instruction.Op0Kind == OpKind.Register) // ex: jmp rax
×
650
                {
NEW
651
                    Add(instruction.IP, ISIL.OpCode.IndirectCall, ConvertOperand(instruction, 0));
×
652
                    break;
×
653
                }
654

655
                goto default;
656
            case Mnemonic.Je:
657
                if (instruction.Op0Kind != OpKind.Register)
×
658
                {
659
                    var jumpTarget = instruction.NearBranchTarget;
×
660

NEW
661
                    Add(instruction.IP, ISIL.OpCode.ConditionalJump, jumpTarget, new ISIL.Register(null, "ZF")); // if ZF == 1
×
662
                    break;
×
663
                }
664

665
                goto default;
666
            case Mnemonic.Jne:
667
                if (instruction.Op0Kind != OpKind.Register)
×
668
                {
669
                    var jumpTarget = instruction.NearBranchTarget;
×
670

NEW
671
                    Add(instruction.IP, ISIL.OpCode.Not, new ISIL.Register(null, "TEMP"), new ISIL.Register(null, "ZF")); // TEMP = !ZF
×
NEW
672
                    Add(instruction.IP, ISIL.OpCode.ConditionalJump, jumpTarget, new ISIL.Register(null, "TEMP"));
×
UNCOV
673
                    break;
×
674
                }
675
                goto default;
676
            case Mnemonic.Js:
677
                if (instruction.Op0Kind != OpKind.Register)
×
678
                {
679
                    var jumpTarget = instruction.NearBranchTarget;
×
680

NEW
681
                    Add(instruction.IP, ISIL.OpCode.ConditionalJump, jumpTarget, new ISIL.Register(null, "SF")); // if SF == 1
×
682
                    break;
×
683
                }
684

685
                goto default;
686
            case Mnemonic.Jns:
687
                if (instruction.Op0Kind != OpKind.Register)
×
688
                {
689
                    var jumpTarget = instruction.NearBranchTarget;
×
690

NEW
691
                    Add(instruction.IP, ISIL.OpCode.Not, new ISIL.Register(null, "TEMP"), new ISIL.Register(null, "SF")); // TEMP = !SF
×
NEW
692
                    Add(instruction.IP, ISIL.OpCode.ConditionalJump, jumpTarget, new ISIL.Register(null, "TEMP"));
×
UNCOV
693
                    break;
×
694
                }
695

696
                goto default;
697
            case Mnemonic.Jg:
698
            case Mnemonic.Ja:
699
                if (instruction.Op0Kind != OpKind.Register)
×
700
                {
701
                    var jumpTarget = instruction.NearBranchTarget;
×
NEW
702
                    var temp = new ISIL.Register(null, "TEMP");
×
NEW
703
                    var temp2 = new ISIL.Register(null, "TEMP2");
×
704

NEW
705
                    Add(instruction.IP, ISIL.OpCode.CheckEqual, temp, new ISIL.Register(null, "SF"), new ISIL.Register(null, "OF")); // TEMP = SF == OF
×
NEW
706
                    Add(instruction.IP, ISIL.OpCode.Not, temp2, new ISIL.Register(null, "ZF")); // TEMP2 = !ZF
×
NEW
707
                    Add(instruction.IP, ISIL.OpCode.And, temp, temp, temp2); // TEMP = TEMP && TEMP2
×
NEW
708
                    Add(instruction.IP, ISIL.OpCode.ConditionalJump, jumpTarget, temp);
×
UNCOV
709
                    break;
×
710
                }
711

712
                goto default;
713
            case Mnemonic.Jl:
714
            case Mnemonic.Jb:
715
                if (instruction.Op0Kind != OpKind.Register)
×
716
                {
717
                    var jumpTarget = instruction.NearBranchTarget;
×
NEW
718
                    var temp = new ISIL.Register(null, "TEMP");
×
719

NEW
720
                    Add(instruction.IP, ISIL.OpCode.CheckEqual, temp, new ISIL.Register(null, "SF"), new ISIL.Register(null, "OF")); // TEMP = SF == OF
×
NEW
721
                    Add(instruction.IP, ISIL.OpCode.Not, temp, temp); // TEMP = !TEMP
×
NEW
722
                    Add(instruction.IP, ISIL.OpCode.ConditionalJump, jumpTarget, temp);
×
UNCOV
723
                    break;
×
724
                }
725

726
                goto default;
727
            case Mnemonic.Jge:
728
            case Mnemonic.Jae:
729
                if (instruction.Op0Kind != OpKind.Register)
×
730
                {
731
                    var jumpTarget = instruction.NearBranchTarget;
×
NEW
732
                    var temp = new ISIL.Register(null, "TEMP");
×
733

NEW
734
                    Add(instruction.IP, ISIL.OpCode.CheckEqual, temp, new ISIL.Register(null, "SF"), new ISIL.Register(null, "OF")); // TEMP = SF == OF
×
NEW
735
                    Add(instruction.IP, ISIL.OpCode.ConditionalJump, jumpTarget, temp);
×
UNCOV
736
                    break;
×
737
                }
738

739
                goto default;
740
            case Mnemonic.Jle:
741
            case Mnemonic.Jbe:
742
                if (instruction.Op0Kind != OpKind.Register)
×
743
                {
744
                    var jumpTarget = instruction.NearBranchTarget;
×
NEW
745
                    var temp = new ISIL.Register(null, "TEMP");
×
746

NEW
747
                    Add(instruction.IP, ISIL.OpCode.CheckEqual, temp, new ISIL.Register(null, "SF"), new ISIL.Register(null, "OF")); // TEMP = SF == OF
×
NEW
748
                    Add(instruction.IP, ISIL.OpCode.Not, temp, temp); // TEMP = !TEMP
×
NEW
749
                    Add(instruction.IP, ISIL.OpCode.Or, temp, temp, new ISIL.Register(null, "ZF")); // TEMP = TEMP || ZF
×
NEW
750
                    Add(instruction.IP, ISIL.OpCode.ConditionalJump, jumpTarget, temp);
×
UNCOV
751
                    break;
×
752
                }
753

754
                goto default;
755
            case Mnemonic.Xchg:
NEW
756
                Add(instruction.IP, ISIL.OpCode.Move, new ISIL.Register(null, "TEMP"), ConvertOperand(instruction, 0)); // TEMP = op0
×
NEW
757
                Add(instruction.IP, ISIL.OpCode.Move, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1)); // op0 = op1
×
NEW
758
                Add(instruction.IP, ISIL.OpCode.Move, ConvertOperand(instruction, 1), new ISIL.Register(null, "TEMP")); // op1 = TEMP
×
UNCOV
759
                break;
×
760
            case Mnemonic.Int:
761
            case Mnemonic.Int3:
NEW
762
                Add(instruction.IP, ISIL.OpCode.Interrupt); // 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
×
763
                break;
×
764
            case Mnemonic.Prefetchw: // Fetches the cache line containing the specified byte from memory to the 1st or 2nd level cache, invalidating other cached copies.
765
            case Mnemonic.Nop:
766
                // 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.
767
                // So we'll emit an ISIL nop for it.
NEW
768
                Add(instruction.IP, ISIL.OpCode.Nop);
×
769
                break;
×
770
            default:
NEW
771
                Add(instruction.IP, ISIL.OpCode.NotImplemented, FormatInstruction(instruction));
×
772
                break;
773
        }
774

775
        void AddCompareInstruction(ulong ip, object op0, object op1)
776
        {
NEW
777
            var temp1 = new ISIL.Register(null, "TEMP1");
×
NEW
778
            var temp2 = new ISIL.Register(null, "TEMP2");
×
NEW
779
            var temp3 = new ISIL.Register(null, "TEMP3");
×
NEW
780
            var temp4 = new ISIL.Register(null, "TEMP4");
×
NEW
781
            var temp5 = new ISIL.Register(null, "TEMP5");
×
782

NEW
783
            Add(ip, ISIL.OpCode.CheckLess, new ISIL.Register(null, "CF"), op0, op1); // CF = op1 < op2
×
NEW
784
            Add(ip, ISIL.OpCode.Subtract, temp1, op0, op1); // temp1 = op1 - op2
×
NEW
785
            Add(ip, ISIL.OpCode.Xor, temp2, op0, op1); // temp2 = op1 ^ op2
×
NEW
786
            Add(ip, ISIL.OpCode.Xor, temp3, op0, temp1); // temp3 = op1 ^ temp1
×
NEW
787
            Add(ip, ISIL.OpCode.And, temp4, temp2, temp3); // temp4 = temp2 & temp3
×
NEW
788
            Add(ip, ISIL.OpCode.CheckLess, new ISIL.Register(null, "OF"), temp4, 0); // OF = temp4 < 0
×
NEW
789
            Add(ip, ISIL.OpCode.CheckLess, new ISIL.Register(null, "SF"), temp1, 0); // SF = temp1 < 0
×
NEW
790
            Add(ip, ISIL.OpCode.CheckEqual, new ISIL.Register(null, "ZF"), temp1, 0); // ZF = temp1 == 0
×
NEW
791
            Add(ip, ISIL.OpCode.And, temp5, temp2, 1); // temp5 = tmp2 & 1
×
NEW
792
            Add(ip, ISIL.OpCode.CheckEqual, new ISIL.Register(null, "PF"), temp5, 0); // PF = temp5 == 0
×
NEW
793
        }
×
UNCOV
794
    }
×
795

796

797
    private object ConvertOperand(Instruction instruction, int operand, bool isLeaAddress = false)
798
    {
799
        var kind = instruction.GetOpKind(operand);
×
800

801
        if (kind == OpKind.Register)
×
NEW
802
            return new ISIL.Register(null, X86Utils.GetRegisterName(instruction.GetOpRegister(operand)));
×
803
        if (kind.IsImmediate())
×
NEW
804
            return instruction.GetImmediate(operand);
×
805
        if (kind == OpKind.Memory && instruction.MemoryBase == Register.RSP)
×
NEW
806
            return new ISIL.StackOffset((int)instruction.MemoryDisplacement32);
×
807

808
        //Memory
809
        //Most complex to least complex
810

811
        if (instruction.IsIPRelativeMemoryOperand)
×
NEW
812
            return new ISIL.MemoryOperand(addend: (long)instruction.IPRelativeMemoryAddress);
×
813

814
        //All four components
815
        if (instruction.MemoryIndex != Register.None && instruction.MemoryBase != Register.None && instruction.MemoryDisplacement64 != 0)
×
816
        {
NEW
817
            var mBase = new ISIL.Register(null, X86Utils.GetRegisterName(instruction.MemoryBase));
×
NEW
818
            var mIndex = new ISIL.Register(null, X86Utils.GetRegisterName(instruction.MemoryIndex));
×
NEW
819
            return new ISIL.MemoryOperand(mBase, mIndex, instruction.MemoryDisplacement32, instruction.MemoryIndexScale);
×
820
        }
821

822
        //No addend
823
        if (instruction.MemoryIndex != Register.None && instruction.MemoryBase != Register.None)
×
824
        {
NEW
825
            var mBase = new ISIL.Register(null, X86Utils.GetRegisterName(instruction.MemoryBase));
×
NEW
826
            var mIndex = new ISIL.Register(null, X86Utils.GetRegisterName(instruction.MemoryIndex));
×
NEW
827
            return new ISIL.MemoryOperand(mBase, mIndex, instruction.MemoryIndexScale);
×
828
        }
829

830
        //No base
NEW
831
        if (instruction.MemoryIndex != Register.None && instruction.MemoryDisplacement64 != 0)
×
832
        {
NEW
833
            var mIndex = new ISIL.Register(null, X86Utils.GetRegisterName(instruction.MemoryIndex));
×
NEW
834
            return new ISIL.MemoryOperand(null, mIndex, instruction.MemoryDisplacement32, instruction.MemoryIndexScale);
×
835
        }
836

837
        //No index (and so no scale)
838
        if (instruction.MemoryBase != Register.None && instruction.MemoryDisplacement64 > 0)
×
839
        {
NEW
840
            var mBase = new ISIL.Register(null, X86Utils.GetRegisterName(instruction.MemoryBase));
×
NEW
841
            return new ISIL.MemoryOperand(mBase, addend: (long)instruction.MemoryDisplacement64);
×
842
        }
843

844
        //Only base
845
        if (instruction.MemoryBase != Register.None)
×
846
        {
NEW
847
            return new ISIL.MemoryOperand(new ISIL.Register(null, X86Utils.GetRegisterName(instruction.MemoryBase)));
×
848
        }
849

850
        //Only addend
NEW
851
        return new ISIL.MemoryOperand(addend: (long)instruction.MemoryDisplacement64);
×
852
    }
853
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc