From 964a3a7bdc8843b3b11034d7635cf8dac40dade3 Mon Sep 17 00:00:00 2001 From: kremnev8 Date: Tue, 6 Jun 2023 18:12:15 +0300 Subject: [PATCH 1/3] Allow static method injection --- .../Injection/ClassInjector.cs | 49 ++++++++++++------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/Il2CppInterop.Runtime/Injection/ClassInjector.cs b/Il2CppInterop.Runtime/Injection/ClassInjector.cs index 6db08110..b8df02ee 100644 --- a/Il2CppInterop.Runtime/Injection/ClassInjector.cs +++ b/Il2CppInterop.Runtime/Injection/ClassInjector.cs @@ -550,7 +550,6 @@ private static bool IsFieldEligible(FieldInfo field) private static bool IsMethodEligible(MethodInfo method) { if (method.Name == "Finalize") return false; - if (method.IsStatic) return false; if (method.CustomAttributes.Any(it => typeof(HideFromIl2CppAttribute).IsAssignableFrom(it.AttributeType))) return false; @@ -583,10 +582,12 @@ private static bool IsMethodEligible(MethodInfo method) foreach (var parameter in method.GetParameters()) { var parameterType = parameter.ParameterType; - if (!IsTypeSupported(parameterType)) + if (!IsTypeSupported(parameterType) || + method.IsStatic && parameterType.IsGenericType && parameterType.ContainsGenericParameters) { Logger.Instance.LogWarning( - "Method {Method} on type {DeclaringType} has unsupported parameter {Parameter} of type {ParameterType}", method.ToString(), method.DeclaringType, parameter, parameterType); + "Method {Method} on type {DeclaringType} has unsupported parameter {Parameter} of type {ParameterType}", method.ToString(), + method.DeclaringType, parameter, parameterType); return false; } } @@ -726,6 +727,11 @@ private static bool IsMethodEligible(MethodInfo method) converted.Flags = Il2CppMethodFlags.METHOD_ATTRIBUTE_PUBLIC | Il2CppMethodFlags.METHOD_ATTRIBUTE_HIDE_BY_SIG; + if (monoMethod.IsStatic) + { + converted.Flags |= Il2CppMethodFlags.METHOD_ATTRIBUTE_STATIC; + } + if (monoMethod.IsAbstract) { converted.Flags |= Il2CppMethodFlags.METHOD_ATTRIBUTE_ABSTRACT; @@ -834,7 +840,8 @@ private static Delegate CreateInvoker(MethodInfo monoMethod) var body = method.GetILGenerator(); - body.Emit(OpCodes.Ldarg_2); + if (!monoMethod.IsStatic) + body.Emit(OpCodes.Ldarg_2); for (var i = 0; i < monoMethod.GetParameters().Length; i++) { var parameterInfo = monoMethod.GetParameters()[i]; @@ -916,33 +923,41 @@ private static void StaticVoidIntPtrInvoker_MetadataV29(IntPtr methodPointer, Il private static Delegate CreateTrampoline(MethodInfo monoMethod) { - var nativeParameterTypes = new[] { typeof(IntPtr) }.Concat(monoMethod.GetParameters() - .Select(it => it.ParameterType.NativeType()).Concat(new[] { typeof(Il2CppMethodInfo*) })).ToArray(); + var nativeParameterTypes = new List(); + if (!monoMethod.IsStatic) + nativeParameterTypes.Add(typeof(IntPtr)); + nativeParameterTypes.AddRange(monoMethod.GetParameters().Select(it => it.ParameterType.NativeType())); + nativeParameterTypes.Add(typeof(Il2CppMethodInfo*)); - var managedParameters = new[] { monoMethod.DeclaringType } - .Concat(monoMethod.GetParameters().Select(it => it.ParameterType)).ToArray(); + var managedParameters = new List(); + if (!monoMethod.IsStatic) + managedParameters.Add(monoMethod.DeclaringType); + managedParameters.AddRange(monoMethod.GetParameters().Select(it => it.ParameterType)); var method = new DynamicMethod( "Trampoline_" + ExtractSignature(monoMethod) + monoMethod.DeclaringType + monoMethod.Name, MethodAttributes.Static | MethodAttributes.Public, CallingConventions.Standard, - monoMethod.ReturnType.NativeType(), nativeParameterTypes, + monoMethod.ReturnType.NativeType(), nativeParameterTypes.ToArray(), monoMethod.DeclaringType, true); - var signature = new DelegateSupport.MethodSignature(monoMethod, true); + var signature = new DelegateSupport.MethodSignature(monoMethod, !monoMethod.IsStatic); var delegateType = DelegateSupport.GetOrCreateDelegateType(signature, monoMethod); var body = method.GetILGenerator(); body.BeginExceptionBlock(); - body.Emit(OpCodes.Ldarg_0); - body.Emit(OpCodes.Call, - typeof(ClassInjectorBase).GetMethod(nameof(ClassInjectorBase.GetMonoObjectFromIl2CppPointer))!); - body.Emit(OpCodes.Castclass, monoMethod.DeclaringType); + if (!monoMethod.IsStatic) + { + body.Emit(OpCodes.Ldarg_0); + body.Emit(OpCodes.Call, + typeof(ClassInjectorBase).GetMethod(nameof(ClassInjectorBase.GetMonoObjectFromIl2CppPointer))!); + body.Emit(OpCodes.Castclass, monoMethod.DeclaringType); + } - var indirectVariables = new LocalBuilder[managedParameters.Length]; + var indirectVariables = new LocalBuilder[managedParameters.Count]; - for (var i = 1; i < managedParameters.Length; i++) + for (var i = 1; i < managedParameters.Count; i++) { var parameter = managedParameters[i]; if (parameter.IsSubclassOf(typeof(ValueType))) @@ -1012,7 +1027,7 @@ void HandleTypeConversion(Type type) body.Emit(OpCodes.Stloc, managedReturnVariable); } - for (var i = 1; i < managedParameters.Length; i++) + for (var i = 1; i < managedParameters.Count; i++) { var variable = indirectVariables[i]; if (variable == null) From 45c1598cca5a988b2944671d19c8de88f8eafeb6 Mon Sep 17 00:00:00 2001 From: js6pak Date: Sun, 25 Feb 2024 20:00:21 +0100 Subject: [PATCH 2/3] Actually include static methods as eligible --- Il2CppInterop.Runtime/Injection/ClassInjector.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Il2CppInterop.Runtime/Injection/ClassInjector.cs b/Il2CppInterop.Runtime/Injection/ClassInjector.cs index b8df02ee..277346c8 100644 --- a/Il2CppInterop.Runtime/Injection/ClassInjector.cs +++ b/Il2CppInterop.Runtime/Injection/ClassInjector.cs @@ -303,7 +303,7 @@ public static void RegisterTypeInIl2Cpp(Type type, RegisterTypeOptions options) classPointer.InstanceSize = (uint)(fieldOffset + sizeof(InjectedClassData)); classPointer.ActualSize = classPointer.InstanceSize; - var eligibleMethods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly).Where(IsMethodEligible).ToArray(); + var eligibleMethods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly).Where(IsMethodEligible).ToArray(); var methodsOffset = type.IsAbstract ? 1 : 2; // 1 is the finalizer, 1 is empty ctor var methodCount = methodsOffset + eligibleMethods.Length; From b13fc2c4a7c98c8b5d8dfbeb3d93ac15218b16c5 Mon Sep 17 00:00:00 2001 From: js6pak Date: Sun, 25 Feb 2024 20:01:52 +0100 Subject: [PATCH 3/3] Fix invoker/trampoline for static methods with parameters --- .../Injection/ClassInjector.cs | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/Il2CppInterop.Runtime/Injection/ClassInjector.cs b/Il2CppInterop.Runtime/Injection/ClassInjector.cs index 277346c8..63d91020 100644 --- a/Il2CppInterop.Runtime/Injection/ClassInjector.cs +++ b/Il2CppInterop.Runtime/Injection/ClassInjector.cs @@ -818,6 +818,16 @@ private static Delegate GetOrCreateTrampoline(MethodInfo monoMethod) return CreateTrampoline(monoMethod); } + private static Type[] GetNativeParameterTypes(MethodInfo monoMethod) + { + var nativeParameterTypes = new List(); + if (!monoMethod.IsStatic) + nativeParameterTypes.Add(typeof(IntPtr)); + nativeParameterTypes.AddRange(monoMethod.GetParameters().Select(it => it.ParameterType.NativeType())); + nativeParameterTypes.Add(typeof(Il2CppMethodInfo*)); + return nativeParameterTypes.ToArray(); + } + private static Delegate CreateInvoker(MethodInfo monoMethod) { DynamicMethod method; @@ -841,11 +851,11 @@ private static Delegate CreateInvoker(MethodInfo monoMethod) var body = method.GetILGenerator(); if (!monoMethod.IsStatic) - body.Emit(OpCodes.Ldarg_2); + body.Emit(OpCodes.Ldarg_2); // obj for (var i = 0; i < monoMethod.GetParameters().Length; i++) { var parameterInfo = monoMethod.GetParameters()[i]; - body.Emit(OpCodes.Ldarg_3); + body.Emit(OpCodes.Ldarg_3); // args body.Emit(OpCodes.Ldc_I4, i * IntPtr.Size); body.Emit(OpCodes.Add_Ovf_Un); var nativeType = parameterInfo.ParameterType.NativeType(); @@ -854,10 +864,9 @@ private static Delegate CreateInvoker(MethodInfo monoMethod) body.Emit(OpCodes.Ldobj, nativeType); } - body.Emit(OpCodes.Ldarg_0); - body.EmitCalli(OpCodes.Calli, CallingConvention.Cdecl, monoMethod.ReturnType.NativeType(), - new[] { typeof(IntPtr) }.Concat(monoMethod.GetParameters().Select(it => it.ParameterType.NativeType())) - .ToArray()); + body.Emit(OpCodes.Ldarg_1); // methodMetadata + body.Emit(OpCodes.Ldarg_0); // methodPointer + body.EmitCalli(OpCodes.Calli, CallingConvention.Cdecl, monoMethod.ReturnType.NativeType(), GetNativeParameterTypes(monoMethod)); if (UnityVersionHandler.IsMetadataV29OrHigher) { @@ -923,12 +932,6 @@ private static void StaticVoidIntPtrInvoker_MetadataV29(IntPtr methodPointer, Il private static Delegate CreateTrampoline(MethodInfo monoMethod) { - var nativeParameterTypes = new List(); - if (!monoMethod.IsStatic) - nativeParameterTypes.Add(typeof(IntPtr)); - nativeParameterTypes.AddRange(monoMethod.GetParameters().Select(it => it.ParameterType.NativeType())); - nativeParameterTypes.Add(typeof(Il2CppMethodInfo*)); - var managedParameters = new List(); if (!monoMethod.IsStatic) managedParameters.Add(monoMethod.DeclaringType); @@ -937,7 +940,7 @@ private static Delegate CreateTrampoline(MethodInfo monoMethod) var method = new DynamicMethod( "Trampoline_" + ExtractSignature(monoMethod) + monoMethod.DeclaringType + monoMethod.Name, MethodAttributes.Static | MethodAttributes.Public, CallingConventions.Standard, - monoMethod.ReturnType.NativeType(), nativeParameterTypes.ToArray(), + monoMethod.ReturnType.NativeType(), GetNativeParameterTypes(monoMethod), monoMethod.DeclaringType, true); var signature = new DelegateSupport.MethodSignature(monoMethod, !monoMethod.IsStatic); @@ -957,7 +960,9 @@ private static Delegate CreateTrampoline(MethodInfo monoMethod) var indirectVariables = new LocalBuilder[managedParameters.Count]; - for (var i = 1; i < managedParameters.Count; i++) + var argOffset = method.IsStatic ? 0 : 1; + + for (var i = argOffset; i < managedParameters.Count; i++) { var parameter = managedParameters[i]; if (parameter.IsSubclassOf(typeof(ValueType))) @@ -1027,7 +1032,7 @@ void HandleTypeConversion(Type type) body.Emit(OpCodes.Stloc, managedReturnVariable); } - for (var i = 1; i < managedParameters.Count; i++) + for (var i = argOffset; i < managedParameters.Count; i++) { var variable = indirectVariables[i]; if (variable == null)