Skip to content

Commit 72c306a

Browse files
authored
light refactor of binary and metadata initialization (#533)
1 parent 9fcbb6b commit 72c306a

5 files changed

Lines changed: 158 additions & 102 deletions

File tree

LibCpp2IL/Il2CppBinary.cs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,28 @@ public abstract class Il2CppBinary(MemoryStream input) : ClassReadingBinaryReade
6464
private float? _metadataVersion;
6565
public sealed override float MetadataVersion => _metadataVersion ?? 0;
6666

67-
internal void SetMetadataVersion(float version) => _metadataVersion = version;
68-
6967
public int InBinaryMetadataSize { get; private set; }
7068

7169
private Il2CppMetadata? _metadata;
7270

71+
public void Init(Il2CppMetadata metadata)
72+
{
73+
_metadataVersion = metadata.MetadataVersion;
74+
75+
var start = DateTime.Now;
76+
77+
var (codereg, metareg) = FindCodeAndMetadataReg(metadata);
78+
79+
LibLogger.InfoNewline($"Got Binary codereg: 0x{codereg:X}, metareg: 0x{metareg:X} in {(DateTime.Now - start).TotalMilliseconds:F0}ms.");
80+
LibLogger.InfoNewline("Initializing Binary...");
81+
82+
start = DateTime.Now;
83+
84+
Init(codereg, metareg, metadata);
85+
86+
LibLogger.InfoNewline($"Initialized Binary in {(DateTime.Now - start).TotalMilliseconds:F0}ms");
87+
}
88+
7389
public void Init(ulong pCodeRegistration, ulong pMetadataRegistration, Il2CppMetadata metadata)
7490
{
7591
_metadata = metadata;

LibCpp2IL/LibCpp2IlBinaryRegistry.cs

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -64,22 +64,12 @@ internal static Il2CppBinary CreateAndInit(byte[] buffer, Il2CppMetadata metadat
6464
var memStream = new MemoryStream(buffer, 0, buffer.Length, true, true);
6565

6666
LibLogger.InfoNewline("Searching Binary for Required Data...");
67-
var start = DateTime.Now;
6867

6968
var binary = match.FactoryFunc(memStream);
70-
binary.SetMetadataVersion(metadata.MetadataVersion);
7169

7270
// NOTE: Do not write to LibCpp2IlMain.Binary here. The binary registry is global, but the loaded binary is per-context.
73-
74-
var (codereg, metareg) = binary.FindCodeAndMetadataReg(metadata);
75-
76-
LibLogger.InfoNewline($"Got Binary codereg: 0x{codereg:X}, metareg: 0x{metareg:X} in {(DateTime.Now - start).TotalMilliseconds:F0}ms.");
77-
LibLogger.InfoNewline("Initializing Binary...");
78-
start = DateTime.Now;
79-
80-
binary.Init(codereg, metareg, metadata);
81-
82-
LibLogger.InfoNewline($"Initialized Binary in {(DateTime.Now - start).TotalMilliseconds:F0}ms");
71+
72+
binary.Init(metadata);
8373

8474
return binary;
8575
}

LibCpp2IL/LibCpp2IlContext.cs

Lines changed: 4 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
1-
using System;
21
using System.Collections.Generic;
3-
using System.IO;
4-
using System.Linq;
5-
using AssetRipper.Primitives;
6-
using LibCpp2IL.BinaryStructures;
7-
using LibCpp2IL.Logging;
82
using LibCpp2IL.Metadata;
93
using LibCpp2IL.Reflection;
104

@@ -17,90 +11,20 @@ public sealed class LibCpp2IlContext
1711
{
1812
public LibCpp2IlMain.LibCpp2IlSettings Settings { get; }
1913

20-
public bool Il2CppTypeHasNumMods5Bits { get; private set; }
14+
public bool Il2CppTypeHasNumMods5Bits { get; internal set; }
2115

22-
public Il2CppBinary Binary { get; private set; }
23-
public Il2CppMetadata Metadata { get; private set; }
16+
public Il2CppBinary Binary { get; internal set; } = null!;
17+
public Il2CppMetadata Metadata { get; internal set; } = null!;
2418

2519
public float MetadataVersion => Metadata.MetadataVersion;
2620

2721
public Dictionary<ulong, List<Il2CppMethodDefinition>> MethodsByPtr { get; } = new();
2822

2923
public LibCpp2IlReflectionCache ReflectionCache { get; } = new();
3024

31-
private LibCpp2IlContext(LibCpp2IlMain.LibCpp2IlSettings settings, Il2CppBinary binary, Il2CppMetadata metadata)
25+
internal LibCpp2IlContext(LibCpp2IlMain.LibCpp2IlSettings settings)
3226
{
3327
Settings = settings;
34-
Binary = binary;
35-
Metadata = metadata;
36-
}
37-
38-
public static LibCpp2IlContext LoadFromFile(string pePath, string metadataPath, UnityVersion unityVersion)
39-
{
40-
var metadataBytes = File.ReadAllBytes(metadataPath);
41-
var peBytes = File.ReadAllBytes(pePath);
42-
return Initialize(peBytes, metadataBytes, unityVersion);
43-
}
44-
45-
public static LibCpp2IlContext Initialize(byte[] binaryBytes, byte[] metadataBytes, UnityVersion unityVersion)
46-
{
47-
// Snapshot settings at creation time.
48-
var settings = new LibCpp2IlMain.LibCpp2IlSettings
49-
{
50-
AllowManualMetadataAndCodeRegInput = LibCpp2IlMain.Settings.AllowManualMetadataAndCodeRegInput,
51-
DisableMethodPointerMapping = LibCpp2IlMain.Settings.DisableMethodPointerMapping,
52-
DisableGlobalResolving = LibCpp2IlMain.Settings.DisableGlobalResolving,
53-
};
54-
55-
var start = DateTime.Now;
56-
LibLogger.InfoNewline("Initializing Metadata...");
57-
58-
var metadata = Il2CppMetadata.ReadFrom(metadataBytes, unityVersion);
59-
60-
var context = new LibCpp2IlContext(settings, binary: null!, metadata);
61-
62-
context.Il2CppTypeHasNumMods5Bits = metadata.MetadataVersion >= 27.2f;
63-
64-
LibLogger.InfoNewline($"Initialized Metadata in {(DateTime.Now - start).TotalMilliseconds:F0}ms");
65-
66-
// Legacy/static API compatibility: some in-binary structures still resolve via LibCpp2IlMain.Binary/TheMetadata
67-
// during binary initialization, so we must set metadata defaults before initializing the binary.
68-
LibCpp2IlMain.TheMetadata = metadata;
69-
LibCpp2IlMain.DefaultContext = context;
70-
LibCpp2IlMain.Il2CppTypeHasNumMods5Bits = context.Il2CppTypeHasNumMods5Bits;
71-
72-
var bin = LibCpp2IlBinaryRegistry.CreateAndInit(binaryBytes, metadata);
73-
context.Binary = bin;
74-
75-
// Complete legacy/static initialization now that the binary exists.
76-
LibCpp2IlMain.Binary = bin;
77-
78-
if (!context.Settings.DisableGlobalResolving && context.MetadataVersion < 27)
79-
{
80-
start = DateTime.Now;
81-
LibLogger.Info("Mapping Globals...");
82-
LibCpp2IlGlobalMapper.MapGlobalIdentifiers(metadata, bin);
83-
LibLogger.InfoNewline($"OK ({(DateTime.Now - start).TotalMilliseconds:F0}ms)");
84-
}
85-
86-
if (!context.Settings.DisableMethodPointerMapping)
87-
{
88-
start = DateTime.Now;
89-
LibLogger.Info("Mapping pointers to Il2CppMethodDefinitions...");
90-
foreach (var (method, ptr) in metadata.methodDefs.Select(method => (method, ptr: method.MethodPointer)))
91-
{
92-
if (!context.MethodsByPtr.TryGetValue(ptr, out var list))
93-
context.MethodsByPtr[ptr] = list = [];
94-
95-
list.Add(method);
96-
}
97-
98-
LibLogger.InfoNewline($"Processed {metadata.methodDefs.Length} OK ({(DateTime.Now - start).TotalMilliseconds:F0}ms)");
99-
}
100-
101-
context.ReflectionCache.Init(context);
102-
103-
return context;
10428
}
10529

10630
public List<Il2CppMethodDefinition>? GetManagedMethodImplementationsAtAddress(ulong addr)
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
using System;
2+
using System.IO;
3+
using System.Linq;
4+
using AssetRipper.Primitives;
5+
using LibCpp2IL.Logging;
6+
using LibCpp2IL.Metadata;
7+
8+
namespace LibCpp2IL;
9+
10+
public sealed class LibCpp2IlContextBuilder
11+
{
12+
private readonly LibCpp2IlContext _context = new(
13+
new LibCpp2IlMain.LibCpp2IlSettings // Snapshot settings at creation time.
14+
{
15+
AllowManualMetadataAndCodeRegInput = LibCpp2IlMain.Settings.AllowManualMetadataAndCodeRegInput,
16+
DisableMethodPointerMapping = LibCpp2IlMain.Settings.DisableMethodPointerMapping,
17+
DisableGlobalResolving = LibCpp2IlMain.Settings.DisableGlobalResolving,
18+
});
19+
20+
private bool _metadataLoaded;
21+
private bool _binaryLoaded;
22+
23+
public void LoadMetadata(byte[] metadataBytes, UnityVersion unityVersion)
24+
{
25+
var start = DateTime.Now;
26+
LibLogger.InfoNewline("Initializing Metadata...");
27+
28+
var metadata = _context.Metadata = Il2CppMetadata.ReadFrom(metadataBytes, unityVersion);
29+
30+
_context.Il2CppTypeHasNumMods5Bits = metadata.MetadataVersion >= 27.2f;
31+
32+
LibLogger.InfoNewline($"Initialized Metadata in {(DateTime.Now - start).TotalMilliseconds:F0}ms");
33+
34+
// Legacy/static API compatibility: some in-binary structures still resolve via LibCpp2IlMain.Binary/TheMetadata
35+
// during binary initialization, so we must set metadata defaults before initializing the binary.
36+
LibCpp2IlMain.TheMetadata = metadata;
37+
LibCpp2IlMain.DefaultContext = _context;
38+
LibCpp2IlMain.Il2CppTypeHasNumMods5Bits = _context.Il2CppTypeHasNumMods5Bits;
39+
40+
_metadataLoaded = true;
41+
}
42+
43+
public void LoadBinary(byte[] binaryBytes)
44+
{
45+
if (!_metadataLoaded)
46+
throw new InvalidOperationException("Metadata must be loaded before the binary can be loaded.");
47+
48+
var bin = _context.Binary = LibCpp2IlBinaryRegistry.CreateAndInit(binaryBytes, _context.Metadata);
49+
50+
// Complete legacy/static initialization now that the binary exists.
51+
LibCpp2IlMain.Binary = bin;
52+
53+
_binaryLoaded = true;
54+
}
55+
56+
public void LoadBinary(Il2CppBinary binary)
57+
{
58+
if (!_metadataLoaded)
59+
throw new InvalidOperationException("Metadata must be loaded before the binary can be loaded.");
60+
61+
binary.Init(_context.Metadata);
62+
63+
_context.Binary = binary;
64+
65+
// Complete legacy/static initialization now that the binary exists.
66+
LibCpp2IlMain.Binary = binary;
67+
68+
_binaryLoaded = true;
69+
}
70+
71+
public LibCpp2IlContext Build()
72+
{
73+
if (!_metadataLoaded)
74+
throw new InvalidOperationException("Metadata must be loaded before context can be built.");
75+
76+
if (!_binaryLoaded)
77+
throw new InvalidOperationException("Binary must be loaded before context can be built.");
78+
79+
DateTime start;
80+
if (!_context.Settings.DisableGlobalResolving && _context.MetadataVersion < 27)
81+
{
82+
start = DateTime.Now;
83+
LibLogger.Info("Mapping Globals...");
84+
LibCpp2IlGlobalMapper.MapGlobalIdentifiers(_context.Metadata, _context.Binary);
85+
LibLogger.InfoNewline($"OK ({(DateTime.Now - start).TotalMilliseconds:F0}ms)");
86+
}
87+
88+
if (!_context.Settings.DisableMethodPointerMapping)
89+
{
90+
start = DateTime.Now;
91+
LibLogger.Info("Mapping pointers to Il2CppMethodDefinitions...");
92+
foreach (var (method, ptr) in _context.Metadata.methodDefs.Select(method => (method, ptr: method.MethodPointer)))
93+
{
94+
if (!_context.MethodsByPtr.TryGetValue(ptr, out var list))
95+
_context.MethodsByPtr[ptr] = list = [];
96+
97+
list.Add(method);
98+
}
99+
100+
LibLogger.InfoNewline($"Processed {_context.Metadata.methodDefs.Length} OK ({(DateTime.Now - start).TotalMilliseconds:F0}ms)");
101+
}
102+
103+
_context.ReflectionCache.Init(_context);
104+
105+
return _context;
106+
}
107+
108+
public static LibCpp2IlContext Build(byte[] binaryBytes, byte[] metadataBytes, UnityVersion unityVersion)
109+
{
110+
LibCpp2IlContextBuilder builder = new();
111+
112+
builder.LoadMetadata(metadataBytes, unityVersion);
113+
builder.LoadBinary(binaryBytes);
114+
115+
return builder.Build();
116+
}
117+
118+
public static LibCpp2IlContext BuildFromFiles(string pePath, string metadataPath, UnityVersion unityVersion)
119+
{
120+
var metadataBytes = File.ReadAllBytes(metadataPath);
121+
var peBytes = File.ReadAllBytes(pePath);
122+
123+
LibCpp2IlContextBuilder builder = new();
124+
125+
builder.LoadMetadata(metadataBytes, unityVersion);
126+
builder.LoadBinary(peBytes);
127+
128+
return builder.Build();
129+
}
130+
}

LibCpp2IL/LibCpp2IlMain.cs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,12 @@
22
using System.Collections.Generic;
33
using System.Diagnostics;
44
using System.IO;
5-
using System.Linq;
65
using System.Text;
76
using System.Text.RegularExpressions;
87
using AssetRipper.Primitives;
9-
using LibCpp2IL.Elf;
108
using LibCpp2IL.Logging;
119
using LibCpp2IL.Metadata;
12-
using LibCpp2IL.NintendoSwitch;
1310
using LibCpp2IL.Reflection;
14-
using LibCpp2IL.Wasm;
1511

1612
namespace LibCpp2IL;
1713

@@ -159,7 +155,7 @@ public static void Reset()
159155
/// <throws><see cref="System.NotSupportedException"/> if the PE file specifies it is neither for AMD64 or i386 architecture</throws>
160156
public static bool Initialize(byte[] binaryBytes, byte[] metadataBytes, UnityVersion unityVersion)
161157
{
162-
DefaultContext = LibCpp2IlContext.Initialize(binaryBytes, metadataBytes, unityVersion);
158+
DefaultContext = LibCpp2IlContextBuilder.Build(binaryBytes, metadataBytes, unityVersion);
163159

164160
// Preserve legacy static fields for existing consumers.
165161
TheMetadata = DefaultContext.Metadata;
@@ -175,10 +171,10 @@ public static bool Initialize(byte[] binaryBytes, byte[] metadataBytes, UnityVer
175171
}
176172

177173
public static LibCpp2IlContext InitializeAsContext(byte[] binaryBytes, byte[] metadataBytes, UnityVersion unityVersion)
178-
=> LibCpp2IlContext.Initialize(binaryBytes, metadataBytes, unityVersion);
174+
=> LibCpp2IlContextBuilder.Build(binaryBytes, metadataBytes, unityVersion);
179175

180176
public static LibCpp2IlContext LoadFromFileAsContext(string pePath, string metadataPath, UnityVersion unityVersion)
181-
=> LibCpp2IlContext.LoadFromFile(pePath, metadataPath, unityVersion);
177+
=> LibCpp2IlContextBuilder.BuildFromFiles(pePath, metadataPath, unityVersion);
182178

183179
/// <summary>
184180
/// Initialize the metadata and PE from their respective file locations.
@@ -191,7 +187,7 @@ public static LibCpp2IlContext LoadFromFileAsContext(string pePath, string metad
191187
/// <throws><see cref="System.NotSupportedException"/> if the PE file specifies it is neither for AMD64 or i386 architecture</throws>
192188
public static bool LoadFromFile(string pePath, string metadataPath, UnityVersion unityVersion)
193189
{
194-
var ctx = LibCpp2IlContext.LoadFromFile(pePath, metadataPath, unityVersion);
190+
var ctx = LibCpp2IlContextBuilder.BuildFromFiles(pePath, metadataPath, unityVersion);
195191
DefaultContext = ctx;
196192

197193
TheMetadata = ctx.Metadata;

0 commit comments

Comments
 (0)