From 84670191689b894bad196d096542468c6a7b3863 Mon Sep 17 00:00:00 2001 From: js6pak Date: Sat, 10 Dec 2022 18:01:58 +0100 Subject: [PATCH] Workaround garbage field offset values --- .../Extensions/CustomAttributeEx.cs | 36 ++++++++++++------- .../Passes/Pass11ComputeTypeSpecifics.cs | 8 +++++ .../Passes/Pass21GenerateValueTypeFields.cs | 5 +-- 3 files changed, 32 insertions(+), 17 deletions(-) diff --git a/Il2CppInterop.Generator/Extensions/CustomAttributeEx.cs b/Il2CppInterop.Generator/Extensions/CustomAttributeEx.cs index 1f0c5700..57f0ddf3 100644 --- a/Il2CppInterop.Generator/Extensions/CustomAttributeEx.cs +++ b/Il2CppInterop.Generator/Extensions/CustomAttributeEx.cs @@ -1,5 +1,3 @@ -using System.Globalization; -using System.Linq; using Mono.Cecil; namespace Il2CppInterop.Generator.Extensions; @@ -8,30 +6,42 @@ public static class CustomAttributeEx { public static long ExtractOffset(this ICustomAttributeProvider originalMethod) { - return Extract(originalMethod, "AddressAttribute", "Offset"); + return ExtractLong(originalMethod, "AddressAttribute", "Offset"); } public static long ExtractRva(this ICustomAttributeProvider originalMethod) { - return Extract(originalMethod, "AddressAttribute", "RVA"); + return ExtractLong(originalMethod, "AddressAttribute", "RVA"); } public static long ExtractToken(this ICustomAttributeProvider originalMethod) { - return Extract(originalMethod, "TokenAttribute", "Token"); + return ExtractLong(originalMethod, "TokenAttribute", "Token"); } - private static long Extract(this ICustomAttributeProvider originalMethod, string attributeName, + public static int ExtractFieldOffset(this ICustomAttributeProvider originalField) + { + return ExtractInt(originalField, "FieldOffsetAttribute", "Offset"); + } + + private static string Extract(this ICustomAttributeProvider originalMethod, string attributeName, string parameterName) { - var addressAttribute = - originalMethod.CustomAttributes.SingleOrDefault(it => it.AttributeType.Name == attributeName); - var rvaField = addressAttribute?.Fields.SingleOrDefault(it => it.Name == parameterName); + var attribute = originalMethod.CustomAttributes.SingleOrDefault(it => it.AttributeType.Name == attributeName); + var field = attribute?.Fields.SingleOrDefault(it => it.Name == parameterName); - if (rvaField?.Name == null) return 0; + if (field?.Name == null) return null; + + return (string)field.Value.Argument.Value; + } - var addressString = (string)rvaField.Value.Argument.Value; - long.TryParse(addressString.Substring(2), NumberStyles.HexNumber, null, out var address); - return address; + private static long ExtractLong(this ICustomAttributeProvider originalMethod, string attributeName, string parameterName) + { + return Convert.ToInt64(Extract(originalMethod, attributeName, parameterName), 16); + } + + private static int ExtractInt(this ICustomAttributeProvider originalMethod, string attributeName, string parameterName) + { + return Convert.ToInt32(Extract(originalMethod, attributeName, parameterName), 16); } } diff --git a/Il2CppInterop.Generator/Passes/Pass11ComputeTypeSpecifics.cs b/Il2CppInterop.Generator/Passes/Pass11ComputeTypeSpecifics.cs index 3e609c98..43730192 100644 --- a/Il2CppInterop.Generator/Passes/Pass11ComputeTypeSpecifics.cs +++ b/Il2CppInterop.Generator/Passes/Pass11ComputeTypeSpecifics.cs @@ -1,4 +1,5 @@ using Il2CppInterop.Generator.Contexts; +using Il2CppInterop.Generator.Extensions; namespace Il2CppInterop.Generator.Passes; @@ -18,6 +19,13 @@ private static void ComputeSpecifics(TypeRewriteContext typeContext) foreach (var originalField in typeContext.OriginalType.Fields) { + // Sometimes il2cpp metadata has invalid field offsets for some reason (https://github.com/SamboyCoding/Cpp2IL/issues/167) + if (originalField.ExtractFieldOffset() >= 0x8000000) + { + typeContext.ComputedTypeSpecifics = TypeRewriteContext.TypeSpecifics.NonBlittableStruct; + return; + } + if (originalField.IsStatic) continue; var fieldType = originalField.FieldType; diff --git a/Il2CppInterop.Generator/Passes/Pass21GenerateValueTypeFields.cs b/Il2CppInterop.Generator/Passes/Pass21GenerateValueTypeFields.cs index 4deb5178..c7e0d6c5 100644 --- a/Il2CppInterop.Generator/Passes/Pass21GenerateValueTypeFields.cs +++ b/Il2CppInterop.Generator/Passes/Pass21GenerateValueTypeFields.cs @@ -42,10 +42,7 @@ public static void DoPass(RewriteGlobalContext context) ? assemblyContext.Imports.Module.IntPtr() : assemblyContext.RewriteTypeRef(field.FieldType)); - newField.Offset = Convert.ToInt32( - (string)field.CustomAttributes - .Single(it => it.AttributeType.Name == "FieldOffsetAttribute") - .Fields.Single().Argument.Value, 16); + newField.Offset = field.ExtractFieldOffset(); // Special case: bools in Il2Cpp are bytes if (newField.FieldType.FullName == "System.Boolean")