Skip to content

Commit

Permalink
Remove VersionAwareSizeOf. Closes #243
Browse files Browse the repository at this point in the history
  • Loading branch information
SamboyCoding committed Dec 31, 2023
1 parent 052a238 commit 5fa8ddd
Show file tree
Hide file tree
Showing 11 changed files with 141 additions and 151 deletions.
49 changes: 1 addition & 48 deletions Cpp2IL.Core/Utils/MiscUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Cpp2IL.Core.Extensions;
using LibCpp2IL;

namespace Cpp2IL.Core.Utils
Expand Down Expand Up @@ -153,52 +152,6 @@ public static int GetPointerSizeBytes()
return LibCpp2IlMain.Binary!.is32Bit ? 4 : 8;
}

public static IConvertible ReinterpretBytes(IConvertible original, Type desired)
{
if (desired is null)
throw new ArgumentNullException(nameof(desired), "Destination type is null");

var rawBytes = RawBytes(original);

if (!typeof(IConvertible).IsAssignableFrom(desired))
throw new Exception($"ReinterpretBytes: Desired type, {desired}, does not implement IConvertible");

//Pad out with leading zeros if we have to
var requiredLength = LibCpp2ILUtils.VersionAwareSizeOf(desired);

if (requiredLength > rawBytes.Length)
{
rawBytes = ((byte) 0).Repeat(requiredLength - rawBytes.Length).Concat(rawBytes).ToArray();
}

if (desired == typeof(bool))
return BitConverter.ToBoolean(rawBytes, 0);
if (desired == typeof(byte))
return rawBytes[0];
if (desired == typeof(char))
return BitConverter.ToChar(rawBytes, 0);
if (desired == typeof(sbyte))
return unchecked((sbyte)rawBytes[0]);
if (desired == typeof(ushort))
return BitConverter.ToUInt16(rawBytes, 0);
if (desired == typeof(short))
return BitConverter.ToInt16(rawBytes,0);
if (desired == typeof(uint))
return BitConverter.ToUInt32(rawBytes, 0);
if (desired == typeof(int))
return BitConverter.ToInt32(rawBytes, 0);
if (desired == typeof(ulong))
return BitConverter.ToUInt64(rawBytes, 0);
if (desired == typeof(long))
return BitConverter.ToInt64(rawBytes, 0);
if (desired == typeof(float))
return BitConverter.ToSingle(rawBytes, 0);
if(desired == typeof(double))
return BitConverter.ToDouble(rawBytes, 0);

throw new($"ReinterpretBytes: Cannot convert byte array back to a type of {desired}");
}

internal static byte[] RawBytes(IConvertible original) =>
original switch
{
Expand Down Expand Up @@ -344,7 +297,7 @@ public static string AnalyzeStackTracePointers(ulong[] pointers)
if (distanceGeneric < distanceNormal)
{
var actualGen = genericMethod.Value.First();
return actualGen.DeclaringType!.DeclaringAssembly!.Name + " ## " + actualGen + "(" + string.Join(", ", actualGen.BaseMethod.Parameters!.ToList()) + ")";
return actualGen.DeclaringType.DeclaringAssembly!.Name + " ## " + actualGen + "(" + string.Join(", ", actualGen.BaseMethod.Parameters!.ToList()) + ")";
}

return method.DeclaringType!.DeclaringAssembly!.Name + " ## " + method.DeclaringType.FullName + "::" + method.Name + "(" + string.Join(", ", method.Parameters!.ToList()) + ")";
Expand Down
10 changes: 5 additions & 5 deletions LibCpp2IL/BinarySearcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ internal ulong FindCodeRegistrationPost2019()

//We have pCodegenModules which *should* be x-reffed in the last pointer of Il2CppCodeRegistration.
//So, subtract the size of one pointer from that...
var bytesToGoBack = (ulong) LibCpp2ILUtils.VersionAwareSizeOf(typeof(Il2CppCodeRegistration)) - ptrSize;
var bytesToGoBack = (ulong) Il2CppCodeRegistration.GetStructSize(_binary.is32Bit, LibCpp2IlMain.MetadataVersion) - ptrSize;

LibLogger.VerboseNewline($"\t\t\tpCodegenModules is the second-to-last field of the codereg struct. Therefore on this version and architecture, we need to subtract {bytesToGoBack} bytes from its address to get pCodeReg");

Expand Down Expand Up @@ -285,7 +285,7 @@ public static bool ValidateCodeRegistration(Il2CppCodeRegistration codeReg, Dict
public ulong FindMetadataRegistrationPre24_5()
{
//We're looking for TypeDefinitionsSizesCount, which is the 4th-to-last field
var sizeOfMr = (ulong) LibCpp2ILUtils.VersionAwareSizeOf(typeof(Il2CppMetadataRegistration));
var sizeOfMr = (ulong) Il2CppMetadataRegistration.GetStructSize(_binary.is32Bit);
var ptrSize = _binary.is32Bit ? 4ul : 8ul;

var bytesToSubtract = sizeOfMr - ptrSize * 4;
Expand Down Expand Up @@ -315,7 +315,7 @@ public ulong FindMetadataRegistrationPre24_5()
public ulong FindMetadataRegistrationPost24_5()
{
var ptrSize = _binary.is32Bit ? 4ul : 8ul;
var sizeOfMr = (uint) LibCpp2ILUtils.VersionAwareSizeOf(typeof(Il2CppMetadataRegistration));
var sizeOfMr = (uint) Il2CppMetadataRegistration.GetStructSize(_binary.is32Bit);

LibLogger.VerboseNewline($"\t\t\tLooking for the number of type definitions, 0x{_typeDefinitionsCount:X}");
var ptrsToNumberOfTypes = FindAllMappedWords((ulong) _typeDefinitionsCount).ToList();
Expand All @@ -339,8 +339,8 @@ public ulong FindMetadataRegistrationPost24_5()
//Count
ok = mrWords[i] < 0xC_0000;

if (!ok && mrWords[i] < 0xF_FFFF)
LibLogger.VerboseNewline($"\t\t\tRejected Metadata registration at 0x{va:X}, because it has a count field 0x{mrWords[i]:X} at offset {i} which is above sanity limit of 0xA0000. If metadata registration detection fails, need to bump up the limit.");
if (!ok)
LibLogger.VerboseNewline($"\t\t\tRejected Metadata registration at 0x{va:X}, because it has a count field 0x{mrWords[i]:X} at offset {i} which is above sanity limit of 0xC0000. If metadata registration detection fails, may need to bump up the limit.");
}
else
{
Expand Down
51 changes: 51 additions & 0 deletions LibCpp2IL/BinaryStructures/Il2CppCodeRegistration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,57 @@ namespace LibCpp2IL.BinaryStructures
{
public class Il2CppCodeRegistration : ReadableClass
{
/*
* IMPORTANT:
* Again, like in Il2CppMetadataRegistration, all of the counts are defined as int32_t, but due to alignment, we treat them as native-width uints.
* See the comment in Il2CppMetadataRegistration for more info.
*/
public static int GetStructSize(bool isBinary32Bit, float metadataVersion)
{
//Unfortunately, this struct is not a fixed size, so we have to do some manual calculations.
var size = 0;
var ptrSize = isBinary32Bit ? 4 : 8;

if (metadataVersion <= 24.15f)
//methodPointers
size += 2 * ptrSize;

//reversePInvokeWrappers and genericMethodPointers
size += 4 * ptrSize;

if (metadataVersion is (>= 24.5f and < 27f) or >= 27.1f)
//genericAdjustorThunks
size += ptrSize;

//invokerPointers
size += 2 * ptrSize;

if (metadataVersion <= 24.5f)
//customAttributes
size += 2 * ptrSize;

//unresolvedVirtualCallPointers
size += 2 * ptrSize;

if (metadataVersion >= 29.1f)
//unresolvedInstanceCallPointers and unresolvedStaticCallPointers
size += 2 * ptrSize;

if (metadataVersion >= 23f)
//interopData
size += 2 * ptrSize;

if (metadataVersion >= 24.3f)
//windowsRuntimeFactoryTable
size += 2 * ptrSize;

if (metadataVersion >= 24.2f)
//addrCodeGenModulePtrs
size += 2 * ptrSize;

return size;
}

[Version(Max = 24.15f)] public ulong methodPointersCount;
[Version(Max = 24.15f)] public ulong methodPointers;

Expand Down
21 changes: 19 additions & 2 deletions LibCpp2IL/BinaryStructures/Il2CppMetadataRegistration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,22 @@ namespace LibCpp2IL.BinaryStructures
{
public class Il2CppMetadataRegistration : ReadableClass
{
private const int NumPointerFields = 9;
private const int NumIntFields = 7;

/*
* IMPORTANT:
* TECHNICALLY all of the counts are defined as int32_t (except for metadataUsagesCount which is size_t for some reason).
* However, this struct is aligned/packed to the native pointer width, so we actually just treat these as a bunch of ulongs (i.e. pointers/native-width uints), and the padding (4*00 bytes after each count) is ignored.
* This is (probably?) a little bit more performant than aligning (i.e. setting the stream position, i.e. seeking) after reading each count.
* Future: Does this cause issues with little-endian vs big-endian? I've not actually come across a big-endian system - or binary - to test this on.
*
* Regardless of how we do it, the fact of the matter is that the count fields are (as well as the pointers which of course are) in practice [pointer size] bytes before the next field, not always 4,
* so when calculating the total size of this struct, we need to take that into account.
*/
public static int GetStructSize(bool isBinary32Bit)
=> (NumIntFields + NumPointerFields) * (isBinary32Bit ? sizeof(int) : sizeof(long)); //On 32-bit platforms, all pointers (represented in fields by long/ulong) are 32-bit. If this struct is updated, update the number of fields above.

public long genericClassesCount;
public ulong genericClasses;
public long genericInstsCount;
Expand All @@ -18,11 +34,12 @@ public class Il2CppMetadataRegistration : ReadableClass

public long typeDefinitionsSizesCount;
public ulong typeDefinitionsSizes;
public ulong metadataUsagesCount;
public ulong metadataUsagesCount; //this one, and only this one, is defined as size_t. The rest of the counts are int32_t.
public ulong metadataUsages;

public override void Read(ClassReadingBinaryReader reader)
{
//All of the count fields (barring metadataUsagesCount) are 32-bit ints. However this struct is aligned to the size of the pointers, so we actually just read as nuint
genericClassesCount = reader.ReadNInt();
genericClasses = reader.ReadNUint();
genericInstsCount = reader.ReadNInt();
Expand All @@ -43,4 +60,4 @@ public override void Read(ClassReadingBinaryReader reader)
metadataUsages = reader.ReadNUint();
}
}
}
}
38 changes: 25 additions & 13 deletions LibCpp2IL/ClassReadingBinaryReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ public uint ReadUnityCompressedUIntAtRawAddr(long offset, out int bytesRead)
}
finally
{
PositionShiftLock.Exit();
ReleaseLock();
}
}

Expand Down Expand Up @@ -238,7 +238,7 @@ private object ReadAndConvertPrimitive(bool overrideArchCheck, Type type)
}
finally
{
PositionShiftLock.Exit();
ReleaseLock();
}
}

Expand All @@ -254,7 +254,7 @@ public virtual string ReadStringToNull(long offset)
}
finally
{
PositionShiftLock.Exit();
ReleaseLock();
}
}

Expand Down Expand Up @@ -293,7 +293,7 @@ public byte[] ReadByteArrayAtRawAddress(long offset, int count)
}
finally
{
PositionShiftLock.Exit();
ReleaseLock();
}
}

Expand Down Expand Up @@ -349,7 +349,7 @@ public ulong[] ReadNUintArrayAtRawAddress(long offset, int count)
}
finally
{
PositionShiftLock.Exit();
ReleaseLock();

var bytesRead = count * (int) PointerSize;
TrackRead<ulong>(bytesRead, false);
Expand Down Expand Up @@ -418,7 +418,7 @@ protected void WriteWord(int position, long word)
}
finally
{
PositionShiftLock.Exit();
ReleaseLock();
}
}

Expand All @@ -442,7 +442,7 @@ protected void WriteWord(int position, long word)
var bytesRead = (int) (Position - initialPos);
TrackRead<T>(bytesRead, trackIfFinishedReading: true);

PositionShiftLock.Exit();
ReleaseLock();
}
}

Expand All @@ -454,24 +454,36 @@ protected void WriteWord(int position, long word)

if (offset != -1)
Position = offset;

try
{
//This handles the actual reading into the array, and tracking read counts, for us.
FillReadableArrayHereNoLock(t);
}
finally
{
ReleaseLock();
}

return t;
}

public void FillReadableArrayHereNoLock<T>(T[] array, int startOffset = 0) where T : ReadableClass, new()
{
var initialPos = Position;

try
{
for (var i = 0; i < count; i++)
var i = startOffset;
for (; i < array.Length; i++)
{
t[i] = InternalReadReadableClass<T>();
array[i] = InternalReadReadableClass<T>();
}

return t;
}
finally
{
var bytesRead = (int) (Position - initialPos);
TrackRead<T>(bytesRead, trackIfFinishedReading: true);

PositionShiftLock.Exit();
}
}

Expand Down
4 changes: 3 additions & 1 deletion LibCpp2IL/Elf/ElfDynamicSymbol32.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
{
public class ElfDynamicSymbol32 : ReadableClass, IElfDynamicSymbol
{
public const int StructSize = 16;

private uint _internalNameIndex;
private uint _internalValue;
private uint _internalSize;
Expand All @@ -27,4 +29,4 @@ public override void Read(ClassReadingBinaryReader reader)
_internalShndx = reader.ReadUInt16();
}
}
}
}
4 changes: 3 additions & 1 deletion LibCpp2IL/Elf/ElfDynamicSymbol64.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
{
public class ElfDynamicSymbol64 : ReadableClass, IElfDynamicSymbol
{
public const int StructSize = 24;

//Slightly reorganized for alignment reasons.
private uint _internalNameIndex;
private byte _internalInfo;
Expand Down Expand Up @@ -29,4 +31,4 @@ public override void Read(ClassReadingBinaryReader reader)
_internalSize = reader.ReadUInt64();
}
}
}
}
2 changes: 1 addition & 1 deletion LibCpp2IL/Elf/ElfFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ private void ProcessRelocations()
}
}

var sizeOfRelocationStruct = (ulong) (is32Bit ? LibCpp2ILUtils.VersionAwareSizeOf(typeof(ElfDynamicSymbol32), true, false) : LibCpp2ILUtils.VersionAwareSizeOf(typeof(ElfDynamicSymbol64), true, false));
var sizeOfRelocationStruct = (ulong) (is32Bit ? ElfDynamicSymbol32.StructSize : ElfDynamicSymbol64.StructSize);

LibLogger.Verbose($"\t-Now Processing {rels.Count} relocations...");

Expand Down
1 change: 0 additions & 1 deletion LibCpp2IL/LibCpp2IlMain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ public class LibCpp2IlSettings
public static void Reset()
{
LibCpp2IlGlobalMapper.Reset();
LibCpp2ILUtils.Reset();
MethodsByPtr.Clear();
}

Expand Down
Loading

0 comments on commit 5fa8ddd

Please sign in to comment.