diff --git a/Il2CppInspector.Common/Cpp/CppDeclarationGenerator.cs b/Il2CppInspector.Common/Cpp/CppDeclarationGenerator.cs index 8cad83a..8dab1bd 100644 --- a/Il2CppInspector.Common/Cpp/CppDeclarationGenerator.cs +++ b/Il2CppInspector.Common/Cpp/CppDeclarationGenerator.cs @@ -399,11 +399,13 @@ namespace Il2CppInspector.Cpp var statics = types.Struct(name + "__StaticFields"); var namer = CreateNamespace().MakeNamer((field) => field.Name.ToCIdentifier()); foreach (var field in ti.DeclaredFields) { - if (field.IsLiteral || !field.IsStatic) + if (field.IsLiteral || !field.IsStatic || field.IsThreadStatic) continue; statics.AddField(namer.GetName(field), AsCType(field.FieldType)); } + // L-TODO: Maybe add structs for StaticThreadLocalFields? not sure how useful it would be because they are resolved at runtime + /* TODO: type the rgctx_data */ var cls = types.Struct(name + "__Class"); types.AddField(cls, "_0", "Il2CppClass_0"); diff --git a/Il2CppInspector.Common/Outputs/AssemblyShims.cs b/Il2CppInspector.Common/Outputs/AssemblyShims.cs index bb6e5fb..4c61e64 100644 --- a/Il2CppInspector.Common/Outputs/AssemblyShims.cs +++ b/Il2CppInspector.Common/Outputs/AssemblyShims.cs @@ -97,6 +97,7 @@ namespace Il2CppInspector.Outputs var attributeCtorRef = new MemberRefUser(attributeTypeRef.Module, ".ctor", MethodSig.CreateInstance(module.CorLibTypes.Void), attributeTypeRef); var stringField = new FieldSig(module.CorLibTypes.String); + var boolField = new FieldSig(module.CorLibTypes.Boolean); // Create a type deriving from System.Attribute and add it to the assembly TypeDefUser createAttribute(string name) { @@ -121,6 +122,7 @@ namespace Il2CppInspector.Outputs staticFieldOffsetAttribute = createAttribute("StaticFieldOffsetAttribute"); staticFieldOffsetAttribute.Fields.Add(new FieldDefUser("Offset", stringField, FieldAttributes.Public)); + staticFieldOffsetAttribute.Fields.Add(new FieldDefUser("ThreadStatic", boolField, FieldAttributes.Public)); staticFieldOffsetAttribute.AddDefaultConstructor(attributeCtorRef); attributeAttribute = createAttribute("AttributeAttribute"); @@ -257,7 +259,7 @@ namespace Il2CppInspector.Outputs if (!field.IsStatic) mField.AddAttribute(module, fieldOffsetAttribute, ("Offset", $"0x{field.Offset:X2}")); else if (!field.IsLiteral) - mField.AddAttribute(module, staticFieldOffsetAttribute, ("Offset", $"0x{field.Offset:X2}")); + mField.AddAttribute(module, staticFieldOffsetAttribute, ("ThreadStatic", field.IsThreadStatic), ("Offset", $"0x{field.Offset:X2}")); // Add token attribute mField.AddAttribute(module, tokenAttribute, ("Token", $"0x{field.MetadataToken:X8}")); diff --git a/Il2CppInspector.Common/Outputs/CSharpCodeStubs.cs b/Il2CppInspector.Common/Outputs/CSharpCodeStubs.cs index dd03198..cbb8585 100644 --- a/Il2CppInspector.Common/Outputs/CSharpCodeStubs.cs +++ b/Il2CppInspector.Common/Outputs/CSharpCodeStubs.cs @@ -396,6 +396,9 @@ namespace Il2CppInspector.Outputs if (field.IsNotSerialized) sb.Append(prefix + "\t[NonSerialized]\n"); + if (field.IsThreadStatic) + sb.Append(prefix + "\t[ThreadStatic]\n"); + // Attributes sb.Append(field.CustomAttributes.Where(a => a.AttributeType.FullName != FBAttribute).OrderBy(a => a.AttributeType.Name) .ToString(scope, prefix + "\t", emitPointer: !SuppressMetadata, mustCompile: MustCompile)); diff --git a/Il2CppInspector.Common/Reflection/FieldInfo.cs b/Il2CppInspector.Common/Reflection/FieldInfo.cs index d4cc2d2..c493831 100644 --- a/Il2CppInspector.Common/Reflection/FieldInfo.cs +++ b/Il2CppInspector.Common/Reflection/FieldInfo.cs @@ -29,6 +29,8 @@ namespace Il2CppInspector.Reflection { public bool HasFieldRVA => (Attributes & FieldAttributes.HasFieldRVA) != 0; public ulong DefaultValueMetadataAddress { get; } + public bool IsThreadStatic { get; } + // Custom attributes for this member public override IEnumerable CustomAttributes => CustomAttributeData.GetCustomAttributes(rootDefinition); @@ -96,6 +98,11 @@ namespace Il2CppInspector.Reflection { Name = pkg.Strings[Definition.nameIndex]; rawOffset = pkg.FieldOffsets[fieldIndex]; + if (0 > rawOffset) + { + IsThreadStatic = true; + rawOffset &= ~0x80000000; + } rootDefinition = this;