Skip to content

Commit

Permalink
Add Arm64 field writes, post-processors.
Browse files Browse the repository at this point in the history
  • Loading branch information
Sam Byass committed Sep 17, 2021
1 parent a4fe785 commit dc046b9
Show file tree
Hide file tree
Showing 13 changed files with 210 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@ public Arm64FieldReadToRegAction(MethodAnalysis<Arm64Instruction> context, Arm64

if(FieldRead == null)
return;

RegisterUsedLocal(ReadFrom);

LocalWritten = context.MakeLocal(FieldRead.GetFinalType()!, reg: destReg);

RegisterUsedLocal(LocalWritten);
}
}
}
36 changes: 36 additions & 0 deletions Cpp2IL.Core/Analysis/Actions/ARM64/Arm64ImmediateToFieldAction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using Cpp2IL.Core.Analysis.Actions.Base;
using Cpp2IL.Core.Analysis.ResultModels;
using Gee.External.Capstone.Arm64;
using Mono.Cecil.Cil;

namespace Cpp2IL.Core.Analysis.Actions.ARM64
{
public class Arm64ImmediateToFieldAction : AbstractFieldWriteAction<Arm64Instruction>
{
private long _immValue;

public Arm64ImmediateToFieldAction(MethodAnalysis<Arm64Instruction> context, Arm64Instruction instruction) : base(context, instruction)
{
var memReg = Utils.GetRegisterNameNew(instruction.MemoryBase()!.Id);
InstanceBeingSetOn = context.GetLocalInReg(memReg);

_immValue = instruction.Details.Operands[0].Immediate;

if(InstanceBeingSetOn?.Type == null)
return;

RegisterUsedLocal(InstanceBeingSetOn);

FieldWritten = FieldUtils.GetFieldBeingAccessed(InstanceBeingSetOn.Type, (ulong)instruction.MemoryOffset(), false);
}

protected override string? GetValueSummary() => _immValue.ToString();

protected override string? GetValuePseudocode() => _immValue.ToString();

protected override Instruction[] GetIlToLoadValue(MethodAnalysis<Arm64Instruction> context, ILProcessor processor) => new[]
{
processor.Create(OpCodes.Ldc_I4, (int) _immValue),
};
}
}
2 changes: 2 additions & 0 deletions Cpp2IL.Core/Analysis/Actions/ARM64/Arm64NewObjectAction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ public Arm64NewObjectAction(MethodAnalysis<Arm64Instruction> context, Arm64Instr
return;

LocalReturned = context.MakeLocal(TypeCreated, reg: "x0");

RegisterUsedLocal(LocalReturned);
}
}
}
48 changes: 48 additions & 0 deletions Cpp2IL.Core/Analysis/Actions/ARM64/Arm64OrZeroAndImmAction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System;
using Cpp2IL.Core.Analysis.Actions.Base;
using Cpp2IL.Core.Analysis.ResultModels;
using Gee.External.Capstone.Arm64;
using Mono.Cecil.Cil;

namespace Cpp2IL.Core.Analysis.Actions.ARM64
{
public class Arm64OrZeroAndImmAction : BaseAction<Arm64Instruction>
{
private readonly string _destReg;
private readonly long _immValue;
private readonly LocalDefinition _localMade;

public Arm64OrZeroAndImmAction(MethodAnalysis<Arm64Instruction> context, Arm64Instruction instruction) : base(context, instruction)
{
_destReg = Utils.GetRegisterNameNew(instruction.Details.Operands[0].Register.Id);
_immValue = instruction.Details.Operands[2].Immediate;

_localMade = context.MakeLocal(Utils.Int64Reference, reg: _destReg, knownInitialValue: _immValue);
RegisterDefinedLocalWithoutSideEffects(_localMade);
}

public override Instruction[] ToILInstructions(MethodAnalysis<Arm64Instruction> context, ILProcessor processor)
{
if (_localMade.Variable == null)
return Array.Empty<Instruction>();

return new[]
{
processor.Create(OpCodes.Ldc_I4, (int) _immValue),
processor.Create(OpCodes.Stloc, _localMade.Variable)
};
}

public override string? ToPsuedoCode()
{
return $"{_localMade.Type} {_localMade.Name} = {_immValue}";
}

public override string ToTextSummary()
{
return $"Creates new local {_localMade} in {_destReg} by ORing 0 with {_immValue}";
}

public override bool IsImportant() => true;
}
}
38 changes: 38 additions & 0 deletions Cpp2IL.Core/Analysis/Actions/ARM64/Arm64RegisterToFieldAction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System;
using Cpp2IL.Core.Analysis.Actions.Base;
using Cpp2IL.Core.Analysis.ResultModels;
using Gee.External.Capstone.Arm64;
using Mono.Cecil.Cil;

namespace Cpp2IL.Core.Analysis.Actions.ARM64
{
public class Arm64RegisterToFieldAction : AbstractFieldWriteAction<Arm64Instruction>
{
private IAnalysedOperand? _sourceOperand;

public Arm64RegisterToFieldAction(MethodAnalysis<Arm64Instruction> context, Arm64Instruction instruction) : base(context, instruction)
{
var memReg = Utils.GetRegisterNameNew(instruction.MemoryBase()!.Id);
InstanceBeingSetOn = context.GetLocalInReg(memReg);

var sourceReg = Utils.GetRegisterNameNew(instruction.Details.Operands[0].Register.Id);
_sourceOperand = context.GetOperandInRegister(sourceReg);

if(InstanceBeingSetOn?.Type == null)
return;

RegisterUsedLocal(InstanceBeingSetOn);

if(_sourceOperand is LocalDefinition l)
RegisterUsedLocal(l);

FieldWritten = FieldUtils.GetFieldBeingAccessed(InstanceBeingSetOn.Type, (ulong)instruction.MemoryOffset(), sourceReg[0] == 'v');
}

protected override string? GetValueSummary() => _sourceOperand?.ToString();

protected override string? GetValuePseudocode() => _sourceOperand?.GetPseudocodeRepresentation();

protected override Instruction[] GetIlToLoadValue(MethodAnalysis<Arm64Instruction> context, ILProcessor processor) => _sourceOperand?.GetILToLoad(context, processor) ?? Array.Empty<Instruction>();
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Cpp2IL.Core.Analysis.Actions.Base;
using System;
using Cpp2IL.Core.Analysis.Actions.Base;
using Cpp2IL.Core.Analysis.ResultModels;
using Gee.External.Capstone.Arm64;
using Mono.Cecil.Cil;
Expand All @@ -14,13 +15,18 @@ public Arm64ZeroRegisterToRegisterAction(MethodAnalysis<Arm64Instruction> contex
{
_destReg = Utils.GetRegisterNameNew(instruction.Details.Operands[0].Register.Id);
_localMade = context.MakeLocal(Utils.Int64Reference, reg: _destReg, knownInitialValue: 0UL);
RegisterDefinedLocalWithoutSideEffects(_localMade);
}

public override Instruction[] ToILInstructions(MethodAnalysis<Arm64Instruction> context, ILProcessor processor)
{
if (_localMade.Variable == null)
return Array.Empty<Instruction>();

return new[]
{
processor.Create(OpCodes.Ldc_I4, 0)
processor.Create(OpCodes.Ldc_I4, 0),
processor.Create(OpCodes.Stloc, _localMade.Variable)
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public override Instruction[] ToILInstructions(MethodAnalysis<T> context, ILProc
if (LocalWritten == null || ReadFrom == null || FieldRead == null)
throw new TaintedInstructionException();

var ret = new List<Mono.Cecil.Cil.Instruction>();
var ret = new List<Instruction>();

//Load object
ret.AddRange(ReadFrom.GetILToLoad(context, processor));
Expand Down
58 changes: 58 additions & 0 deletions Cpp2IL.Core/Analysis/AsmAnalyzerArmV8A.InstructionChecks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ protected override void PerformInstructionChecks(Arm64Instruction instruction)
case 2:
CheckForTwoOpInstruction(instruction);
break;
case 3:
CheckForThreeOpInstruction(instruction);
break;
}
}

Expand Down Expand Up @@ -93,6 +96,8 @@ private void CheckForTwoOpInstruction(Arm64Instruction instruction)
var mnemonic = instruction.Mnemonic;
if (mnemonic is "ldrb" or "ldrh")
mnemonic = "ldr";
if (mnemonic is "strb" or "strh")
mnemonic = "str";

//The single most annoying part about capstone is that its mnemonics are strings.
switch (mnemonic)
Expand Down Expand Up @@ -175,6 +180,59 @@ private void CheckForTwoOpInstruction(Arm64Instruction instruction)
//Move generic analyzed op to another reg
Analysis.Actions.Add(new Arm64RegCopyAction(Analysis, instruction));
break;
case "str" when t0 is Arm64OperandType.Register && t1 is Arm64OperandType.Memory && var0 is {} && memVar is LocalDefinition:
//Field write from register.
//Unlike a bunch of other instructions, source is operand 0, destination is operand 1.
Analysis.Actions.Add(new Arm64RegisterToFieldAction(Analysis, instruction));
break;
case "str" when t0 is Arm64OperandType.Immediate && t1 is Arm64OperandType.Memory && memVar is LocalDefinition:
//Field write from immediate
Analysis.Actions.Add(new Arm64ImmediateToFieldAction(Analysis, instruction));
break;
}
}

private void CheckForThreeOpInstruction(Arm64Instruction instruction)
{
var op0 = instruction.Details.Operands[0]!;
var op1 = instruction.Details.Operands[1]!;
var op2 = instruction.Details.Operands[2]!;

var t0 = op0.Type;
var t1 = op1.Type;
var t2 = op2.Type;

var r0 = op0.RegisterSafe()?.Id ?? Arm64RegisterId.Invalid;
var r1 = op1.RegisterSafe()?.Id ?? Arm64RegisterId.Invalid;
var r2 = op2.RegisterSafe()?.Id ?? Arm64RegisterId.Invalid;

var r0Name = Utils.GetRegisterNameNew(r0);
var r1Name = Utils.GetRegisterNameNew(r1);
var r2Name = Utils.GetRegisterNameNew(r2);

var var0 = Analysis.GetOperandInRegister(r0Name);
var var1 = Analysis.GetOperandInRegister(r1Name);
var var2 = Analysis.GetOperandInRegister(r2Name);

var imm0 = op0.ImmediateSafe();
var imm1 = op1.ImmediateSafe();
var imm2 = op2.ImmediateSafe();

var memoryBase = instruction.MemoryBase()?.Id ?? Arm64RegisterId.Invalid;
var memoryOffset = instruction.MemoryOffset();
var memoryIndex = instruction.MemoryIndex()?.Id ?? Arm64RegisterId.Invalid;

var memVar = Analysis.GetOperandInRegister(Utils.GetRegisterNameNew(memoryBase));

var mnemonic = instruction.Mnemonic;

switch (mnemonic)
{
case "orr" when r1Name is "xzr" && t2 == Arm64OperandType.Immediate && imm2 != 0:
//ORR dest, xzr, #n
//dest = n, basically. Technically 0 | n, but that's the same.
Analysis.Actions.Add(new Arm64OrZeroAndImmAction(Analysis, instruction));
break;
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion Cpp2IL.Core/Analysis/AsmAnalyzerArmV8a.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Cpp2IL.Core.Analysis.PostProcessActions;
using Gee.External.Capstone;
using Gee.External.Capstone.Arm64;
using LibCpp2IL;
Expand Down Expand Up @@ -119,7 +120,8 @@ internal override StringBuilder GetAssemblyDump()

public override void RunPostProcessors()
{
//no-op
new RemovedUnusedLocalsPostProcessor<Arm64Instruction>().PostProcess(Analysis);
new RenameLocalsPostProcessor<Arm64Instruction>().PostProcess(Analysis);
}
}
}
4 changes: 2 additions & 2 deletions Cpp2IL.Core/Analysis/AsmAnalyzerX86.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ internal override StringBuilder GetAssemblyDump()

public override void RunPostProcessors()
{
new RemovedUnusedLocalsPostProcessor<Instruction>().PostProcess(Analysis, MethodDefinition!);
new RenameLocalsPostProcessor().PostProcess(Analysis, MethodDefinition!);
new RemovedUnusedLocalsPostProcessor<Instruction>().PostProcess(Analysis);
new RenameLocalsPostProcessor<Instruction>().PostProcess(Analysis);
}

#if false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@

using System.Linq;
using Cpp2IL.Core.Analysis.ResultModels;
using Mono.Cecil;

namespace Cpp2IL.Core.Analysis.PostProcessActions
{
public class RemovedUnusedLocalsPostProcessor<T> : PostProcessor<T>
{
public override void PostProcess(MethodAnalysis<T> analysis, MethodDefinition definition)
public override void PostProcess(MethodAnalysis<T> analysis)
{
var unused = analysis.Locals.Where(l => !analysis.FunctionArgumentLocals.Contains(l) && analysis.Actions.All(a => !a.GetUsedLocals().Contains(l))).ToList();
#if PRINT_UNUSED_LOCAL_DATA
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
using System;
using System.Collections.Generic;
using Cpp2IL.Core.Analysis.Actions.Base;
using Cpp2IL.Core.Analysis.Actions.x86;
using Cpp2IL.Core.Analysis.Actions.x86.Important;
using Cpp2IL.Core.Analysis.ResultModels;
using Iced.Intel;
using Mono.Cecil;

namespace Cpp2IL.Core.Analysis.PostProcessActions
{
public class RenameLocalsPostProcessor : PostProcessor<Instruction> {
public class RenameLocalsPostProcessor<T> : PostProcessor<T> {

public override void PostProcess(MethodAnalysis<Instruction> analysis, MethodDefinition definition)
public override void PostProcess(MethodAnalysis<T> analysis)
{
var countDict = new Dictionary<string, int>();

foreach (var action in analysis.Actions)
{
LocalDefinition localDefinition;
string nameBase;
if (action is FieldToLocalAction {FieldRead: {}, LocalWritten: {}} ftla)
if (action is AbstractFieldReadAction<T> {FieldRead: {}, LocalWritten: {}} ftla)
{
var field = ftla.FieldRead.GetLast().FinalLoadInChain!;
nameBase = field.Name;
Expand All @@ -27,7 +27,7 @@ public override void PostProcess(MethodAnalysis<Instruction> analysis, MethodDef

localDefinition = ftla.LocalWritten;
}
else if (action is StaticFieldToRegAction {FieldRead: {}, LocalWritten: {}} sftra)
else if (action is AbstractStaticFieldReadAction<T> {FieldRead: {}, LocalWritten: {}} sftra)
{
var field = sftra.FieldRead;
nameBase = field.Name;
Expand All @@ -36,7 +36,7 @@ public override void PostProcess(MethodAnalysis<Instruction> analysis, MethodDef

localDefinition = sftra.LocalWritten;
}
else if (action is BaseX86CallAction {ReturnedLocal: { }, ManagedMethodBeingCalled: {}} aca)
else if (action is AbstractCallAction<T> {ReturnedLocal: { }, ManagedMethodBeingCalled: {}} aca)
{
if (aca.ManagedMethodBeingCalled.Name.StartsWith("get_"))
nameBase = aca.ManagedMethodBeingCalled.Name[4..];
Expand All @@ -53,11 +53,11 @@ public override void PostProcess(MethodAnalysis<Instruction> analysis, MethodDef
{
nameBase = "length";
localDefinition = alptla.LocalMade;
} else if (action is ArrayElementReadToRegAction {LocalMade: { }} aertpa)
} else if (action is AbstractArrayOffsetReadAction<T> {LocalMade: { }} aertpa)
{
nameBase = aertpa.LocalMade.Type!.Name;
localDefinition = aertpa.LocalMade;
} else if (action is AllocateInstanceAction {LocalReturned: { }, TypeCreated: { }} aia)
} else if (action is AbstractNewObjAction<T> {LocalReturned: { }, TypeCreated: { }} aia)
{
nameBase = aia.TypeCreated.Name;
localDefinition = aia.LocalReturned;
Expand Down
3 changes: 1 addition & 2 deletions Cpp2IL.Core/Analysis/PostProcessActions/PostProcessor.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
using Cpp2IL.Core.Analysis.ResultModels;
using Mono.Cecil;

namespace Cpp2IL.Core.Analysis.PostProcessActions
{
public abstract class PostProcessor<T>
{
public abstract void PostProcess(MethodAnalysis<T> analysis, MethodDefinition definition);
public abstract void PostProcess(MethodAnalysis<T> analysis);
}
}

0 comments on commit dc046b9

Please sign in to comment.