Skip to content

Commit f907959

Browse files
authored
Fix NewArmV8InstructionSet to properly fetch 'this' parameter and add call instructions (#557)
1 parent 79fe832 commit f907959

3 files changed

Lines changed: 47 additions & 17 deletions

File tree

Cpp2IL.Core/Analysis/LocalVariables.cs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public static void CreateAll(MethodAnalysisContext method)
8080
var operandOffset = method.IsStatic ? 0 : 1; // 'this'
8181

8282
// 'this' param
83-
if (!method.IsStatic && method.Locals.Count > 0)
83+
if (!method.IsStatic && method.Locals.Count > 0 && method.ParameterOperands.Count > 0)
8484
{
8585
var thisOperand = (Register)method.ParameterOperands[0];
8686
var thisLocal = method.Locals.FirstOrDefault(l => l.Register.Number == thisOperand.Number && l.Register.Version == -1);
@@ -352,9 +352,22 @@ private static bool PropagateFromCallParameters(MethodAnalysisContext method)
352352
calledMethod.Name is ".ctor" or ".cctor" ? calledMethod.DeclaringType : calledMethod.ReturnType);
353353
}
354354

355+
356+
// Call operands
357+
// 0. Target
358+
// 1. ReturnValue
359+
// 2. thisParam
360+
// ... parameters
361+
362+
// CallVoid operands
363+
// 0. Target
364+
// 1. thisParam
365+
// ... parameters
366+
var thisParamIndex = instruction.OpCode == OpCode.CallVoid ? 1 : 2;
367+
355368
// 'this' param
356369
if (!calledMethod.IsStatic
357-
&& instruction.Operands[instruction.OpCode == OpCode.CallVoid ? 1 : 2] is LocalVariable thisParam)
370+
&& instruction.Operands[thisParamIndex] is LocalVariable thisParam)
358371
{
359372
changed |= SetTypeIfUnknown(thisParam, calledMethod.DeclaringType);
360373
}

Cpp2IL.Core/IlGenerator.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,10 @@ private static List<CilInstruction> GenerateInstructions(Instruction instruction
212212
if ((instruction.Operands.Count - 1) >= thisParamIndex)
213213
LoadOperand(instruction.Operands[thisParamIndex], method, locals, writeLine, stringCtor);
214214
else
215+
{
215216
instructions.Add(CilOpCodes.Ldstr, $"Non static method called without 'this' param ({instruction})");
217+
instructions.Add(CilOpCodes.Call, importer.ImportMethod(writeLine));
218+
}
216219
}
217220

218221
// Load normal params
@@ -439,7 +442,7 @@ private static void LoadOperand(object operand, MethodDefinition method,
439442
break;
440443
default:
441444
instructions.Add(CilOpCodes.Ldstr, "Unknown operand: " + operand.ToString());
442-
instructions.Add(CilOpCodes.Newobj, importer.ImportMethod(stringCtor));
445+
instructions.Add(CilOpCodes.Call, importer.ImportMethod(writeLine));
443446
break;
444447
}
445448
}

Cpp2IL.Core/InstructionSets/NewArmV8InstructionSet.cs

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ public override Memory<byte> GetRawBytesForMethod(MethodAnalysisContext context,
4848

4949
public override List<object> GetParameterOperandsFromMethod(MethodAnalysisContext context)
5050
{
51-
return [];
51+
// Is this correct (?)
52+
return GetArgumentOperandsForCall(context);
5253
}
5354

5455
public override List<Instruction> GetIsilFromMethod(MethodAnalysisContext context)
@@ -97,10 +98,21 @@ private void ConvertInstructionStatement(Arm64Instruction instruction, List<Inst
9798
{
9899
var address = instruction.Address;
99100

100-
void Add(ulong address, OpCode opCode, params object[] operands)
101+
Instruction Add(ulong address, OpCode opCode, params object[] operands)
101102
{
102103
addresses.Add(address);
103-
instructions.Add(new Instruction(instructions.Count, opCode, operands));
104+
var newInstruction = new Instruction(instructions.Count, opCode, operands);
105+
instructions.Add(newInstruction);
106+
return newInstruction;
107+
}
108+
109+
void AddCall(MethodAnalysisContext context, object? returnRegister2, ulong address, ulong target)
110+
{
111+
var call = returnRegister2 == null ?
112+
Add(address, OpCode.CallVoid, target) :
113+
Add(address, OpCode.Call, target, returnRegister2);
114+
115+
call.Operands.AddRange(GetArgumentOperandsForCall(context, target));
104116
}
105117

106118
switch (instruction.Mnemonic)
@@ -238,7 +250,7 @@ void Add(ulong address, OpCode opCode, params object[] operands)
238250
Add(address, OpCode.Move, dest2, mem2);
239251
break;
240252
case Arm64Mnemonic.BL:
241-
Add(address, OpCode.Call, instruction.BranchTarget, GetArgumentOperandsForCall(context, instruction.BranchTarget).ToArray());
253+
AddCall(context, GetReturnRegisterForContext(context), address, instruction.BranchTarget);
242254
break;
243255
case Arm64Mnemonic.RET:
244256
var returnRegister = GetReturnRegisterForContext(context);
@@ -253,9 +265,9 @@ void Add(ulong address, OpCode opCode, params object[] operands)
253265
if (target < context.UnderlyingPointer || target > context.UnderlyingPointer + (ulong)context.RawBytes.Length)
254266
{
255267
//Unconditional branch to outside the method, treat as call (tail-call, specifically) followed by return
256-
257-
Add(address, OpCode.Call, instruction.BranchTarget, GetArgumentOperandsForCall(context, instruction.BranchTarget).ToArray());
258268
var returnRegister2 = GetReturnRegisterForContext(context);
269+
AddCall(context, returnRegister2, address, target);
270+
259271
if (returnRegister2 == null)
260272
Add(address, OpCode.Return);
261273
else
@@ -527,15 +539,8 @@ private object ConvertOperand(Arm64Instruction instruction, int operand)
527539
return new Register(null, nameof(Arm64Register.X0));
528540
}
529541

530-
private List<object> GetArgumentOperandsForCall(MethodAnalysisContext contextBeingAnalyzed, ulong callAddr)
542+
private List<object> GetArgumentOperandsForCall(MethodAnalysisContext contextBeingCalled)
531543
{
532-
if (!contextBeingAnalyzed.AppContext.MethodsByAddress.TryGetValue(callAddr, out var methodsAtAddress))
533-
//TODO
534-
return [];
535-
536-
//For the sake of arguments, all we care about is the first method at the address, because they'll only be shared if they have the same signature.
537-
var contextBeingCalled = methodsAtAddress.First();
538-
539544
var vectorCount = 0;
540545
var nonVectorCount = 0;
541546

@@ -572,4 +577,13 @@ private List<object> GetArgumentOperandsForCall(MethodAnalysisContext contextBei
572577

573578
return ret;
574579
}
580+
581+
private List<object> GetArgumentOperandsForCall(MethodAnalysisContext contextBeingAnalyzed, ulong callAddr)
582+
{
583+
if (!contextBeingAnalyzed.AppContext.MethodsByAddress.TryGetValue(callAddr, out var methodsAtAddress))
584+
//TODO
585+
return [];
586+
587+
return GetArgumentOperandsForCall(methodsAtAddress.First());
588+
}
575589
}

0 commit comments

Comments
 (0)