上传新的package

This commit is contained in:
2025-04-11 10:35:10 +08:00
parent 2511dc60dc
commit f7e101d56e
290 changed files with 195 additions and 170 deletions

View File

@@ -1,19 +0,0 @@
{
"versions": [
{
"unity_version":"2020",
"hybridclr" : { "branch":"v4.0.10"},
"il2cpp_plus": { "branch":"v2020-4.0.8"}
},
{
"unity_version":"2021",
"hybridclr" : { "branch":"v4.0.10"},
"il2cpp_plus": { "branch":"v2021-4.0.8"}
},
{
"unity_version":"2022",
"hybridclr" : { "branch":"v4.0.10"},
"il2cpp_plus": { "branch":"v2022-4.0.8"}
}
]
}

View File

@@ -1,12 +0,0 @@
fileFormatVersion: 2
<<<<<<<< HEAD:Assets/05.TableTextConversion/RunTime/Abstract.meta
guid: 3f4958b2707b1874fb59e045842881b7
========
guid: c3fabc41cf17c444995fc01a76c5dbe6
>>>>>>>> 00.StaryEvo:Packages/com.code-philosophy.hybridclr/Editor.meta
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: daa1e09af240aae4da0741843cb2b3f3
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 13fe0cab0b357464d889de45c8d98850
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,320 +0,0 @@
using DotNetDetour;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
namespace MonoHook
{
public unsafe abstract class CodePatcher
{
public bool isValid { get; protected set; }
protected void* _pTarget, _pReplace, _pProxy;
protected int _jmpCodeSize;
protected byte[] _targetHeaderBackup;
public CodePatcher(IntPtr target, IntPtr replace, IntPtr proxy, int jmpCodeSize)
{
_pTarget = target.ToPointer();
_pReplace = replace.ToPointer();
_pProxy = proxy.ToPointer();
_jmpCodeSize = jmpCodeSize;
}
public void ApplyPatch()
{
BackupHeader();
EnableAddrModifiable();
PatchTargetMethod();
PatchProxyMethod();
FlushICache();
}
public void RemovePatch()
{
if (_targetHeaderBackup == null)
return;
EnableAddrModifiable();
RestoreHeader();
FlushICache();
}
protected void BackupHeader()
{
if (_targetHeaderBackup != null)
return;
uint requireSize = LDasm.SizeofMinNumByte(_pTarget, _jmpCodeSize);
_targetHeaderBackup = new byte[requireSize];
fixed (void* ptr = _targetHeaderBackup)
HookUtils.MemCpy(ptr, _pTarget, _targetHeaderBackup.Length);
}
protected void RestoreHeader()
{
if (_targetHeaderBackup == null)
return;
HookUtils.MemCpy_Jit(_pTarget, _targetHeaderBackup);
}
protected void PatchTargetMethod()
{
byte[] buff = GenJmpCode(_pTarget, _pReplace);
HookUtils.MemCpy_Jit(_pTarget, buff);
}
protected void PatchProxyMethod()
{
if (_pProxy == null)
return;
// copy target's code to proxy
HookUtils.MemCpy_Jit(_pProxy, _targetHeaderBackup);
// jmp to target's new position
long jmpFrom = (long)_pProxy + _targetHeaderBackup.Length;
long jmpTo = (long)_pTarget + _targetHeaderBackup.Length;
byte[] buff = GenJmpCode((void*)jmpFrom, (void*)jmpTo);
HookUtils.MemCpy_Jit((void*)jmpFrom, buff);
}
protected void FlushICache()
{
HookUtils.FlushICache(_pTarget, _targetHeaderBackup.Length);
HookUtils.FlushICache(_pProxy, _targetHeaderBackup.Length * 2);
}
protected abstract byte[] GenJmpCode(void* jmpFrom, void* jmpTo);
#if ENABLE_HOOK_DEBUG
protected string PrintAddrs()
{
if (IntPtr.Size == 4)
return $"target:0x{(uint)_pTarget:x}, replace:0x{(uint)_pReplace:x}, proxy:0x{(uint)_pProxy:x}";
else
return $"target:0x{(ulong)_pTarget:x}, replace:0x{(ulong)_pReplace:x}, proxy:0x{(ulong)_pProxy:x}";
}
#endif
private void EnableAddrModifiable()
{
HookUtils.SetAddrFlagsToRWX(new IntPtr(_pTarget), _targetHeaderBackup.Length);
HookUtils.SetAddrFlagsToRWX(new IntPtr(_pProxy), _targetHeaderBackup.Length + _jmpCodeSize);
}
}
public unsafe class CodePatcher_x86 : CodePatcher
{
protected static readonly byte[] s_jmpCode = new byte[] // 5 bytes
{
0xE9, 0x00, 0x00, 0x00, 0x00, // jmp $val ; $val = $dst - $src - 5
};
public CodePatcher_x86(IntPtr target, IntPtr replace, IntPtr proxy) : base(target, replace, proxy, s_jmpCode.Length) { }
protected override unsafe byte[] GenJmpCode(void* jmpFrom, void* jmpTo)
{
byte[] ret = new byte[s_jmpCode.Length];
int val = (int)jmpTo - (int)jmpFrom - 5;
fixed(void * p = &ret[0])
{
byte* ptr = (byte*)p;
*ptr = 0xE9;
int* pOffset = (int*)(ptr + 1);
*pOffset = val;
}
return ret;
}
}
/// <summary>
/// x64下2G 内的跳转
/// </summary>
public unsafe class CodePatcher_x64_near : CodePatcher_x86 // x64_near pathcer code is same to x86
{
public CodePatcher_x64_near(IntPtr target, IntPtr replace, IntPtr proxy) : base(target, replace, proxy) { }
}
/// <summary>
/// x64下距离超过2G的跳转
/// </summary>
public unsafe class CodePatcher_x64_far : CodePatcher
{
protected static readonly byte[] s_jmpCode = new byte[] // 12 bytes
{
// 由于 rax 会被函数作为返回值修改,并且不会被做为参数使用,因此修改是安全的
0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov rax, <jmpTo>
0x50, // push rax
0xC3 // ret
};
//protected static readonly byte[] s_jmpCode2 = new byte[] // 14 bytes
//{
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // <jmpTo>
// 0xFF, 0x25, 0xF2, 0xFF, 0xFF, 0xFF // jmp [rip - 0xe]
//};
public CodePatcher_x64_far(IntPtr target, IntPtr replace, IntPtr proxy) : base(target, replace, proxy, s_jmpCode.Length) { }
protected override unsafe byte[] GenJmpCode(void* jmpFrom, void* jmpTo)
{
byte[] ret = new byte[s_jmpCode.Length];
fixed (void* p = &ret[0])
{
byte* ptr = (byte*)p;
*ptr++ = 0x48;
*ptr++ = 0xB8;
*(long*)ptr = (long)jmpTo;
ptr += 8;
*ptr++ = 0x50;
*ptr++ = 0xC3;
}
return ret;
}
}
public unsafe class CodePatcher_arm32_near : CodePatcher
{
private static readonly byte[] s_jmpCode = new byte[] // 4 bytes
{
0x00, 0x00, 0x00, 0xEA, // B $val ; $val = (($dst - $src) / 4 - 2) & 0x1FFFFFF
};
public CodePatcher_arm32_near(IntPtr target, IntPtr replace, IntPtr proxy) : base(target, replace, proxy, s_jmpCode.Length)
{
if (Math.Abs((long)target - (long)replace) >= ((1 << 25) - 1))
throw new ArgumentException("address offset of target and replace must less than ((1 << 25) - 1)");
#if ENABLE_HOOK_DEBUG
Debug.Log($"CodePatcher_arm32_near: {PrintAddrs()}");
#endif
}
protected override unsafe byte[] GenJmpCode(void* jmpFrom, void* jmpTo)
{
byte[] ret = new byte[s_jmpCode.Length];
int val = ((int)jmpTo - (int)jmpFrom) / 4 - 2;
fixed (void* p = &ret[0])
{
byte* ptr = (byte*)p;
*ptr++ = (byte)val;
*ptr++ = (byte)(val >> 8);
*ptr++ = (byte)(val >> 16);
*ptr++ = 0xEA;
}
return ret;
}
}
public unsafe class CodePatcher_arm32_far : CodePatcher
{
private static readonly byte[] s_jmpCode = new byte[] // 8 bytes
{
0x04, 0xF0, 0x1F, 0xE5, // LDR PC, [PC, #-4]
0x00, 0x00, 0x00, 0x00, // $val
};
public CodePatcher_arm32_far(IntPtr target, IntPtr replace, IntPtr proxy) : base(target, replace, proxy, s_jmpCode.Length)
{
if (Math.Abs((long)target - (long)replace) < ((1 << 25) - 1))
throw new ArgumentException("address offset of target and replace must larger than ((1 << 25) - 1), please use InstructionModifier_arm32_near instead");
#if ENABLE_HOOK_DEBUG
Debug.Log($"CodePatcher_arm32_far: {PrintAddrs()}");
#endif
}
protected override unsafe byte[] GenJmpCode(void* jmpFrom, void* jmpTo)
{
byte[] ret = new byte[s_jmpCode.Length];
fixed (void* p = &ret[0])
{
uint* ptr = (uint*)p;
*ptr++ = 0xE51FF004;
*ptr = (uint)jmpTo;
}
return ret;
}
}
/// <summary>
/// arm64 下 ±128MB 范围内的跳转
/// </summary>
public unsafe class CodePatcher_arm64_near : CodePatcher
{
private static readonly byte[] s_jmpCode = new byte[] // 4 bytes
{
/*
* from 0x14 to 0x17 is B opcode
* offset bits is 26
* https://developer.arm.com/documentation/ddi0596/2021-09/Base-Instructions/B--Branch-
*/
0x00, 0x00, 0x00, 0x14, // B $val ; $val = (($dst - $src)/4) & 7FFFFFF
};
public CodePatcher_arm64_near(IntPtr target, IntPtr replace, IntPtr proxy) : base(target, replace, proxy, s_jmpCode.Length)
{
if (Math.Abs((long)target - (long)replace) >= ((1 << 26) - 1) * 4)
throw new ArgumentException("address offset of target and replace must less than (1 << 26) - 1) * 4");
#if ENABLE_HOOK_DEBUG
Debug.Log($"CodePatcher_arm64: {PrintAddrs()}");
#endif
}
protected override unsafe byte[] GenJmpCode(void* jmpFrom, void* jmpTo)
{
byte[] ret = new byte[s_jmpCode.Length];
int val = (int)((long)jmpTo - (long)jmpFrom) / 4;
fixed (void* p = &ret[0])
{
byte* ptr = (byte*)p;
*ptr++ = (byte)val;
*ptr++ = (byte)(val >> 8);
*ptr++ = (byte)(val >> 16);
byte last = (byte)(val >> 24);
last &= 0b11;
last |= 0x14;
*ptr = last;
}
return ret;
}
}
/// <summary>
/// arm64 远距离跳转
/// </summary>
public unsafe class CodePatcher_arm64_far : CodePatcher
{
private static readonly byte[] s_jmpCode = new byte[] // 20 bytes(字节数过多,太危险了,不建议使用)
{
/*
* ADR: https://developer.arm.com/documentation/ddi0596/2021-09/Base-Instructions/ADR--Form-PC-relative-address-
* BR: https://developer.arm.com/documentation/ddi0596/2021-09/Base-Instructions/BR--Branch-to-Register-
*/
0x6A, 0x00, 0x00, 0x10, // ADR X10, #C
0x4A, 0x01, 0x40, 0xF9, // LDR X10, [X10,#0]
0x40, 0x01, 0x1F, 0xD6, // BR X10
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // $dst
};
public CodePatcher_arm64_far(IntPtr target, IntPtr replace, IntPtr proxy, int jmpCodeSize) : base(target, replace, proxy, jmpCodeSize)
{
}
protected override unsafe byte[] GenJmpCode(void* jmpFrom, void* jmpTo)
{
throw new NotImplementedException();
}
}
}

View File

@@ -1,15 +0,0 @@
fileFormatVersion: 2
<<<<<<<< HEAD:Assets/04.AudioCore/RunTime/Abstract/IAudio.cs.meta
guid: a45ad70b96df7ae428058f547876d158
========
guid: 97cc0d26f72fc4148b8370b2252d1585
>>>>>>>> 00.StaryEvo:Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/CodePatcher.cs.meta
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,74 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
using System.Linq;
using System.IO;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace MonoHook
{
/// <summary>
/// Hook 池,防止重复 Hook
/// </summary>
public static class HookPool
{
private static Dictionary<MethodBase, MethodHook> _hooks = new Dictionary<MethodBase, MethodHook>();
public static void AddHook(MethodBase method, MethodHook hook)
{
MethodHook preHook;
if (_hooks.TryGetValue(method, out preHook))
{
preHook.Uninstall();
_hooks[method] = hook;
}
else
_hooks.Add(method, hook);
}
public static MethodHook GetHook(MethodBase method)
{
if (method == null) return null;
MethodHook hook;
if (_hooks.TryGetValue(method, out hook))
return hook;
return null;
}
public static void RemoveHooker(MethodBase method)
{
if (method == null) return;
_hooks.Remove(method);
}
public static void UninstallAll()
{
var list = _hooks.Values.ToList();
foreach (var hook in list)
hook.Uninstall();
_hooks.Clear();
}
public static void UninstallByTag(string tag)
{
var list = _hooks.Values.ToList();
foreach (var hook in list)
{
if(hook.tag == tag)
hook.Uninstall();
}
}
public static List<MethodHook> GetAllHooks()
{
return _hooks.Values.ToList();
}
}
}

View File

@@ -1,15 +0,0 @@
fileFormatVersion: 2
<<<<<<<< HEAD:Assets/04.AudioCore/RunTime/Base/AudioSourcePool.cs.meta
guid: b0879cbfda12f434f97c3e393664b7ec
========
guid: 6b7421e47f0ae1e4ebb72bf18d1d7d48
>>>>>>>> 00.StaryEvo:Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HookPool.cs.meta
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,272 +0,0 @@
#if !(UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX)
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using UnityEngine;
namespace MonoHook
{
public static unsafe class HookUtils
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate void DelegateFlushICache(void* code, int size); // delegate * unmanaged[Cdecl] <void, byte, uint> native_flush_cache_fun_ptr; // unsupported at C# 8.0
static DelegateFlushICache flush_icache;
private static readonly long _Pagesize;
static HookUtils()
{
PropertyInfo p_SystemPageSize = typeof(Environment).GetProperty("SystemPageSize");
if (p_SystemPageSize == null)
throw new NotSupportedException("Unsupported runtime");
_Pagesize = (int)p_SystemPageSize.GetValue(null, new object[0]);
SetupFlushICacheFunc();
}
public static void MemCpy(void* pDst, void* pSrc, int len)
{
byte* pDst_ = (byte*)pDst;
byte* pSrc_ = (byte*)pSrc;
for (int i = 0; i < len; i++)
*pDst_++ = *pSrc_++;
}
public static void MemCpy_Jit(void* pDst, byte[] src)
{
fixed (void* p = &src[0])
{
MemCpy(pDst, p, src.Length);
}
}
/// <summary>
/// set flags of address to `read write execute`
/// </summary>
public static void SetAddrFlagsToRWX(IntPtr ptr, int size)
{
if (ptr == IntPtr.Zero)
return;
#if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN
uint oldProtect;
bool ret = VirtualProtect(ptr, (uint)size, Protection.PAGE_EXECUTE_READWRITE, out oldProtect);
UnityEngine.Debug.Assert(ret);
#else
SetMemPerms(ptr,(ulong)size,MmapProts.PROT_READ | MmapProts.PROT_WRITE | MmapProts.PROT_EXEC);
#endif
}
public static void FlushICache(void* code, int size)
{
if (code == null)
return;
flush_icache?.Invoke(code, size);
#if ENABLE_HOOK_DEBUG
Debug.Log($"flush icache at 0x{(IntPtr.Size == 4 ? (uint)code : (ulong)code):x}, size:{size}");
#endif
}
public static KeyValuePair<long, long> GetPageAlignedAddr(long code, int size)
{
long pagesize = _Pagesize;
long startPage = (code) & ~(pagesize - 1);
long endPage = (code + size + pagesize - 1) & ~(pagesize - 1);
return new KeyValuePair<long, long>(startPage, endPage);
}
const int PRINT_SPLIT = 4;
const int PRINT_COL_SIZE = PRINT_SPLIT * 4;
public static string HexToString(void* ptr, int size, int offset = 0)
{
Func<IntPtr, string> formatAddr = (IntPtr addr__) => IntPtr.Size == 4 ? $"0x{(uint)addr__:x}" : $"0x{(ulong)addr__:x}";
byte* addr = (byte*)ptr;
StringBuilder sb = new StringBuilder(1024);
sb.AppendLine($"addr:{formatAddr(new IntPtr(addr))}");
addr += offset;
size += Math.Abs(offset);
int count = 0;
while (true)
{
sb.Append($"\r\n{formatAddr(new IntPtr(addr + count))}: ");
for (int i = 1; i < PRINT_COL_SIZE + 1; i++)
{
if (count >= size)
goto END;
sb.Append($"{*(addr + count):x2}");
if (i % PRINT_SPLIT == 0)
sb.Append(" ");
count++;
}
}
END:;
return sb.ToString();
}
static void SetupFlushICacheFunc()
{
string processorType = SystemInfo.processorType;
if (processorType.Contains("Intel") || processorType.Contains("AMD"))
return;
if (IntPtr.Size == 4)
{
// never release, so save GCHandle is unnecessary
s_ptr_flush_icache_arm32 = GCHandle.Alloc(s_flush_icache_arm32, GCHandleType.Pinned).AddrOfPinnedObject().ToPointer();
SetAddrFlagsToRWX(new IntPtr(s_ptr_flush_icache_arm32), s_flush_icache_arm32.Length);
flush_icache = Marshal.GetDelegateForFunctionPointer<DelegateFlushICache>(new IntPtr(s_ptr_flush_icache_arm32));
}
else
{
s_ptr_flush_icache_arm64 = GCHandle.Alloc(s_flush_icache_arm64, GCHandleType.Pinned).AddrOfPinnedObject().ToPointer();
SetAddrFlagsToRWX(new IntPtr(s_ptr_flush_icache_arm64), s_flush_icache_arm64.Length);
flush_icache = Marshal.GetDelegateForFunctionPointer<DelegateFlushICache>(new IntPtr(s_ptr_flush_icache_arm64));
}
#if ENABLE_HOOK_DEBUG
Debug.Log($"flush_icache delegate is {((flush_icache != null) ? "not " : "")}null");
#endif
}
static void* s_ptr_flush_icache_arm32, s_ptr_flush_icache_arm64;
private static byte[] s_flush_icache_arm32 = new byte[]
{
// void cdecl mono_arch_flush_icache (guint8 *code, gint size)
0x00, 0x48, 0x2D, 0xE9, // PUSH {R11,LR}
0x0D, 0xB0, 0xA0, 0xE1, // MOV R11, SP
0x08, 0xD0, 0x4D, 0xE2, // SUB SP, SP, #8
0x04, 0x00, 0x8D, 0xE5, // STR R0, [SP,#8+var_4]
0x00, 0x10, 0x8D, 0xE5, // STR R1, [SP,#8+var_8]
0x04, 0x00, 0x9D, 0xE5, // LDR R0, [SP,#8+var_4]
0x04, 0x10, 0x9D, 0xE5, // LDR R1, [SP,#8+var_4]
0x00, 0x20, 0x9D, 0xE5, // LDR R2, [SP,#8+var_8]
0x02, 0x10, 0x81, 0xE0, // ADD R1, R1, R2
0x01, 0x00, 0x00, 0xEB, // BL __clear_cache
0x0B, 0xD0, 0xA0, 0xE1, // MOV SP, R11
0x00, 0x88, 0xBD, 0xE8, // POP {R11,PC}
// __clear_cache ; CODE XREF: j___clear_cache+8↑j
0x80, 0x00, 0x2D, 0xE9, // PUSH { R7 }
0x02, 0x70, 0x00, 0xE3, 0x0F, 0x70, 0x40, 0xE3, // MOV R7, #0xF0002
0x00, 0x20, 0xA0, 0xE3, // MOV R2, #0
0x00, 0x00, 0x00, 0xEF, // SVC 0
0x80, 0x00, 0xBD, 0xE8, // POP {R7}
0x1E, 0xFF, 0x2F, 0xE1, // BX LR
};
private static byte[] s_flush_icache_arm64 = new byte[] // X0: code, W1: size
{
// void cdecl mono_arch_flush_icache (guint8 *code, gint size)
0xFF, 0xC3, 0x00, 0xD1, // SUB SP, SP, #0x30
0xE8, 0x03, 0x7E, 0xB2, // MOV X8, #4
0xE0, 0x17, 0x00, 0xF9, // STR X0, [SP,#0x30+var_8]
0xE1, 0x27, 0x00, 0xB9, // STR W1, [SP,#0x30+var_C]
0xE0, 0x17, 0x40, 0xF9, // LDR X0, [SP,#0x30+var_8]
0xE9, 0x27, 0x80, 0xB9, // LDRSW X9, [SP,#0x30+var_C]
0x09, 0x00, 0x09, 0x8B, // ADD X9, X0, X9
0xE9, 0x0F, 0x00, 0xF9, // STR X9, [SP,#0x30+var_18]
0xE8, 0x07, 0x00, 0xF9, // STR X8, [SP,#0x30+var_28]
0xE8, 0x03, 0x00, 0xF9, // STR X8, [SP,#0x30+var_30]
0xE8, 0x17, 0x40, 0xF9, // LDR X8, [SP,#0x30+var_8]
0x08, 0xF5, 0x7E, 0x92, // AND X8, X8, #0xFFFFFFFFFFFFFFFC
0xE8, 0x0B, 0x00, 0xF9, // STR X8, [SP,#0x30+var_20]
// loc_590 ; CODE XREF: mono_arch_flush_icache(uchar*, int)+58↓j
0xE8, 0x0B, 0x40, 0xF9, // LDR X8, [SP,#0x30+var_20]
0xE9, 0x0F, 0x40, 0xF9, // LDR X9, [SP,#0x30+var_18]
0x1F, 0x01, 0x09, 0xEB, // CMP X8, X9
0xE2, 0x00, 0x00, 0x54, // B.CS loc_5B8
0xE8, 0x0B, 0x40, 0xF9, // LDR X8, [SP,#0x30+var_20]
0x28, 0x7E, 0x0B, 0xD5, // SYS #3, c7, c14, #1, X8
0xE8, 0x0B, 0x40, 0xF9, // LDR X8, [SP,#0x30+var_20]
0x08, 0x11, 0x00, 0x91, // ADD X8, X8, #4
0xE8, 0x0B, 0x00, 0xF9, // STR X8, [SP,#0x30+var_20]
0xF7, 0xFF, 0xFF, 0x17, // B loc_590
// ; ---------------------------------------------------------------------------
// loc_5B8 ; CODE XREF: mono_arch_flush_icache(uchar *, int)+40↑j
0x9F, 0x3B, 0x03, 0xD5, // DSB ISH
0xE8, 0x17, 0x40, 0xF9, // LDR X8, [SP,#0x30+var_8]
0x08, 0xF5, 0x7E, 0x92, // AND X8, X8, #0xFFFFFFFFFFFFFFFC
0xE8, 0x0B, 0x00, 0xF9, // STR X8, [SP,#0x30+var_20]
// loc_5C8 ; CODE XREF: mono_arch_flush_icache(uchar *, int)+90↓j
0xE8, 0x0B, 0x40, 0xF9, // LDR X8, [SP,#0x30+var_20]
0xE9, 0x0F, 0x40, 0xF9, // LDR X9, [SP,#0x30+var_18]
0x1F, 0x01, 0x09, 0xEB, // CMP X8, X9
0xE2, 0x00, 0x00, 0x54, // B.CS loc_5F0
0xE8, 0x0B, 0x40, 0xF9, // LDR X8, [SP,#0x30+var_20]
0x28, 0x75, 0x0B, 0xD5, // SYS #3, c7, c5, #1, X8
0xE8, 0x0B, 0x40, 0xF9, // LDR X8, [SP,#0x30+var_20]
0x08, 0x11, 0x00, 0x91, // ADD X8, X8, #4
0xE8, 0x0B, 0x00, 0xF9, // STR X8, [SP,#0x30+var_20]
0xF7, 0xFF, 0xFF, 0x17, // B loc_5C8
// ; ---------------------------------------------------------------------------
// loc_5F0 ; CODE XREF: mono_arch_flush_icache(uchar *, int)+78↑j
0x9F, 0x3B, 0x03, 0xD5, // DSB ISH
0xDF, 0x3F, 0x03, 0xD5, // ISB
0xFF, 0xC3, 0x00, 0x91, // ADD SP, SP, #0x30 ; '0'
0xC0, 0x03, 0x5F, 0xD6, // RET
};
#if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN
[Flags]
public enum Protection
{
PAGE_NOACCESS = 0x01,
PAGE_READONLY = 0x02,
PAGE_READWRITE = 0x04,
PAGE_WRITECOPY = 0x08,
PAGE_EXECUTE = 0x10,
PAGE_EXECUTE_READ = 0x20,
PAGE_EXECUTE_READWRITE = 0x40,
PAGE_EXECUTE_WRITECOPY = 0x80,
PAGE_GUARD = 0x100,
PAGE_NOCACHE = 0x200,
PAGE_WRITECOMBINE = 0x400
}
[DllImport("kernel32")]
public static extern bool VirtualProtect(IntPtr lpAddress, uint dwSize, Protection flNewProtect, out uint lpflOldProtect);
#else
[Flags]
public enum MmapProts : int {
PROT_READ = 0x1,
PROT_WRITE = 0x2,
PROT_EXEC = 0x4,
PROT_NONE = 0x0,
PROT_GROWSDOWN = 0x01000000,
PROT_GROWSUP = 0x02000000,
}
[DllImport("libc", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
private static extern int mprotect(IntPtr start, IntPtr len, MmapProts prot);
public static unsafe void SetMemPerms(IntPtr start, ulong len, MmapProts prot) {
var requiredAddr = GetPageAlignedAddr(start.ToInt64(), (int)len);
long startPage = requiredAddr.Key;
long endPage = requiredAddr.Value;
if (mprotect((IntPtr) startPage, (IntPtr) (endPage - startPage), prot) != 0)
throw new Exception($"mprotect with prot:{prot} fail!");
}
#endif
}
}
#endif

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: e84139b42a6164e4c93ce4df1be6dcfb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,102 +0,0 @@
#if (UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX)
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using UnityEngine;
namespace MonoHook
{
public static unsafe class HookUtils
{
static bool jit_write_protect_supported;
private static readonly long _Pagesize;
static HookUtils()
{
jit_write_protect_supported = pthread_jit_write_protect_supported_np() != 0;
PropertyInfo p_SystemPageSize = typeof(Environment).GetProperty("SystemPageSize");
if (p_SystemPageSize == null)
throw new NotSupportedException("Unsupported runtime");
_Pagesize = (int)p_SystemPageSize.GetValue(null, new object[0]);
}
public static void MemCpy(void* pDst, void* pSrc, int len)
{
byte* pDst_ = (byte*)pDst;
byte* pSrc_ = (byte*)pSrc;
for (int i = 0; i < len; i++)
*pDst_++ = *pSrc_++;
}
public static void MemCpy_Jit(void* pDst, byte[] src)
{
fixed(void * p = &src[0])
{
memcpy_jit(new IntPtr(pDst), new IntPtr(p), src.Length);
}
}
/// <summary>
/// set flags of address to `read write execute`
/// </summary>
public static void SetAddrFlagsToRWX(IntPtr ptr, int size) { }
public static void FlushICache(void* code, int size) { }
public static KeyValuePair<long, long> GetPageAlignedAddr(long code, int size)
{
long pagesize = _Pagesize;
long startPage = (code) & ~(pagesize - 1);
long endPage = (code + size + pagesize - 1) & ~(pagesize - 1);
return new KeyValuePair<long, long>(startPage, endPage);
}
const int PRINT_SPLIT = 4;
const int PRINT_COL_SIZE = PRINT_SPLIT * 4;
public static string HexToString(void* ptr, int size, int offset = 0)
{
Func<IntPtr, string> formatAddr = (IntPtr addr__) => IntPtr.Size == 4 ? $"0x{(uint)addr__:x}" : $"0x{(ulong)addr__:x}";
byte* addr = (byte*)ptr;
StringBuilder sb = new StringBuilder(1024);
sb.AppendLine($"addr:{formatAddr(new IntPtr(addr))}");
addr += offset;
size += Math.Abs(offset);
int count = 0;
while (true)
{
sb.Append($"\r\n{formatAddr(new IntPtr(addr + count))}: ");
for (int i = 1; i < PRINT_COL_SIZE + 1; i++)
{
if (count >= size)
goto END;
sb.Append($"{*(addr + count):x2}");
if (i % PRINT_SPLIT == 0)
sb.Append(" ");
count++;
}
}
END:;
return sb.ToString();
}
[DllImport("pthread", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
private static extern int pthread_jit_write_protect_supported_np();
[DllImport("libMonoHookUtils_OSX", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr memcpy_jit(IntPtr dst, IntPtr src, int len);
}
}
#endif

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: efda6e010e5c6594081c4a62861d469f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: d796fc01daee1964586621890988a5ae
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,67 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
using UnityEditor;
using System.Runtime.CompilerServices;
using MonoHook;
using HybridCLR.Editor.BuildProcessors;
using System.IO;
namespace HybridCLR.MonoHook
{
#if UNITY_2021_1_OR_NEWER
[InitializeOnLoad]
public class CopyStrippedAOTAssembliesHook
{
private static MethodHook _hook;
static CopyStrippedAOTAssembliesHook()
{
if (_hook == null)
{
Type type = typeof(UnityEditor.EditorApplication).Assembly.GetType("UnityEditorInternal.AssemblyStripper");
MethodInfo miTarget = type.GetMethod("StripAssembliesTo", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
MethodInfo miReplacement = new StripAssembliesDel(OverrideStripAssembliesTo).Method;
MethodInfo miProxy = new StripAssembliesDel(StripAssembliesToProxy).Method;
_hook = new MethodHook(miTarget, miReplacement, miProxy);
_hook.Install();
}
}
private delegate bool StripAssembliesDel(string outputFolder, out string output, out string error, IEnumerable<string> linkXmlFiles, object runInformation);
private static bool OverrideStripAssembliesTo(string outputFolder, out string output, out string error, IEnumerable<string> linkXmlFiles, object runInformation)
{
bool result = StripAssembliesToProxy(outputFolder, out output, out error, linkXmlFiles, runInformation);
if (!result)
{
return false;
}
UnityEngine.Debug.Log($"== StripAssembliesTo outputDir:{outputFolder}");
string outputStrippedDir = HybridCLR.Editor.SettingsUtil.GetAssembliesPostIl2CppStripDir(EditorUserBuildSettings.activeBuildTarget);
Directory.CreateDirectory(outputStrippedDir);
foreach (var aotDll in Directory.GetFiles(outputFolder, "*.dll"))
{
string dstFile = $"{outputStrippedDir}/{Path.GetFileName(aotDll)}";
Debug.Log($"[RunAssemblyStripper] copy aot dll {aotDll} -> {dstFile}");
File.Copy(aotDll, dstFile, true);
}
return result;
}
[MethodImpl(MethodImplOptions.NoOptimization)]
private static bool StripAssembliesToProxy(string outputFolder, out string output, out string error, IEnumerable<string> linkXmlFiles, object runInformation)
{
Debug.LogError("== StripAssembliesToProxy ==");
output = "";
error = "";
return true;
}
}
#endif
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: cf42c4f20b8a1b94baa04a1a5c6b8beb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,56 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
using UnityEditor;
using System.Runtime.CompilerServices;
using MonoHook;
using HybridCLR.Editor.BuildProcessors;
using System.IO;
namespace HybridCLR.MonoHook
{
#if UNITY_2022
[InitializeOnLoad]
public class GetIl2CppFolderHook
{
private static MethodHook _hook;
static GetIl2CppFolderHook()
{
if (_hook == null)
{
Type type = typeof(UnityEditor.EditorApplication).Assembly.GetType("UnityEditorInternal.IL2CPPUtils");
MethodInfo miTarget = type.GetMethod("GetIl2CppFolder", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, null,
new Type[] { typeof(bool).MakeByRefType() }, null);
MethodInfo miReplacement = new StripAssembliesDel(OverrideMethod).Method;
MethodInfo miProxy = new StripAssembliesDel(PlaceHolderMethod).Method;
_hook = new MethodHook(miTarget, miReplacement, miProxy);
_hook.Install();
}
}
private delegate string StripAssembliesDel(out bool isDevelopmentLocation);
private static string OverrideMethod(out bool isDevelopmentLocation)
{
//Debug.Log("[GetIl2CppFolderHook] OverrideMethod");
string result = PlaceHolderMethod(out isDevelopmentLocation);
isDevelopmentLocation = false;
return result;
}
[MethodImpl(MethodImplOptions.NoOptimization)]
private static string PlaceHolderMethod(out bool isDevelopmentLocation)
{
Debug.LogError("[GetIl2CppFolderHook] PlaceHolderMethod");
isDevelopmentLocation = false;
return null;
}
}
#endif
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 96c2bc28db69e1644892219abef3d4b5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,57 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
using UnityEditor;
using System.Runtime.CompilerServices;
using MonoHook;
using HybridCLR.Editor.BuildProcessors;
using System.IO;
namespace HybridCLR.MonoHook
{
#if UNITY_2021_1_OR_NEWER && UNITY_WEBGL
[InitializeOnLoad]
public class PatchScriptingAssembliesJsonHook
{
private static MethodHook _hook;
static PatchScriptingAssembliesJsonHook()
{
if (_hook == null)
{
Type type = typeof(UnityEditor.EditorApplication);
MethodInfo miTarget = type.GetMethod("BuildMainWindowTitle", BindingFlags.Static | BindingFlags.NonPublic);
MethodInfo miReplacement = new Func<string>(BuildMainWindowTitle).Method;
MethodInfo miProxy = new Func<string>(BuildMainWindowTitleProxy).Method;
_hook = new MethodHook(miTarget, miReplacement, miProxy);
_hook.Install();
}
}
private static string BuildMainWindowTitle()
{
string tempJsonPath = $"{Application.dataPath}/../Library/PlayerDataCache/WebGL/Data/ScriptingAssemblies.json";
if (File.Exists(tempJsonPath))
{
var patcher = new PatchScriptingAssemblyList();
patcher.PathScriptingAssembilesFile(Path.GetDirectoryName(tempJsonPath));
}
string newTitle = BuildMainWindowTitleProxy();
return newTitle;
}
[MethodImpl(MethodImplOptions.NoOptimization)]
private static string BuildMainWindowTitleProxy()
{
// 为满足MonoHook要求的最小代码长度而特地加入的无用填充代码
UnityEngine.Debug.Log(12345.ToString());
return string.Empty;
}
}
#endif
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: cc89a9041ab48ac41975fbd1e00b9b98
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,903 +0,0 @@
using System;
using System.Runtime.InteropServices;
namespace DotNetDetour
{
/// <summary>
/// 用于计算汇编指令长度使用的是BlackBone的LDasm.c中的算法我把他翻译成C#了
/// </summary>
public unsafe class LDasm
{
const int F_INVALID = 0x01;
const int F_PREFIX = 0x02;
const int F_REX = 0x04;
const int F_MODRM = 0x08;
const int F_SIB = 0x10;
const int F_DISP = 0x20;
const int F_IMM = 0x40;
const int F_RELATIVE = 0x80;
const int OP_NONE = 0x00;
const int OP_INVALID = 0x80;
const int OP_DATA_I8 = 0x01;
const int OP_DATA_I16 = 0x02;
const int OP_DATA_I16_I32 = 0x04;
const int OP_DATA_I16_I32_I64 = 0x08;
const int OP_EXTENDED = 0x10;
const int OP_RELATIVE = 0x20;
const int OP_MODRM = 0x40;
const int OP_PREFIX = 0x80;
struct ldasm_data
{
public byte flags;
public byte rex;
public byte modrm;
public byte sib;
public byte opcd_offset;
public byte opcd_size;
public byte disp_offset;
public byte disp_size;
public byte imm_offset;
public byte imm_size;
}
static byte[] flags_table =
{
/* 00 */ OP_MODRM,
/* 01 */ OP_MODRM,
/* 02 */ OP_MODRM,
/* 03 */ OP_MODRM,
/* 04 */ OP_DATA_I8,
/* 05 */ OP_DATA_I16_I32,
/* 06 */ OP_NONE,
/* 07 */ OP_NONE,
/* 08 */ OP_MODRM,
/* 09 */ OP_MODRM,
/* 0A */ OP_MODRM,
/* 0B */ OP_MODRM,
/* 0C */ OP_DATA_I8,
/* 0D */ OP_DATA_I16_I32,
/* 0E */ OP_NONE,
/* 0F */ OP_NONE,
/* 10 */ OP_MODRM,
/* 11 */ OP_MODRM,
/* 12 */ OP_MODRM,
/* 13 */ OP_MODRM,
/* 14 */ OP_DATA_I8,
/* 15 */ OP_DATA_I16_I32,
/* 16 */ OP_NONE,
/* 17 */ OP_NONE,
/* 18 */ OP_MODRM,
/* 19 */ OP_MODRM,
/* 1A */ OP_MODRM,
/* 1B */ OP_MODRM,
/* 1C */ OP_DATA_I8,
/* 1D */ OP_DATA_I16_I32,
/* 1E */ OP_NONE,
/* 1F */ OP_NONE,
/* 20 */ OP_MODRM,
/* 21 */ OP_MODRM,
/* 22 */ OP_MODRM,
/* 23 */ OP_MODRM,
/* 24 */ OP_DATA_I8,
/* 25 */ OP_DATA_I16_I32,
/* 26 */ OP_PREFIX,
/* 27 */ OP_NONE,
/* 28 */ OP_MODRM,
/* 29 */ OP_MODRM,
/* 2A */ OP_MODRM,
/* 2B */ OP_MODRM,
/* 2C */ OP_DATA_I8,
/* 2D */ OP_DATA_I16_I32,
/* 2E */ OP_PREFIX,
/* 2F */ OP_NONE,
/* 30 */ OP_MODRM,
/* 31 */ OP_MODRM,
/* 32 */ OP_MODRM,
/* 33 */ OP_MODRM,
/* 34 */ OP_DATA_I8,
/* 35 */ OP_DATA_I16_I32,
/* 36 */ OP_PREFIX,
/* 37 */ OP_NONE,
/* 38 */ OP_MODRM,
/* 39 */ OP_MODRM,
/* 3A */ OP_MODRM,
/* 3B */ OP_MODRM,
/* 3C */ OP_DATA_I8,
/* 3D */ OP_DATA_I16_I32,
/* 3E */ OP_PREFIX,
/* 3F */ OP_NONE,
/* 40 */ OP_NONE,
/* 41 */ OP_NONE,
/* 42 */ OP_NONE,
/* 43 */ OP_NONE,
/* 44 */ OP_NONE,
/* 45 */ OP_NONE,
/* 46 */ OP_NONE,
/* 47 */ OP_NONE,
/* 48 */ OP_NONE,
/* 49 */ OP_NONE,
/* 4A */ OP_NONE,
/* 4B */ OP_NONE,
/* 4C */ OP_NONE,
/* 4D */ OP_NONE,
/* 4E */ OP_NONE,
/* 4F */ OP_NONE,
/* 50 */ OP_NONE,
/* 51 */ OP_NONE,
/* 52 */ OP_NONE,
/* 53 */ OP_NONE,
/* 54 */ OP_NONE,
/* 55 */ OP_NONE,
/* 56 */ OP_NONE,
/* 57 */ OP_NONE,
/* 58 */ OP_NONE,
/* 59 */ OP_NONE,
/* 5A */ OP_NONE,
/* 5B */ OP_NONE,
/* 5C */ OP_NONE,
/* 5D */ OP_NONE,
/* 5E */ OP_NONE,
/* 5F */ OP_NONE,
/* 60 */ OP_NONE,
/* 61 */ OP_NONE,
/* 62 */ OP_MODRM,
/* 63 */ OP_MODRM,
/* 64 */ OP_PREFIX,
/* 65 */ OP_PREFIX,
/* 66 */ OP_PREFIX,
/* 67 */ OP_PREFIX,
/* 68 */ OP_DATA_I16_I32,
/* 69 */ OP_MODRM | OP_DATA_I16_I32,
/* 6A */ OP_DATA_I8,
/* 6B */ OP_MODRM | OP_DATA_I8,
/* 6C */ OP_NONE,
/* 6D */ OP_NONE,
/* 6E */ OP_NONE,
/* 6F */ OP_NONE,
/* 70 */ OP_RELATIVE | OP_DATA_I8,
/* 71 */ OP_RELATIVE | OP_DATA_I8,
/* 72 */ OP_RELATIVE | OP_DATA_I8,
/* 73 */ OP_RELATIVE | OP_DATA_I8,
/* 74 */ OP_RELATIVE | OP_DATA_I8,
/* 75 */ OP_RELATIVE | OP_DATA_I8,
/* 76 */ OP_RELATIVE | OP_DATA_I8,
/* 77 */ OP_RELATIVE | OP_DATA_I8,
/* 78 */ OP_RELATIVE | OP_DATA_I8,
/* 79 */ OP_RELATIVE | OP_DATA_I8,
/* 7A */ OP_RELATIVE | OP_DATA_I8,
/* 7B */ OP_RELATIVE | OP_DATA_I8,
/* 7C */ OP_RELATIVE | OP_DATA_I8,
/* 7D */ OP_RELATIVE | OP_DATA_I8,
/* 7E */ OP_RELATIVE | OP_DATA_I8,
/* 7F */ OP_RELATIVE | OP_DATA_I8,
/* 80 */ OP_MODRM | OP_DATA_I8,
/* 81 */ OP_MODRM | OP_DATA_I16_I32,
/* 82 */ OP_MODRM | OP_DATA_I8,
/* 83 */ OP_MODRM | OP_DATA_I8,
/* 84 */ OP_MODRM,
/* 85 */ OP_MODRM,
/* 86 */ OP_MODRM,
/* 87 */ OP_MODRM,
/* 88 */ OP_MODRM,
/* 89 */ OP_MODRM,
/* 8A */ OP_MODRM,
/* 8B */ OP_MODRM,
/* 8C */ OP_MODRM,
/* 8D */ OP_MODRM,
/* 8E */ OP_MODRM,
/* 8F */ OP_MODRM,
/* 90 */ OP_NONE,
/* 91 */ OP_NONE,
/* 92 */ OP_NONE,
/* 93 */ OP_NONE,
/* 94 */ OP_NONE,
/* 95 */ OP_NONE,
/* 96 */ OP_NONE,
/* 97 */ OP_NONE,
/* 98 */ OP_NONE,
/* 99 */ OP_NONE,
/* 9A */ OP_DATA_I16 | OP_DATA_I16_I32,
/* 9B */ OP_NONE,
/* 9C */ OP_NONE,
/* 9D */ OP_NONE,
/* 9E */ OP_NONE,
/* 9F */ OP_NONE,
/* A0 */ OP_DATA_I8,
/* A1 */ OP_DATA_I16_I32_I64,
/* A2 */ OP_DATA_I8,
/* A3 */ OP_DATA_I16_I32_I64,
/* A4 */ OP_NONE,
/* A5 */ OP_NONE,
/* A6 */ OP_NONE,
/* A7 */ OP_NONE,
/* A8 */ OP_DATA_I8,
/* A9 */ OP_DATA_I16_I32,
/* AA */ OP_NONE,
/* AB */ OP_NONE,
/* AC */ OP_NONE,
/* AD */ OP_NONE,
/* AE */ OP_NONE,
/* AF */ OP_NONE,
/* B0 */ OP_DATA_I8,
/* B1 */ OP_DATA_I8,
/* B2 */ OP_DATA_I8,
/* B3 */ OP_DATA_I8,
/* B4 */ OP_DATA_I8,
/* B5 */ OP_DATA_I8,
/* B6 */ OP_DATA_I8,
/* B7 */ OP_DATA_I8,
/* B8 */ OP_DATA_I16_I32_I64,
/* B9 */ OP_DATA_I16_I32_I64,
/* BA */ OP_DATA_I16_I32_I64,
/* BB */ OP_DATA_I16_I32_I64,
/* BC */ OP_DATA_I16_I32_I64,
/* BD */ OP_DATA_I16_I32_I64,
/* BE */ OP_DATA_I16_I32_I64,
/* BF */ OP_DATA_I16_I32_I64,
/* C0 */ OP_MODRM | OP_DATA_I8,
/* C1 */ OP_MODRM | OP_DATA_I8,
/* C2 */ OP_DATA_I16,
/* C3 */ OP_NONE,
/* C4 */ OP_MODRM,
/* C5 */ OP_MODRM,
/* C6 */ OP_MODRM | OP_DATA_I8,
/* C7 */ OP_MODRM | OP_DATA_I16_I32,
/* C8 */ OP_DATA_I8 | OP_DATA_I16,
/* C9 */ OP_NONE,
/* CA */ OP_DATA_I16,
/* CB */ OP_NONE,
/* CC */ OP_NONE,
/* CD */ OP_DATA_I8,
/* CE */ OP_NONE,
/* CF */ OP_NONE,
/* D0 */ OP_MODRM,
/* D1 */ OP_MODRM,
/* D2 */ OP_MODRM,
/* D3 */ OP_MODRM,
/* D4 */ OP_DATA_I8,
/* D5 */ OP_DATA_I8,
/* D6 */ OP_NONE,
/* D7 */ OP_NONE,
/* D8 */ OP_MODRM,
/* D9 */ OP_MODRM,
/* DA */ OP_MODRM,
/* DB */ OP_MODRM,
/* DC */ OP_MODRM,
/* DD */ OP_MODRM,
/* DE */ OP_MODRM,
/* DF */ OP_MODRM,
/* E0 */ OP_RELATIVE | OP_DATA_I8,
/* E1 */ OP_RELATIVE | OP_DATA_I8,
/* E2 */ OP_RELATIVE | OP_DATA_I8,
/* E3 */ OP_RELATIVE | OP_DATA_I8,
/* E4 */ OP_DATA_I8,
/* E5 */ OP_DATA_I8,
/* E6 */ OP_DATA_I8,
/* E7 */ OP_DATA_I8,
/* E8 */ OP_RELATIVE | OP_DATA_I16_I32,
/* E9 */ OP_RELATIVE | OP_DATA_I16_I32,
/* EA */ OP_DATA_I16 | OP_DATA_I16_I32,
/* EB */ OP_RELATIVE | OP_DATA_I8,
/* EC */ OP_NONE,
/* ED */ OP_NONE,
/* EE */ OP_NONE,
/* EF */ OP_NONE,
/* F0 */ OP_PREFIX,
/* F1 */ OP_NONE,
/* F2 */ OP_PREFIX,
/* F3 */ OP_PREFIX,
/* F4 */ OP_NONE,
/* F5 */ OP_NONE,
/* F6 */ OP_MODRM,
/* F7 */ OP_MODRM,
/* F8 */ OP_NONE,
/* F9 */ OP_NONE,
/* FA */ OP_NONE,
/* FB */ OP_NONE,
/* FC */ OP_NONE,
/* FD */ OP_NONE,
/* FE */ OP_MODRM,
/* FF */ OP_MODRM
};
static byte[] flags_table_ex =
{
/* 0F00 */ OP_MODRM,
/* 0F01 */ OP_MODRM,
/* 0F02 */ OP_MODRM,
/* 0F03 */ OP_MODRM,
/* 0F04 */ OP_INVALID,
/* 0F05 */ OP_NONE,
/* 0F06 */ OP_NONE,
/* 0F07 */ OP_NONE,
/* 0F08 */ OP_NONE,
/* 0F09 */ OP_NONE,
/* 0F0A */ OP_INVALID,
/* 0F0B */ OP_NONE,
/* 0F0C */ OP_INVALID,
/* 0F0D */ OP_MODRM,
/* 0F0E */ OP_INVALID,
/* 0F0F */ OP_MODRM | OP_DATA_I8, //3Dnow
/* 0F10 */ OP_MODRM,
/* 0F11 */ OP_MODRM,
/* 0F12 */ OP_MODRM,
/* 0F13 */ OP_MODRM,
/* 0F14 */ OP_MODRM,
/* 0F15 */ OP_MODRM,
/* 0F16 */ OP_MODRM,
/* 0F17 */ OP_MODRM,
/* 0F18 */ OP_MODRM,
/* 0F19 */ OP_INVALID,
/* 0F1A */ OP_INVALID,
/* 0F1B */ OP_INVALID,
/* 0F1C */ OP_INVALID,
/* 0F1D */ OP_INVALID,
/* 0F1E */ OP_INVALID,
/* 0F1F */ OP_NONE,
/* 0F20 */ OP_MODRM,
/* 0F21 */ OP_MODRM,
/* 0F22 */ OP_MODRM,
/* 0F23 */ OP_MODRM,
/* 0F24 */ OP_MODRM | OP_EXTENDED, //SSE5
/* 0F25 */ OP_INVALID,
/* 0F26 */ OP_MODRM,
/* 0F27 */ OP_INVALID,
/* 0F28 */ OP_MODRM,
/* 0F29 */ OP_MODRM,
/* 0F2A */ OP_MODRM,
/* 0F2B */ OP_MODRM,
/* 0F2C */ OP_MODRM,
/* 0F2D */ OP_MODRM,
/* 0F2E */ OP_MODRM,
/* 0F2F */ OP_MODRM,
/* 0F30 */ OP_NONE,
/* 0F31 */ OP_NONE,
/* 0F32 */ OP_NONE,
/* 0F33 */ OP_NONE,
/* 0F34 */ OP_NONE,
/* 0F35 */ OP_NONE,
/* 0F36 */ OP_INVALID,
/* 0F37 */ OP_NONE,
/* 0F38 */ OP_MODRM | OP_EXTENDED,
/* 0F39 */ OP_INVALID,
/* 0F3A */ OP_MODRM | OP_EXTENDED | OP_DATA_I8,
/* 0F3B */ OP_INVALID,
/* 0F3C */ OP_INVALID,
/* 0F3D */ OP_INVALID,
/* 0F3E */ OP_INVALID,
/* 0F3F */ OP_INVALID,
/* 0F40 */ OP_MODRM,
/* 0F41 */ OP_MODRM,
/* 0F42 */ OP_MODRM,
/* 0F43 */ OP_MODRM,
/* 0F44 */ OP_MODRM,
/* 0F45 */ OP_MODRM,
/* 0F46 */ OP_MODRM,
/* 0F47 */ OP_MODRM,
/* 0F48 */ OP_MODRM,
/* 0F49 */ OP_MODRM,
/* 0F4A */ OP_MODRM,
/* 0F4B */ OP_MODRM,
/* 0F4C */ OP_MODRM,
/* 0F4D */ OP_MODRM,
/* 0F4E */ OP_MODRM,
/* 0F4F */ OP_MODRM,
/* 0F50 */ OP_MODRM,
/* 0F51 */ OP_MODRM,
/* 0F52 */ OP_MODRM,
/* 0F53 */ OP_MODRM,
/* 0F54 */ OP_MODRM,
/* 0F55 */ OP_MODRM,
/* 0F56 */ OP_MODRM,
/* 0F57 */ OP_MODRM,
/* 0F58 */ OP_MODRM,
/* 0F59 */ OP_MODRM,
/* 0F5A */ OP_MODRM,
/* 0F5B */ OP_MODRM,
/* 0F5C */ OP_MODRM,
/* 0F5D */ OP_MODRM,
/* 0F5E */ OP_MODRM,
/* 0F5F */ OP_MODRM,
/* 0F60 */ OP_MODRM,
/* 0F61 */ OP_MODRM,
/* 0F62 */ OP_MODRM,
/* 0F63 */ OP_MODRM,
/* 0F64 */ OP_MODRM,
/* 0F65 */ OP_MODRM,
/* 0F66 */ OP_MODRM,
/* 0F67 */ OP_MODRM,
/* 0F68 */ OP_MODRM,
/* 0F69 */ OP_MODRM,
/* 0F6A */ OP_MODRM,
/* 0F6B */ OP_MODRM,
/* 0F6C */ OP_MODRM,
/* 0F6D */ OP_MODRM,
/* 0F6E */ OP_MODRM,
/* 0F6F */ OP_MODRM,
/* 0F70 */ OP_MODRM | OP_DATA_I8,
/* 0F71 */ OP_MODRM | OP_DATA_I8,
/* 0F72 */ OP_MODRM | OP_DATA_I8,
/* 0F73 */ OP_MODRM | OP_DATA_I8,
/* 0F74 */ OP_MODRM,
/* 0F75 */ OP_MODRM,
/* 0F76 */ OP_MODRM,
/* 0F77 */ OP_NONE,
/* 0F78 */ OP_MODRM,
/* 0F79 */ OP_MODRM,
/* 0F7A */ OP_INVALID,
/* 0F7B */ OP_INVALID,
/* 0F7C */ OP_MODRM,
/* 0F7D */ OP_MODRM,
/* 0F7E */ OP_MODRM,
/* 0F7F */ OP_MODRM,
/* 0F80 */ OP_RELATIVE | OP_DATA_I16_I32,
/* 0F81 */ OP_RELATIVE | OP_DATA_I16_I32,
/* 0F82 */ OP_RELATIVE | OP_DATA_I16_I32,
/* 0F83 */ OP_RELATIVE | OP_DATA_I16_I32,
/* 0F84 */ OP_RELATIVE | OP_DATA_I16_I32,
/* 0F85 */ OP_RELATIVE | OP_DATA_I16_I32,
/* 0F86 */ OP_RELATIVE | OP_DATA_I16_I32,
/* 0F87 */ OP_RELATIVE | OP_DATA_I16_I32,
/* 0F88 */ OP_RELATIVE | OP_DATA_I16_I32,
/* 0F89 */ OP_RELATIVE | OP_DATA_I16_I32,
/* 0F8A */ OP_RELATIVE | OP_DATA_I16_I32,
/* 0F8B */ OP_RELATIVE | OP_DATA_I16_I32,
/* 0F8C */ OP_RELATIVE | OP_DATA_I16_I32,
/* 0F8D */ OP_RELATIVE | OP_DATA_I16_I32,
/* 0F8E */ OP_RELATIVE | OP_DATA_I16_I32,
/* 0F8F */ OP_RELATIVE | OP_DATA_I16_I32,
/* 0F90 */ OP_MODRM,
/* 0F91 */ OP_MODRM,
/* 0F92 */ OP_MODRM,
/* 0F93 */ OP_MODRM,
/* 0F94 */ OP_MODRM,
/* 0F95 */ OP_MODRM,
/* 0F96 */ OP_MODRM,
/* 0F97 */ OP_MODRM,
/* 0F98 */ OP_MODRM,
/* 0F99 */ OP_MODRM,
/* 0F9A */ OP_MODRM,
/* 0F9B */ OP_MODRM,
/* 0F9C */ OP_MODRM,
/* 0F9D */ OP_MODRM,
/* 0F9E */ OP_MODRM,
/* 0F9F */ OP_MODRM,
/* 0FA0 */ OP_NONE,
/* 0FA1 */ OP_NONE,
/* 0FA2 */ OP_NONE,
/* 0FA3 */ OP_MODRM,
/* 0FA4 */ OP_MODRM | OP_DATA_I8,
/* 0FA5 */ OP_MODRM,
/* 0FA6 */ OP_INVALID,
/* 0FA7 */ OP_INVALID,
/* 0FA8 */ OP_NONE,
/* 0FA9 */ OP_NONE,
/* 0FAA */ OP_NONE,
/* 0FAB */ OP_MODRM,
/* 0FAC */ OP_MODRM | OP_DATA_I8,
/* 0FAD */ OP_MODRM,
/* 0FAE */ OP_MODRM,
/* 0FAF */ OP_MODRM,
/* 0FB0 */ OP_MODRM,
/* 0FB1 */ OP_MODRM,
/* 0FB2 */ OP_MODRM,
/* 0FB3 */ OP_MODRM,
/* 0FB4 */ OP_MODRM,
/* 0FB5 */ OP_MODRM,
/* 0FB6 */ OP_MODRM,
/* 0FB7 */ OP_MODRM,
/* 0FB8 */ OP_MODRM,
/* 0FB9 */ OP_MODRM,
/* 0FBA */ OP_MODRM | OP_DATA_I8,
/* 0FBB */ OP_MODRM,
/* 0FBC */ OP_MODRM,
/* 0FBD */ OP_MODRM,
/* 0FBE */ OP_MODRM,
/* 0FBF */ OP_MODRM,
/* 0FC0 */ OP_MODRM,
/* 0FC1 */ OP_MODRM,
/* 0FC2 */ OP_MODRM | OP_DATA_I8,
/* 0FC3 */ OP_MODRM,
/* 0FC4 */ OP_MODRM | OP_DATA_I8,
/* 0FC5 */ OP_MODRM | OP_DATA_I8,
/* 0FC6 */ OP_MODRM | OP_DATA_I8,
/* 0FC7 */ OP_MODRM,
/* 0FC8 */ OP_NONE,
/* 0FC9 */ OP_NONE,
/* 0FCA */ OP_NONE,
/* 0FCB */ OP_NONE,
/* 0FCC */ OP_NONE,
/* 0FCD */ OP_NONE,
/* 0FCE */ OP_NONE,
/* 0FCF */ OP_NONE,
/* 0FD0 */ OP_MODRM,
/* 0FD1 */ OP_MODRM,
/* 0FD2 */ OP_MODRM,
/* 0FD3 */ OP_MODRM,
/* 0FD4 */ OP_MODRM,
/* 0FD5 */ OP_MODRM,
/* 0FD6 */ OP_MODRM,
/* 0FD7 */ OP_MODRM,
/* 0FD8 */ OP_MODRM,
/* 0FD9 */ OP_MODRM,
/* 0FDA */ OP_MODRM,
/* 0FDB */ OP_MODRM,
/* 0FDC */ OP_MODRM,
/* 0FDD */ OP_MODRM,
/* 0FDE */ OP_MODRM,
/* 0FDF */ OP_MODRM,
/* 0FE0 */ OP_MODRM,
/* 0FE1 */ OP_MODRM,
/* 0FE2 */ OP_MODRM,
/* 0FE3 */ OP_MODRM,
/* 0FE4 */ OP_MODRM,
/* 0FE5 */ OP_MODRM,
/* 0FE6 */ OP_MODRM,
/* 0FE7 */ OP_MODRM,
/* 0FE8 */ OP_MODRM,
/* 0FE9 */ OP_MODRM,
/* 0FEA */ OP_MODRM,
/* 0FEB */ OP_MODRM,
/* 0FEC */ OP_MODRM,
/* 0FED */ OP_MODRM,
/* 0FEE */ OP_MODRM,
/* 0FEF */ OP_MODRM,
/* 0FF0 */ OP_MODRM,
/* 0FF1 */ OP_MODRM,
/* 0FF2 */ OP_MODRM,
/* 0FF3 */ OP_MODRM,
/* 0FF4 */ OP_MODRM,
/* 0FF5 */ OP_MODRM,
/* 0FF6 */ OP_MODRM,
/* 0FF7 */ OP_MODRM,
/* 0FF8 */ OP_MODRM,
/* 0FF9 */ OP_MODRM,
/* 0FFA */ OP_MODRM,
/* 0FFB */ OP_MODRM,
/* 0FFC */ OP_MODRM,
/* 0FFD */ OP_MODRM,
/* 0FFE */ OP_MODRM,
/* 0FFF */ OP_INVALID,
};
static byte cflags(byte op)
{
return flags_table[op];
}
static byte cflags_ex(byte op)
{
return flags_table_ex[op];
}
/// <summary>
/// 计算大于等于 size 字节的最少指令的长度
/// </summary>
/// <param name="code"></param>
/// <returns></returns>
public static uint SizeofMinNumByte(void* code, int size)
{
if (IsARM())
return (uint)((size + 3) / 4) * 4; // 此为 jit 模式下的长度,不再支持 thumb
uint Length;
byte* pOpcode;
uint Result = 0;
ldasm_data data = new ldasm_data();
bool is64 = IntPtr.Size == 8;
do
{
Length = ldasm(code, data, is64);
pOpcode = (byte*)code + data.opcd_offset;
Result += Length;
if (Result >= size)
break;
if ((Length == 1) && (*pOpcode == 0xCC))
break;
code = (void*)((ulong)code + Length);
} while (Length>0);
return Result;
}
static bool? s_isArm;
public static bool IsARM()
{
if(s_isArm.HasValue)
return s_isArm.Value;
var arch = RuntimeInformation.ProcessArchitecture;
s_isArm = arch == Architecture.Arm || arch == Architecture.Arm64;
return s_isArm.Value;
}
public static bool IsArm32()
{
return IsARM() && IntPtr.Size == 4;
}
public static bool IsArm64()
{
return IsARM() && IntPtr.Size == 8;
}
static bool? s_isiOS;
public static bool IsiOS()
{
if(s_isiOS.HasValue)
return s_isiOS.Value;
s_isiOS = UnityEngine.SystemInfo.operatingSystem.ToLower().Contains("ios");
return s_isiOS.Value;
}
static bool? s_isIL2CPP;
public static bool IsIL2CPP()
{
if (s_isIL2CPP.HasValue)
return s_isIL2CPP.Value;
try
{
byte[] ilBody = typeof(LDasm).GetMethod("IsIL2CPP").GetMethodBody().GetILAsByteArray();
if (ilBody == null || ilBody.Length == 0)
s_isIL2CPP = true;
else
s_isIL2CPP = false;
}
catch
{
s_isIL2CPP = true;
}
return s_isIL2CPP.Value;
}
public static bool IsThumb(IntPtr code)
{
return IsArm32() && ((long)code & 0x1) == 0x1;
}
/// <summary>
/// 计算 thumb 指令长度
/// </summary>
/// <param name="code"></param>
/// <param name="size"></param>
/// <returns></returns>
public static uint CalcARMThumbMinLen(void* code, int size)
{
uint len = 0;
ushort* ins = (ushort*)code;
while (true)
{
if (len >= size)
return len;
if (((*ins >> 13) & 3) == 3)
{
ins += 2;
len += 4;
}
else
{
ins++;
len += 2;
}
}
}
static uint ldasm(void* code, ldasm_data ld, bool is64)
{
byte* p = (byte*)code;
byte s, op, f;
byte rexw, pr_66, pr_67;
s = rexw = pr_66 = pr_67 = 0;
/* dummy check */
if ((int)code==0)
return 0;
/* init output data */
//memset(ld, 0, sizeof(ldasm_data));
/* phase 1: parse prefixies */
while ((cflags(*p) & OP_PREFIX)!=0)
{
if (*p == 0x66)
pr_66 = 1;
if (*p == 0x67)
pr_67 = 1;
p++; s++;
ld.flags |= F_PREFIX;
if (s == 15)
{
ld.flags |= F_INVALID;
return s;
}
}
/* parse REX prefix */
if (is64 && *p >> 4 == 4)
{
ld.rex = *p;
rexw = (byte)((ld.rex >> 3) & 1);
ld.flags |= F_REX;
p++; s++;
}
/* can be only one REX prefix */
if (is64 && *p >> 4 == 4)
{
ld.flags |= F_INVALID;
s++;
return s;
}
/* phase 2: parse opcode */
ld.opcd_offset = (byte)(p - (byte*)code);
ld.opcd_size = 1;
op = *p++; s++;
/* is 2 byte opcode? */
if (op == 0x0F)
{
op = *p++; s++;
ld.opcd_size++;
f = cflags_ex(op);
if ((f & OP_INVALID)!=0)
{
ld.flags |= F_INVALID;
return s;
}
/* for SSE instructions */
if ((f & OP_EXTENDED)!=0)
{
op = *p++; s++;
ld.opcd_size++;
}
}
else {
f = cflags(op);
/* pr_66 = pr_67 for opcodes A0-A3 */
if (op >= 0xA0 && op <= 0xA3)
pr_66 = pr_67;
}
/* phase 3: parse ModR/M, SIB and DISP */
if ((f & OP_MODRM)!=0)
{
byte mod = (byte)(*p >> 6);
byte ro = (byte)((*p & 0x38) >> 3);
byte rm = (byte)(*p & 7);
ld.modrm = *p++; s++;
ld.flags |= F_MODRM;
/* in F6,F7 opcodes immediate data present if R/O == 0 */
if (op == 0xF6 && (ro == 0 || ro == 1))
f |= OP_DATA_I8;
if (op == 0xF7 && (ro == 0 || ro == 1))
f |= OP_DATA_I16_I32_I64;
/* is SIB byte exist? */
if (mod != 3 && rm == 4 && !(!is64 && pr_67!=0))
{
ld.sib = *p++; s++;
ld.flags |= F_SIB;
/* if base == 5 and mod == 0 */
if ((ld.sib & 7) == 5 && mod == 0)
{
ld.disp_size = 4;
}
}
switch (mod)
{
case 0:
if (is64)
{
if (rm == 5)
{
ld.disp_size = 4;
if (is64)
ld.flags |= F_RELATIVE;
}
}
else if (pr_67!=0)
{
if (rm == 6)
ld.disp_size = 2;
}
else {
if (rm == 5)
ld.disp_size = 4;
}
break;
case 1:
ld.disp_size = 1;
break;
case 2:
if (is64)
ld.disp_size = 4;
else if (pr_67!=0)
ld.disp_size = 2;
else
ld.disp_size = 4;
break;
}
if (ld.disp_size>0)
{
ld.disp_offset = (byte)(p - (byte*)code);
p += ld.disp_size;
s += ld.disp_size;
ld.flags |= F_DISP;
}
}
/* phase 4: parse immediate data */
if (rexw!=0 && (f & OP_DATA_I16_I32_I64)!=0)
ld.imm_size = 8;
else if ((f & OP_DATA_I16_I32)!=0 || (f & OP_DATA_I16_I32_I64)!=0)
ld.imm_size = (byte)(4 - (pr_66 << 1));
/* if exist, add OP_DATA_I16 and OP_DATA_I8 size */
ld.imm_size += (byte)(f & 3);
if ((ld.imm_size)!=0)
{
s += ld.imm_size;
ld.imm_offset = (byte)(p - (byte*)code);
ld.flags |= F_IMM;
if ((f & OP_RELATIVE)!=0)
ld.flags |= F_RELATIVE;
}
/* instruction is too long */
if (s > 15)
ld.flags |= F_INVALID;
return s;
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 3c561c9729c367e4fbef63f4ec56f268
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,381 +0,0 @@
/*
Desc: 一个可以运行时 Hook Mono 方法的工具,让你可以无需修改 UnityEditor.dll 等文件就可以重写其函数功能
Author: Misaka Mikoto
Github: https://github.com/Misaka-Mikoto-Tech/MonoHook
*/
using DotNetDetour;
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;
using Unity.Collections.LowLevel.Unsafe;
#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEngine;
using System.Runtime.CompilerServices;
/*
>>>>>>> 原始 UnityEditor.LogEntries.Clear 一型(.net 4.x)
0000000000403A00 < | 55 | push rbp |
0000000000403A01 | 48 8B EC | mov rbp,rsp |
0000000000403A04 | 48 81 EC 80 00 00 00 | sub rsp,80 |
0000000000403A0B | 48 89 65 B0 | mov qword ptr ss:[rbp-50],rsp |
0000000000403A0F | 48 89 6D A8 | mov qword ptr ss:[rbp-58],rbp |
0000000000403A13 | 48 89 5D C8 | mov qword ptr ss:[rbp-38],rbx | <<
0000000000403A17 | 48 89 75 D0 | mov qword ptr ss:[rbp-30],rsi |
0000000000403A1B | 48 89 7D D8 | mov qword ptr ss:[rbp-28],rdi |
0000000000403A1F | 4C 89 65 E0 | mov qword ptr ss:[rbp-20],r12 |
0000000000403A23 | 4C 89 6D E8 | mov qword ptr ss:[rbp-18],r13 |
0000000000403A27 | 4C 89 75 F0 | mov qword ptr ss:[rbp-10],r14 |
0000000000403A2B | 4C 89 7D F8 | mov qword ptr ss:[rbp-8],r15 |
0000000000403A2F | 49 BB 00 2D 1E 1A FE 7F 00 00 | mov r11,7FFE1A1E2D00 |
0000000000403A39 | 4C 89 5D B8 | mov qword ptr ss:[rbp-48],r11 |
0000000000403A3D | 49 BB 08 2D 1E 1A FE 7F 00 00 | mov r11,7FFE1A1E2D08 |
>>>>>>> 二型(.net 2.x)
0000000000403E8F | 55 | push rbp |
0000000000403E90 | 48 8B EC | mov rbp,rsp |
0000000000403E93 | 48 83 EC 70 | sub rsp,70 |
0000000000403E97 | 48 89 65 C8 | mov qword ptr ss:[rbp-38],rsp |
0000000000403E9B | 48 89 5D B8 | mov qword ptr ss:[rbp-48],rbx |
0000000000403E9F | 48 89 6D C0 | mov qword ptr ss:[rbp-40],rbp | <<(16)
0000000000403EA3 | 48 89 75 F8 | mov qword ptr ss:[rbp-8],rsi |
0000000000403EA7 | 48 89 7D F0 | mov qword ptr ss:[rbp-10],rdi |
0000000000403EAB | 4C 89 65 D0 | mov qword ptr ss:[rbp-30],r12 |
0000000000403EAF | 4C 89 6D D8 | mov qword ptr ss:[rbp-28],r13 |
0000000000403EB3 | 4C 89 75 E0 | mov qword ptr ss:[rbp-20],r14 |
0000000000403EB7 | 4C 89 7D E8 | mov qword ptr ss:[rbp-18],r15 |
0000000000403EBB | 48 83 EC 20 | sub rsp,20 |
0000000000403EBF | 49 BB 18 3F 15 13 FE 7F 00 00 | mov r11,7FFE13153F18 |
0000000000403EC9 | 41 FF D3 | call r11 |
0000000000403ECC | 48 83 C4 20 | add rsp,20 |
>>>>>>>>> arm64
il2cpp:00000000003DE714 F5 0F 1D F8 STR X21, [SP,#-0x10+var_20]! | << absolute safe
il2cpp:00000000003DE718 F4 4F 01 A9 STP X20, X19, [SP,#0x20+var_10] | << may be safe
il2cpp:00000000003DE71C FD 7B 02 A9 STP X29, X30, [SP,#0x20+var_s0] |
il2cpp:00000000003DE720 FD 83 00 91 ADD X29, SP, #0x20 |
il2cpp:00000000003DE724 B5 30 00 B0 ADRP X21, #_ZZ62GameObject_SetActive_mCF1EEF2A314F3AE | << dangerous: relative instruction, can not be overwritten
il2cpp:00000000003DE728 A2 56 47 F9 LDR method, [X21,#_ZZ62GameObject_SetActive_mCF] ; |
il2cpp:00000000003DE72C F3 03 01 2A MOV W19, W1 |
*/
namespace MonoHook
{
/// <summary>
/// Hook 类,用来 Hook 某个 C# 方法
/// </summary>
public unsafe class MethodHook
{
public string tag;
public bool isHooked { get; private set; }
public bool isPlayModeHook { get; private set; }
public MethodBase targetMethod { get; private set; } // 需要被hook的目标方法
public MethodBase replacementMethod { get; private set; } // 被hook后的替代方法
public MethodBase proxyMethod { get; private set; } // 目标方法的代理方法(可以通过此方法调用被hook后的原方法)
private IntPtr _targetPtr; // 目标方法被 jit 后的地址指针
private IntPtr _replacementPtr;
private IntPtr _proxyPtr;
private CodePatcher _codePatcher;
#if UNITY_EDITOR && !UNITY_2020_3_OR_NEWER
/// <summary>
/// call `MethodInfo.MethodHandle.GetFunctionPointer()`
/// will visit static class `UnityEditor.IMGUI.Controls.TreeViewGUI.Styles` and invoke its static constructor,
/// and init static filed `foldout`, but `GUISKin.current` is null now,
/// so we should wait until `GUISKin.current` has a valid value
/// </summary>
private static FieldInfo s_fi_GUISkin_current;
#endif
static MethodHook()
{
#if UNITY_EDITOR && !UNITY_2020_3_OR_NEWER
s_fi_GUISkin_current = typeof(GUISkin).GetField("current", BindingFlags.Static | BindingFlags.NonPublic);
#endif
}
/// <summary>
/// 创建一个 Hook
/// </summary>
/// <param name="targetMethod">需要替换的目标方法</param>
/// <param name="replacementMethod">准备好的替换方法</param>
/// <param name="proxyMethod">如果还需要调用原始目标方法,可以通过此参数的方法调用,如果不需要可以填 null</param>
public MethodHook(MethodBase targetMethod, MethodBase replacementMethod, MethodBase proxyMethod, string data = "")
{
this.targetMethod = targetMethod;
this.replacementMethod = replacementMethod;
this.proxyMethod = proxyMethod;
this.tag = data;
CheckMethod();
}
public void Install()
{
if (LDasm.IsiOS()) // iOS 不支持修改 code 所在区域 page
return;
if (isHooked)
return;
#if UNITY_EDITOR && !UNITY_2020_3_OR_NEWER
if (s_fi_GUISkin_current.GetValue(null) != null)
DoInstall();
else
EditorApplication.update += OnEditorUpdate;
#else
DoInstall();
#endif
isPlayModeHook = Application.isPlaying;
}
public void Uninstall()
{
if (!isHooked)
return;
_codePatcher.RemovePatch();
isHooked = false;
HookPool.RemoveHooker(targetMethod);
}
#region private
private void DoInstall()
{
if (targetMethod == null || replacementMethod == null)
throw new Exception("none of methods targetMethod or replacementMethod can be null");
HookPool.AddHook(targetMethod, this);
if (_codePatcher == null)
{
if (GetFunctionAddr())
{
#if ENABLE_HOOK_DEBUG
UnityEngine.Debug.Log($"Original [{targetMethod.DeclaringType.Name}.{targetMethod.Name}]: {HookUtils.HexToString(_targetPtr.ToPointer(), 64, -16)}");
UnityEngine.Debug.Log($"Original [{replacementMethod.DeclaringType.Name}.{replacementMethod.Name}]: {HookUtils.HexToString(_replacementPtr.ToPointer(), 64, -16)}");
if(proxyMethod != null)
UnityEngine.Debug.Log($"Original [{proxyMethod.DeclaringType.Name}.{proxyMethod.Name}]: {HookUtils.HexToString(_proxyPtr.ToPointer(), 64, -16)}");
#endif
CreateCodePatcher();
_codePatcher.ApplyPatch();
#if ENABLE_HOOK_DEBUG
UnityEngine.Debug.Log($"New [{targetMethod.DeclaringType.Name}.{targetMethod.Name}]: {HookUtils.HexToString(_targetPtr.ToPointer(), 64, -16)}");
UnityEngine.Debug.Log($"New [{replacementMethod.DeclaringType.Name}.{replacementMethod.Name}]: {HookUtils.HexToString(_replacementPtr.ToPointer(), 64, -16)}");
if(proxyMethod != null)
UnityEngine.Debug.Log($"New [{proxyMethod.DeclaringType.Name}.{proxyMethod.Name}]: {HookUtils.HexToString(_proxyPtr.ToPointer(), 64, -16)}");
#endif
}
}
isHooked = true;
}
private void CheckMethod()
{
if (targetMethod == null || replacementMethod == null)
throw new Exception("MethodHook:targetMethod and replacementMethod and proxyMethod can not be null");
string methodName = $"{targetMethod.DeclaringType.Name}.{targetMethod.Name}";
if (targetMethod.IsAbstract)
throw new Exception($"WRANING: you can not hook abstract method [{methodName}]");
#if UNITY_EDITOR && !UNITY_2020_3_OR_NEWER
int minMethodBodySize = 10;
{
if ((targetMethod.MethodImplementationFlags & MethodImplAttributes.InternalCall) != MethodImplAttributes.InternalCall)
{
int codeSize = targetMethod.GetMethodBody().GetILAsByteArray().Length; // GetMethodBody can not call on il2cpp
if (codeSize < minMethodBodySize)
UnityEngine.Debug.LogWarning($"WRANING: you can not hook method [{methodName}], cause its method body is too short({codeSize}), will random crash on IL2CPP release mode");
}
}
if(proxyMethod != null)
{
methodName = $"{proxyMethod.DeclaringType.Name}.{proxyMethod.Name}";
int codeSize = proxyMethod.GetMethodBody().GetILAsByteArray().Length;
if (codeSize < minMethodBodySize)
UnityEngine.Debug.LogWarning($"WRANING: size of method body[{methodName}] is too short({codeSize}), will random crash on IL2CPP release mode, please fill some dummy code inside");
if ((proxyMethod.MethodImplementationFlags & MethodImplAttributes.NoOptimization) != MethodImplAttributes.NoOptimization)
throw new Exception($"WRANING: method [{methodName}] must has a Attribute `MethodImpl(MethodImplOptions.NoOptimization)` to prevent code call to this optimized by compiler(pass args by shared stack)");
}
#endif
}
private void CreateCodePatcher()
{
long addrOffset = Math.Abs(_targetPtr.ToInt64() - _proxyPtr.ToInt64());
if(_proxyPtr != IntPtr.Zero)
addrOffset = Math.Max(addrOffset, Math.Abs(_targetPtr.ToInt64() - _proxyPtr.ToInt64()));
if (LDasm.IsARM())
{
if (IntPtr.Size == 8)
_codePatcher = new CodePatcher_arm64_near(_targetPtr, _replacementPtr, _proxyPtr);
else if (addrOffset < ((1 << 25) - 1))
_codePatcher = new CodePatcher_arm32_near(_targetPtr, _replacementPtr, _proxyPtr);
else if (addrOffset < ((1 << 27) - 1))
_codePatcher = new CodePatcher_arm32_far(_targetPtr, _replacementPtr, _proxyPtr);
else
throw new Exception("address of target method and replacement method are too far, can not hook");
}
else
{
if (IntPtr.Size == 8)
{
if(addrOffset < 0x7fffffff) // 2G
_codePatcher = new CodePatcher_x64_near(_targetPtr, _replacementPtr, _proxyPtr);
else
_codePatcher = new CodePatcher_x64_far(_targetPtr, _replacementPtr, _proxyPtr);
}
else
_codePatcher = new CodePatcher_x86(_targetPtr, _replacementPtr, _proxyPtr);
}
}
/// <summary>
/// 获取对应函数jit后的native code的地址
/// </summary>
private bool GetFunctionAddr()
{
_targetPtr = GetFunctionAddr(targetMethod);
_replacementPtr = GetFunctionAddr(replacementMethod);
_proxyPtr = GetFunctionAddr(proxyMethod);
if (_targetPtr == IntPtr.Zero || _replacementPtr == IntPtr.Zero)
return false;
if (proxyMethod != null && _proxyPtr == null)
return false;
if(_replacementPtr == _targetPtr)
{
throw new Exception($"the addresses of target method {targetMethod.Name} and replacement method {replacementMethod.Name} can not be same");
}
if (LDasm.IsThumb(_targetPtr) || LDasm.IsThumb(_replacementPtr))
{
throw new Exception("does not support thumb arch");
}
return true;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)] // 好像在 IL2CPP 里无效
private struct __ForCopy
{
public long __dummy;
public MethodBase method;
}
/// <summary>
/// 获取方法指令地址
/// </summary>
/// <param name="method"></param>
/// <returns></returns>
private IntPtr GetFunctionAddr(MethodBase method)
{
if (method == null)
return IntPtr.Zero;
if (!LDasm.IsIL2CPP())
return method.MethodHandle.GetFunctionPointer();
else
{
/*
// System.Reflection.MonoMethod
typedef struct Il2CppReflectionMethod
{
Il2CppObject object;
const MethodInfo *method;
Il2CppString *name;
Il2CppReflectionType *reftype;
} Il2CppReflectionMethod;
typedef Il2CppClass Il2CppVTable;
typedef struct Il2CppObject
{
union
{
Il2CppClass *klass;
Il2CppVTable *vtable;
};
MonitorData *monitor;
} Il2CppObject;
typedef struct MethodInfo
{
Il2CppMethodPointer methodPointer; // this is the pointer to native code of method
InvokerMethod invoker_method;
const char* name;
Il2CppClass *klass;
const Il2CppType *return_type;
const ParameterInfo* parameters;
// ...
}
*/
__ForCopy __forCopy = new __ForCopy() { method = method };
long* ptr = &__forCopy.__dummy;
ptr++; // addr of _forCopy.method
IntPtr methodAddr = IntPtr.Zero;
if (sizeof(IntPtr) == 8)
{
long methodDataAddr = *(long*)ptr;
byte* ptrData = (byte*)methodDataAddr + sizeof(IntPtr) * 2; // offset of Il2CppReflectionMethod::const MethodInfo *method;
long methodPtr = 0;
methodPtr = *(long*)ptrData;
methodAddr = new IntPtr(*(long*)methodPtr); // MethodInfo::Il2CppMethodPointer methodPointer;
}
else
{
int methodDataAddr = *(int*)ptr;
byte* ptrData = (byte*)methodDataAddr + sizeof(IntPtr) * 2; // offset of Il2CppReflectionMethod::const MethodInfo *method;
int methodPtr = 0;
methodPtr = *(int*)ptrData;
methodAddr = new IntPtr(*(int*)methodPtr);
}
return methodAddr;
}
}
#if UNITY_EDITOR && !UNITY_2020_3_OR_NEWER
private void OnEditorUpdate()
{
if (s_fi_GUISkin_current.GetValue(null) != null)
{
try
{
DoInstall();
}
finally
{
EditorApplication.update -= OnEditorUpdate;
}
}
}
#endif
#endregion
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: bd0b8071cf434d6498160259e3829980
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 16b9dc031f67b4fe5ad79c230f75768c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,23 +0,0 @@
//
// Utils.cpp
// MonoHookUtils_OSX
//
// Created by Misaka-Mikoto on 2022/8/31.
//
#include <stdio.h>
#include <stdint.h>
#include <pthread.h>
#include <string.h>
#include <libkern/OSCacheControl.h>
extern "C"{
void* memcpy_jit(void* dst, void* src, int32_t size)
{
pthread_jit_write_protect_np(0);
void* ret = memcpy(dst, src, size);
pthread_jit_write_protect_np(1);
sys_icache_invalidate (dst, size);
return ret;
}
}

View File

@@ -1,81 +0,0 @@
fileFormatVersion: 2
guid: 56b28b5583a184c669dcb968d175544c
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
: Any
second:
enabled: 0
settings:
Exclude Android: 1
Exclude Editor: 0
Exclude Linux64: 1
Exclude OSXUniversal: 1
Exclude WebGL: 1
Exclude Win: 1
Exclude Win64: 1
Exclude iOS: 1
- first:
Android: Android
second:
enabled: 0
settings:
CPU: ARMv7
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 1
settings:
CPU: AnyCPU
DefaultValueInitialized: true
OS: OSX
- first:
Standalone: Linux64
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: OSXUniversal
second:
enabled: 0
settings:
CPU: ARM64
- first:
Standalone: Win
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: Win64
second:
enabled: 0
settings:
CPU: None
- first:
iPhone: iOS
second:
enabled: 0
settings:
AddToEmbeddedBinaries: false
CPU: AnyCPU
CompileFlags:
FrameworkDependencies:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,4 +0,0 @@
#!/bin/bash
clang -shared -undefined dynamic_lookup -o libMonoHookUtils_OSX.dylib Utils.cpp

View File

@@ -1,7 +0,0 @@
fileFormatVersion: 2
guid: 69eeb734e262a0a4fbe0887249198f73
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 7adba4475cf0bdc4fa7995c0d748f480
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,81 +0,0 @@
fileFormatVersion: 2
guid: e092a73910a69894daea44290d7292f6
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 1
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
: Any
second:
enabled: 0
settings:
Exclude Android: 1
Exclude Editor: 0
Exclude Linux64: 1
Exclude OSXUniversal: 1
Exclude WebGL: 1
Exclude Win: 1
Exclude Win64: 1
Exclude iOS: 1
- first:
Android: Android
second:
enabled: 0
settings:
CPU: ARMv7
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 1
settings:
CPU: ARM64
DefaultValueInitialized: true
OS: OSX
- first:
Standalone: Linux64
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: OSXUniversal
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: Win
second:
enabled: 0
settings:
CPU: x86
- first:
Standalone: Win64
second:
enabled: 0
settings:
CPU: x86_64
- first:
iPhone: iOS
second:
enabled: 0
settings:
AddToEmbeddedBinaries: false
CPU: AnyCPU
CompileFlags:
FrameworkDependencies:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 31f6a810e38e66f4c832b135770a04bb
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,81 +0,0 @@
fileFormatVersion: 2
guid: 4adb23596911347faa69537b900c9f5e
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
: Any
second:
enabled: 0
settings:
Exclude Android: 1
Exclude Editor: 0
Exclude Linux64: 1
Exclude OSXUniversal: 1
Exclude WebGL: 1
Exclude Win: 1
Exclude Win64: 1
Exclude iOS: 1
- first:
Android: Android
second:
enabled: 0
settings:
CPU: ARMv7
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 1
settings:
CPU: x86_64
DefaultValueInitialized: true
OS: OSX
- first:
Standalone: Linux64
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: OSXUniversal
second:
enabled: 0
settings:
CPU: AnyCPU
- first:
Standalone: Win
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: Win64
second:
enabled: 0
settings:
CPU: None
- first:
iPhone: iOS
second:
enabled: 0
settings:
AddToEmbeddedBinaries: false
CPU: AnyCPU
CompileFlags:
FrameworkDependencies:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: d26c8b77c84f09442a05f2c67e5e09b8
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,23 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HybridCLR.Editor.ABI
{
public static class ABIUtil
{
public static string GetHybridCLRPlatformMacro(PlatformABI abi)
{
switch(abi)
{
case PlatformABI.Arm64: return "HYBRIDCLR_ABI_ARM_64";
case PlatformABI.Universal64: return "HYBRIDCLR_ABI_UNIVERSAL_64";
case PlatformABI.Universal32: return "HYBRIDCLR_ABI_UNIVERSAL_32";
case PlatformABI.WebGL32: return "HYBRIDCLR_ABI_WEBGL32";
default: throw new NotSupportedException();
}
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: edeb86f4b5b13ca4cb0fe9d87ce509bb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,77 +0,0 @@
using dnlib.DotNet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace HybridCLR.Editor.ABI
{
public class MethodDesc : IEquatable<MethodDesc>
{
public string Sig { get; private set; }
public MethodDef MethodDef { get; set; }
public ReturnInfo ReturnInfo { get; set; }
public List<ParamInfo> ParamInfos { get; set; }
public void Init()
{
for(int i = 0; i < ParamInfos.Count; i++)
{
ParamInfos[i].Index = i;
}
Sig = CreateCallSigName();
}
public void TransfromSigTypes(Func<TypeInfo, bool, TypeInfo> transformer)
{
ReturnInfo.Type = transformer(ReturnInfo.Type, true);
foreach(var paramType in ParamInfos)
{
paramType.Type = transformer(paramType.Type, false);
}
}
public string CreateCallSigName()
{
var n = new StringBuilder();
n.Append(ReturnInfo.Type.CreateSigName());
foreach(var param in ParamInfos)
{
n.Append(param.Type.CreateSigName());
}
return n.ToString();
}
public string CreateInvokeSigName()
{
var n = new StringBuilder();
n.Append(ReturnInfo.Type.CreateSigName());
foreach (var param in ParamInfos)
{
n.Append(param.Type.CreateSigName());
}
return n.ToString();
}
public override bool Equals(object obj)
{
return Equals((MethodDesc)obj);
}
public bool Equals(MethodDesc other)
{
return Sig == other.Sig;
}
public override int GetHashCode()
{
return Sig.GetHashCode();
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 28e06667d06f37b4990b16f54f903a35
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,30 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HybridCLR.Editor.ABI
{
public class ParamInfo
{
public TypeInfo Type { get; set; }
public int Index { get; set; }
}
public class ReturnInfo
{
public TypeInfo Type { get; set; }
public bool IsVoid => Type.PorType == ParamOrReturnType.VOID;
public override string ToString()
{
return Type.GetTypeName();
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: f2ba16cf4bf82374c814789b6ced3abd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,27 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HybridCLR.Editor.ABI
{
public enum ParamOrReturnType
{
VOID,
I1,
U1,
I2,
U2,
I4,
U4,
I8,
U8,
R4,
R8,
I,
U,
TYPEDBYREF,
STRUCT,
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 80682e47c38a2f04f8af94d356688cf0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,10 +0,0 @@
namespace HybridCLR.Editor.ABI
{
public enum PlatformABI
{
Universal32,
Universal64,
Arm64,
WebGL32,
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: b9f06ff0612105b4ea20e0309e759e24
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,102 +0,0 @@
using dnlib.DotNet;
using HybridCLR.Editor.Meta;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace HybridCLR.Editor.ABI
{
public class TypeCreator
{
private readonly Dictionary<TypeSig, TypeInfo> _typeInfoCache = new Dictionary<TypeSig, TypeInfo>(TypeEqualityComparer.Instance);
private int _nextStructId = 0;
public TypeInfo CreateTypeInfo(TypeSig type)
{
type = type.RemovePinnedAndModifiers();
if (!_typeInfoCache.TryGetValue(type, out var typeInfo))
{
typeInfo = CreateTypeInfo0(type);
_typeInfoCache.Add(type, typeInfo);
}
return typeInfo;
}
TypeInfo CreateTypeInfo0(TypeSig type)
{
type = type.RemovePinnedAndModifiers();
if (type.IsByRef)
{
return TypeInfo.s_u;
}
switch (type.ElementType)
{
case ElementType.Void: return TypeInfo.s_void;
case ElementType.Boolean: return TypeInfo.s_u1;
case ElementType.I1: return TypeInfo.s_i1;
case ElementType.U1: return TypeInfo.s_u1;
case ElementType.I2: return TypeInfo.s_i2;
case ElementType.Char:
case ElementType.U2: return TypeInfo.s_u2;
case ElementType.I4: return TypeInfo.s_i4;
case ElementType.U4: return TypeInfo.s_u4;
case ElementType.I8: return TypeInfo.s_i8;
case ElementType.U8: return TypeInfo.s_u8;
case ElementType.R4: return TypeInfo.s_r4;
case ElementType.R8: return TypeInfo.s_r8;
case ElementType.I: return TypeInfo.s_i;
case ElementType.U:
case ElementType.String:
case ElementType.Ptr:
case ElementType.ByRef:
case ElementType.Class:
case ElementType.Array:
case ElementType.SZArray:
case ElementType.FnPtr:
case ElementType.Object:
case ElementType.Module:
case ElementType.Var:
case ElementType.MVar:
return TypeInfo.s_u;
case ElementType.TypedByRef: return TypeInfo.s_typedByRef;
case ElementType.ValueType:
{
TypeDef typeDef = type.ToTypeDefOrRef().ResolveTypeDef();
if (typeDef == null)
{
throw new Exception($"type:{type} definition could not be found. Please try `HybridCLR/Genergate/LinkXml`, then Build once to generate the AOT dll, and then regenerate the bridge function");
}
if (typeDef.IsEnum)
{
return CreateTypeInfo(typeDef.GetEnumUnderlyingType());
}
return CreateValueType(type);
}
case ElementType.GenericInst:
{
GenericInstSig gis = (GenericInstSig)type;
if (!gis.GenericType.IsValueType)
{
return TypeInfo.s_u;
}
TypeDef typeDef = gis.GenericType.ToTypeDefOrRef().ResolveTypeDef();
if (typeDef.IsEnum)
{
return CreateTypeInfo(typeDef.GetEnumUnderlyingType());
}
return CreateValueType(type);
}
default: throw new NotSupportedException($"{type.ElementType}");
}
}
protected TypeInfo CreateValueType(TypeSig type)
{
return new TypeInfo(ParamOrReturnType.STRUCT, type, _nextStructId++);
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 0b1df5760b488fa43a68843c46fda63a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,116 +0,0 @@
using dnlib.DotNet;
using HybridCLR.Editor.Meta;
using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
namespace HybridCLR.Editor.ABI
{
public class TypeInfo : IEquatable<TypeInfo>
{
public static readonly TypeInfo s_void = new TypeInfo(ParamOrReturnType.VOID);
public static readonly TypeInfo s_i1 = new TypeInfo(ParamOrReturnType.I1);
public static readonly TypeInfo s_u1 = new TypeInfo(ParamOrReturnType.U1);
public static readonly TypeInfo s_i2 = new TypeInfo(ParamOrReturnType.I2);
public static readonly TypeInfo s_u2 = new TypeInfo(ParamOrReturnType.U2);
public static readonly TypeInfo s_i4 = new TypeInfo(ParamOrReturnType.I4);
public static readonly TypeInfo s_u4 = new TypeInfo(ParamOrReturnType.U4);
public static readonly TypeInfo s_i8 = new TypeInfo(ParamOrReturnType.I8);
public static readonly TypeInfo s_u8 = new TypeInfo(ParamOrReturnType.U8);
public static readonly TypeInfo s_r4 = new TypeInfo(ParamOrReturnType.R4);
public static readonly TypeInfo s_r8 = new TypeInfo(ParamOrReturnType.R8);
public static readonly TypeInfo s_i = new TypeInfo(ParamOrReturnType.I);
public static readonly TypeInfo s_u = new TypeInfo(ParamOrReturnType.U);
public static readonly TypeInfo s_typedByRef = new TypeInfo(ParamOrReturnType.TYPEDBYREF);
public const string strTypedByRef = "typedbyref";
public TypeInfo(ParamOrReturnType portype, TypeSig klass = null, int typeId = 0)
{
PorType = portype;
Klass = klass;
_typeId = typeId;
}
public ParamOrReturnType PorType { get; }
public TypeSig Klass { get; }
public bool IsStruct => PorType == ParamOrReturnType.STRUCT;
public bool IsPrimitiveType => PorType <= ParamOrReturnType.U;
private readonly int _typeId;
public int TypeId => _typeId;
public bool Equals(TypeInfo other)
{
return PorType == other.PorType && TypeEqualityComparer.Instance.Equals(Klass, other.Klass);
}
public override bool Equals(object obj)
{
return Equals((TypeInfo)obj);
}
public override int GetHashCode()
{
return (int)PorType * 23 + (Klass != null ? TypeEqualityComparer.Instance.GetHashCode(Klass) : 0);
}
public bool NeedExpandValue()
{
return PorType >= ParamOrReturnType.I1 && PorType <= ParamOrReturnType.U2;
}
public string CreateSigName()
{
switch (PorType)
{
case ParamOrReturnType.VOID: return "v";
case ParamOrReturnType.I1: return "i1";
case ParamOrReturnType.U1: return "u1";
case ParamOrReturnType.I2: return "i2";
case ParamOrReturnType.U2: return "u2";
case ParamOrReturnType.I4: return "i4";
case ParamOrReturnType.U4: return "u4";
case ParamOrReturnType.I8: return "i8";
case ParamOrReturnType.U8: return "u8";
case ParamOrReturnType.R4: return "r4";
case ParamOrReturnType.R8: return "r8";
case ParamOrReturnType.I: return "i";
case ParamOrReturnType.U: return "u";
case ParamOrReturnType.TYPEDBYREF: return strTypedByRef;
case ParamOrReturnType.STRUCT: return $"s{_typeId}";
default: throw new NotSupportedException(PorType.ToString());
};
}
public string GetTypeName()
{
switch (PorType)
{
case ParamOrReturnType.VOID: return "void";
case ParamOrReturnType.I1: return "int8_t";
case ParamOrReturnType.U1: return "uint8_t";
case ParamOrReturnType.I2: return "int16_t";
case ParamOrReturnType.U2: return "uint16_t";
case ParamOrReturnType.I4: return "int32_t";
case ParamOrReturnType.U4: return "uint32_t";
case ParamOrReturnType.I8: return "int64_t";
case ParamOrReturnType.U8: return "uint64_t";
case ParamOrReturnType.R4: return "float";
case ParamOrReturnType.R8: return "double";
case ParamOrReturnType.I: return "intptr_t";
case ParamOrReturnType.U: return "uintptr_t";
case ParamOrReturnType.TYPEDBYREF: return "Il2CppTypedRef";
case ParamOrReturnType.STRUCT: return $"__struct_{_typeId}__";
default: throw new NotImplementedException(PorType.ToString());
};
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: ffafce7f1f0bf614d95b48ca39385377
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,181 +0,0 @@
using dnlib.DotNet;
using HybridCLR.Editor.Meta;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace HybridCLR.Editor.ABI
{
public class ValueTypeSizeAligmentCalculator
{
public static ValueTypeSizeAligmentCalculator Caculator64 { get; } = new ValueTypeSizeAligmentCalculator(false);
public static ValueTypeSizeAligmentCalculator Caculator32 { get; } = new ValueTypeSizeAligmentCalculator(true);
public ValueTypeSizeAligmentCalculator(bool arch32)
{
_referenceSize = arch32 ? 4 : 8;
}
private readonly int _referenceSize;
private static bool IsIgnoreField(FieldDef field)
{
var ignoreAttr = field.CustomAttributes.Where(a => a.AttributeType.FullName == "UnityEngine.Bindings.IgnoreAttribute").FirstOrDefault();
if (ignoreAttr == null)
{
return false;
}
CANamedArgument arg = ignoreAttr.GetProperty("DoesNotContributeToSize");
if(arg != null && (bool)arg.Value)
{
//Debug.Log($"IgnoreField.DoesNotContributeToSize = true:{field}");
return true;
}
return false;
}
private (int Size, int Aligment) SizeAndAligmentOfStruct(TypeSig type)
{
int totalSize = 0;
int packAligment = 8;
int maxAligment = 1;
TypeDef typeDef = type.ToTypeDefOrRef().ResolveTypeDefThrow();
List<TypeSig> klassInst = type.ToGenericInstSig()?.GenericArguments?.ToList();
GenericArgumentContext ctx = klassInst != null ? new GenericArgumentContext(klassInst, null) : null;
ClassLayout sa = typeDef.ClassLayout;
if (sa != null && sa.PackingSize > 0)
{
packAligment = sa.PackingSize;
}
bool useSLSize = true;
foreach (FieldDef field in typeDef.Fields)
{
if (field.IsStatic)
{
continue;
}
TypeSig fieldType = ctx != null ? MetaUtil.Inflate(field.FieldType, ctx) : field.FieldType;
var (fs, fa) = SizeAndAligmentOf(fieldType);
fa = Math.Min(fa, packAligment);
if (fa > maxAligment)
{
maxAligment = fa;
}
if (IsIgnoreField(field))
{
continue;
}
if (typeDef.Layout.HasFlag(dnlib.DotNet.TypeAttributes.ExplicitLayout))
{
int offset = (int)field.FieldOffset.Value;
totalSize = Math.Max(totalSize, offset + fs);
if (sa != null && offset > sa.ClassSize)
{
useSLSize = false;
}
}
else
{
if (totalSize % fa != 0)
{
totalSize = (totalSize + fa - 1) / fa * fa;
}
totalSize += fs;
if (sa != null && totalSize > sa.ClassSize)
{
useSLSize = false;
}
}
}
if (totalSize == 0)
{
totalSize = maxAligment;
}
if (totalSize % maxAligment != 0)
{
totalSize = (totalSize + maxAligment - 1) / maxAligment * maxAligment;
}
if (sa != null && sa.ClassSize > 0)
{
if (/*sa.Value == LayoutKind.Explicit &&*/ useSLSize)
{
totalSize = (int)sa.ClassSize;
while(totalSize % maxAligment != 0)
{
maxAligment /= 2;
}
}
}
return (totalSize, maxAligment);
}
public (int Size, int Aligment) SizeAndAligmentOf(TypeSig type)
{
type = type.RemovePinnedAndModifiers();
if (type.IsByRef || !type.IsValueType || type.IsArray)
return (_referenceSize, _referenceSize);
switch (type.ElementType)
{
case ElementType.Void: throw new NotSupportedException(type.ToString());
case ElementType.Boolean:
case ElementType.I1:
case ElementType.U1: return (1, 1);
case ElementType.Char:
case ElementType.I2:
case ElementType.U2: return (2, 2);
case ElementType.I4:
case ElementType.U4: return (4, 4);
case ElementType.I8:
case ElementType.U8: return (8, 8);
case ElementType.R4: return (4, 4);
case ElementType.R8: return (8, 8);
case ElementType.I:
case ElementType.U:
case ElementType.String:
case ElementType.Ptr:
case ElementType.ByRef:
case ElementType.Class:
case ElementType.Array:
case ElementType.SZArray:
case ElementType.FnPtr:
case ElementType.Object:
case ElementType.Module: return (_referenceSize, _referenceSize);
case ElementType.TypedByRef: return SizeAndAligmentOfStruct(type);
case ElementType.ValueType:
{
TypeDef typeDef = type.ToTypeDefOrRef().ResolveTypeDef();
if (typeDef.IsEnum)
{
return SizeAndAligmentOf(typeDef.GetEnumUnderlyingType());
}
return SizeAndAligmentOfStruct(type);
}
case ElementType.GenericInst:
{
GenericInstSig gis = (GenericInstSig)type;
if (!gis.GenericType.IsValueType)
{
return (_referenceSize, _referenceSize);
}
TypeDef typeDef = gis.GenericType.ToTypeDefOrRef().ResolveTypeDef();
if (typeDef.IsEnum)
{
return SizeAndAligmentOf(typeDef.GetEnumUnderlyingType());
}
return SizeAndAligmentOfStruct(type);
}
default: throw new NotSupportedException(type.ToString());
}
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: b7af32bdf1cf55c42bfc449820d401cb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: b4071bf66ac9c544487ae88b5ee9b20a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,208 +0,0 @@
using dnlib.DotNet;
using HybridCLR.Editor.Meta;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace HybridCLR.Editor.AOT
{
public class Analyzer
{
public class Options
{
public AssemblyReferenceDeepCollector Collector { get; set; }
public int MaxIterationCount { get; set; }
}
private readonly int _maxInterationCount;
private readonly AssemblyReferenceDeepCollector _assemblyCollector;
private readonly HashSet<GenericClass> _genericTypes = new HashSet<GenericClass>();
private readonly HashSet<GenericMethod> _genericMethods = new HashSet<GenericMethod>();
private List<GenericMethod> _processingMethods = new List<GenericMethod>();
private List<GenericMethod> _newMethods = new List<GenericMethod>();
public IReadOnlyCollection<GenericClass> GenericTypes => _genericTypes;
public IReadOnlyCollection<GenericMethod> GenericMethods => _genericMethods;
private readonly MethodReferenceAnalyzer _methodReferenceAnalyzer;
private readonly HashSet<string> _hotUpdateAssemblyFiles;
public ConstraintContext ConstraintContext { get; } = new ConstraintContext();
public List<GenericClass> AotGenericTypes { get; } = new List<GenericClass>();
public List<GenericMethod> AotGenericMethods { get; } = new List<GenericMethod>();
public Analyzer(Options options)
{
_assemblyCollector = options.Collector;
_maxInterationCount = options.MaxIterationCount;
_methodReferenceAnalyzer = new MethodReferenceAnalyzer(this.OnNewMethod);
_hotUpdateAssemblyFiles = new HashSet<string>(options.Collector.GetRootAssemblyNames().Select(assName => assName + ".dll"));
}
private void TryAddAndWalkGenericType(GenericClass gc)
{
if (gc == null)
{
return;
}
gc = gc.ToGenericShare();
if (_genericTypes.Add(gc) && NeedWalk(null, gc.Type))
{
WalkType(gc);
}
}
private bool NeedWalk(MethodDef callFrom, TypeDef type)
{
return _hotUpdateAssemblyFiles.Contains(type.Module.Name) || callFrom == null || callFrom.HasGenericParameters;
}
private bool IsAotType(TypeDef type)
{
return !_hotUpdateAssemblyFiles.Contains(type.Module.Name);
}
private bool IsAotGenericMethod(MethodDef method)
{
return IsAotType(method.DeclaringType) && method.HasGenericParameters;
}
private void OnNewMethod(MethodDef methodDef, List<TypeSig> klassGenericInst, List<TypeSig> methodGenericInst, GenericMethod method)
{
if(method == null)
{
return;
}
if (NeedWalk(methodDef, method.Method.DeclaringType) && _genericMethods.Add(method))
{
_newMethods.Add(method);
}
if (method.KlassInst != null)
{
TryAddAndWalkGenericType(new GenericClass(method.Method.DeclaringType, method.KlassInst));
}
}
private void TryAddMethodNotWalkType(GenericMethod method)
{
if (method == null)
{
return;
}
if (NeedWalk(null, method.Method.DeclaringType) && _genericMethods.Add(method))
{
_newMethods.Add(method);
}
}
private void WalkType(GenericClass gc)
{
//Debug.Log($"typespec:{sig} {sig.GenericType} {sig.GenericType.TypeDefOrRef.ResolveTypeDef()}");
//Debug.Log($"== walk generic type:{new GenericInstSig(gc.Type.ToTypeSig().ToClassOrValueTypeSig(), gc.KlassInst)}");
ITypeDefOrRef baseType = gc.Type.BaseType;
if (baseType != null && baseType.TryGetGenericInstSig() != null)
{
GenericClass parentType = GenericClass.ResolveClass((TypeSpec)baseType, new GenericArgumentContext(gc.KlassInst, null));
TryAddAndWalkGenericType(parentType);
}
foreach (var method in gc.Type.Methods)
{
if (method.HasGenericParameters || !method.HasBody || method.Body.Instructions == null)
{
continue;
}
var gm = new GenericMethod(method, gc.KlassInst, null).ToGenericShare();
//Debug.Log($"add method:{gm.Method} {gm.KlassInst}");
TryAddMethodNotWalkType(gm);
}
}
private void WalkType(TypeDef typeDef)
{
if (typeDef.HasGenericParameters)
{
return;
}
ITypeDefOrRef baseType = typeDef.BaseType;
if (baseType != null && baseType.TryGetGenericInstSig() != null)
{
GenericClass gc = GenericClass.ResolveClass((TypeSpec)baseType, null);
TryAddAndWalkGenericType(gc);
}
}
private void Prepare()
{
// 将所有非泛型函数全部加入函数列表同时立马walk这些method。
// 后续迭代中将只遍历MethodSpec
foreach (var ass in _assemblyCollector.GetLoadedModulesOfRootAssemblies())
{
foreach (TypeDef typeDef in ass.GetTypes())
{
WalkType(typeDef);
}
for (uint rid = 1, n = ass.Metadata.TablesStream.TypeSpecTable.Rows; rid <= n; rid++)
{
var ts = ass.ResolveTypeSpec(rid);
var cs = GenericClass.ResolveClass(ts, null)?.ToGenericShare();
if (cs != null)
{
TryAddAndWalkGenericType(cs);
}
}
for (uint rid = 1, n = ass.Metadata.TablesStream.MethodSpecTable.Rows; rid <= n; rid++)
{
var ms = ass.ResolveMethodSpec(rid);
var gm = GenericMethod.ResolveMethod(ms, null)?.ToGenericShare();
TryAddMethodNotWalkType(gm);
}
}
Debug.Log($"PostPrepare genericTypes:{_genericTypes.Count} genericMethods:{_genericMethods.Count} newMethods:{_newMethods.Count}");
}
private void RecursiveCollect()
{
for (int i = 0; i < _maxInterationCount && _newMethods.Count > 0; i++)
{
var temp = _processingMethods;
_processingMethods = _newMethods;
_newMethods = temp;
_newMethods.Clear();
foreach (var method in _processingMethods)
{
_methodReferenceAnalyzer.WalkMethod(method.Method, method.KlassInst, method.MethodInst);
}
Debug.Log($"iteration:[{i}] genericClass:{_genericTypes.Count} genericMethods:{_genericMethods.Count} newMethods:{_newMethods.Count}");
}
}
private void FilterAOTGenericTypeAndMethods()
{
ConstraintContext cc = this.ConstraintContext;
AotGenericTypes.AddRange(_genericTypes.Where(type => IsAotType(type.Type)).Select(gc => cc.ApplyConstraints(gc)));
AotGenericMethods.AddRange(_genericMethods.Where(method => IsAotGenericMethod(method.Method)).Select(gm => cc.ApplyConstraints(gm)));
}
public void Run()
{
Prepare();
RecursiveCollect();
FilterAOTGenericTypeAndMethods();
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 30bbf4a80a6cf3a43b3f489747d9dd6a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,73 +0,0 @@
using dnlib.DotNet;
using HybridCLR.Editor.Meta;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HybridCLR.Editor.AOT
{
public class ConstraintContext
{
public class ImplType
{
public TypeSig BaseType { get; }
public List<TypeSig> Interfaces { get; }
public bool ValueType { get; }
private readonly int _hash;
public ImplType(TypeSig baseType, List<TypeSig> interfaces, bool valueType)
{
BaseType = baseType;
Interfaces = interfaces;
ValueType = valueType;
_hash = ComputHash();
}
public override bool Equals(object obj)
{
ImplType o = (ImplType)obj;
return MetaUtil.EqualsTypeSig(this.BaseType, o.BaseType)
&& MetaUtil.EqualsTypeSigArray(this.Interfaces, o.Interfaces)
&& this.ValueType == o.ValueType;
}
public override int GetHashCode()
{
return _hash;
}
private int ComputHash()
{
int hash = 0;
if (BaseType != null)
{
hash = HashUtil.CombineHash(hash, TypeEqualityComparer.Instance.GetHashCode(BaseType));
}
if (Interfaces.Count > 0)
{
hash = HashUtil.CombineHash(hash, HashUtil.ComputHash(Interfaces));
}
return hash;
}
}
public HashSet<ImplType> ImplTypes { get; } = new HashSet<ImplType>();
public GenericClass ApplyConstraints(GenericClass gc)
{
return gc;
}
public GenericMethod ApplyConstraints(GenericMethod gm)
{
return gm;
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 812d81a75b690394bbe16ef5f0bcbc46
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,139 +0,0 @@
using HybridCLR.Editor.Meta;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using UnityEngine;
namespace HybridCLR.Editor.AOT
{
public class GenericReferenceWriter
{
private static readonly Dictionary<Type, string> _typeNameMapping = new Dictionary<Type, string>
{
{typeof(bool), "bool" },
{typeof(byte), "byte" },
{typeof(sbyte), "sbyte" },
{typeof(short), "short" },
{typeof(ushort), "ushort" },
{typeof(int), "int" },
{typeof(uint), "uint" },
{typeof(long), "long" },
{typeof(ulong), "ulong" },
{typeof(float), "float" },
{typeof(double), "double" },
{typeof(object), "object" },
{typeof(string), "string" },
};
private readonly Dictionary<string, string> _typeSimpleNameMapping = new Dictionary<string, string>();
private readonly Regex _systemTypePattern;
private readonly Regex _genericPattern = new Regex(@"`\d+");
public GenericReferenceWriter()
{
foreach (var e in _typeNameMapping)
{
_typeSimpleNameMapping.Add(e.Key.FullName, e.Value);
}
_systemTypePattern = new Regex(string.Join("|", _typeSimpleNameMapping.Keys.Select (k => $@"\b{k}\b")));
}
public string PrettifyTypeSig(string typeSig)
{
string s = _genericPattern.Replace(typeSig, "").Replace('/', '.');
return _systemTypePattern.Replace(s, m => _typeSimpleNameMapping[m.Groups[0].Value]);
}
public string PrettifyMethodSig(string methodSig)
{
string s = PrettifyTypeSig(methodSig).Replace("::", ".");
if (s.Contains(".ctor("))
{
s = "new " + s.Replace(".ctor(", "(");
}
return s;
}
public void Write(List<GenericClass> types, List<GenericMethod> methods, string outputFile)
{
string parentDir = Directory.GetParent(outputFile).FullName;
Directory.CreateDirectory(parentDir);
List<string> codes = new List<string>();
codes.Add("using System.Collections.Generic;");
codes.Add("public class AOTGenericReferences : UnityEngine.MonoBehaviour");
codes.Add("{");
codes.Add("");
codes.Add("\t// {{ AOT assemblies");
codes.Add("\tpublic static readonly IReadOnlyList<string> PatchedAOTAssemblyList = new List<string>");
codes.Add("\t{");
List<dnlib.DotNet.ModuleDef> modules = new HashSet<dnlib.DotNet.ModuleDef>(
types.Select(t => t.Type.Module).Concat(methods.Select(m => m.Method.Module))).ToList();
modules.Sort((a, b) => a.Name.CompareTo(b.Name));
foreach (dnlib.DotNet.ModuleDef module in modules)
{
codes.Add($"\t\t\"{module.Name}\",");
}
codes.Add("\t};");
codes.Add("\t// }}");
codes.Add("");
codes.Add("\t// {{ constraint implement type");
codes.Add("\t// }} ");
codes.Add("");
codes.Add("\t// {{ AOT generic types");
List<string> typeNames = types.Select(t => PrettifyTypeSig(t.ToTypeSig().ToString())).ToList();
typeNames.Sort(string.CompareOrdinal);
foreach(var typeName in typeNames)
{
codes.Add($"\t// {typeName}");
}
codes.Add("\t// }}");
codes.Add("");
codes.Add("\tpublic void RefMethods()");
codes.Add("\t{");
List<(string, string, string)> methodTypeAndNames = methods.Select(m =>
(PrettifyTypeSig(m.Method.DeclaringType.ToString()), PrettifyMethodSig(m.Method.Name), PrettifyMethodSig(m.ToMethodSpec().ToString())))
.ToList();
methodTypeAndNames.Sort((a, b) =>
{
int c = String.Compare(a.Item1, b.Item1, StringComparison.Ordinal);
if (c != 0)
{
return c;
}
c = String.Compare(a.Item2, b.Item2, StringComparison.Ordinal);
if (c != 0)
{
return c;
}
return String.Compare(a.Item3, b.Item3, StringComparison.Ordinal);
});
foreach(var method in methodTypeAndNames)
{
codes.Add($"\t\t// {PrettifyMethodSig(method.Item3)}");
}
codes.Add("\t}");
codes.Add("}");
var utf8WithoutBom = new System.Text.UTF8Encoding(false);
File.WriteAllText(outputFile, string.Join("\n", codes), utf8WithoutBom);
Debug.Log($"[GenericReferenceWriter] write {outputFile}");
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: d1243cf04685361478972f93b5ca868a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: f80d2287f01c89642a74b0a60f7a3305
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,254 +0,0 @@
using System;
using HybridCLR.Editor.Installer;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using UnityEditor;
using System.Reflection;
using HybridCLR.Editor.Settings;
#if (UNITY_2020 || UNITY_2021) && UNITY_IOS
using UnityEditor.Build;
using UnityEditor.Callbacks;
using UnityEditor.iOS.Xcode;
using UnityEngine;
namespace HybridCLR.Editor.BuildProcessors
{
public static class AddLil2cppSourceCodeToXcodeproj2021OrOlder
{
//[MenuItem("Test/GenProj")]
//public static void Modify()
//{
// OnPostProcessBuild(BuildTarget.iOS, $"{SettingsUtil.ProjectDir}/Build-iOS");
//}
//[MenuItem("Test/CreateLumps")]
//public static void CreateLumpsCmd()
//{
// CreateLumps($"{SettingsUtil.LocalIl2CppDir}/libil2cpp", $"{SettingsUtil.HybridCLRDataDir}/lumps");
//}
[PostProcessBuild]
public static void OnPostProcessBuild(BuildTarget target, string pathToBuiltProject)
{
if (target != BuildTarget.iOS || !HybridCLRSettings.Instance.enable)
return;
/*
* 1. 生成lump并且添加到工程
3. 将libil2cpp目录复制到 Library/. 删除旧的. search paths里修改 libil2cpp/include为libil2cpp
3. Libraries/bdwgc/include -> Libraries/external/bdwgc/include
4. 将external目录复制到 Library/external。删除旧目录
5. 将Library/external/baselib/Platforms/OSX改名为 IOS 全大写
6. 将 external/zlib下c 文件添加到工程
7. 移除libil2cpp.a
8. Include path add libil2cpp/os/ClassLibraryPAL/brotli/include
9. add external/xxHash
*/
string pbxprojFile = $"{pathToBuiltProject}/Unity-iPhone.xcodeproj/project.pbxproj";
string srcLibil2cppDir = $"{SettingsUtil.LocalIl2CppDir}/libil2cpp";
string dstLibil2cppDir = $"{pathToBuiltProject}/Libraries/libil2cpp";
string lumpDir = $"{pathToBuiltProject}/Libraries/lumps";
string srcExternalDir = $"{SettingsUtil.LocalIl2CppDir}/external";
string dstExternalDir = $"{pathToBuiltProject}/Libraries/external";
//RemoveExternalLibil2cppOption(srcExternalDir, dstExternalDir);
CopyLibil2cppToXcodeProj(srcLibil2cppDir, dstLibil2cppDir);
CopyExternalToXcodeProj(srcExternalDir, dstExternalDir);
var lumpFiles = CreateLumps(dstLibil2cppDir, lumpDir);
var extraSources = GetExtraSourceFiles(dstExternalDir, dstLibil2cppDir);
var cflags = new List<string>()
{
"-DIL2CPP_MONO_DEBUGGER_DISABLED",
};
ModifyPBXProject(pathToBuiltProject, pbxprojFile, lumpFiles, extraSources, cflags);
}
private static string GetRelativePathFromProj(string path)
{
return path.Substring(path.IndexOf("Libraries", StringComparison.Ordinal)).Replace('\\', '/');
}
private static void ModifyPBXProject(string pathToBuiltProject, string pbxprojFile, List<LumpFile> lumpFiles, List<string> extraFiles, List<string> cflags)
{
var proj = new PBXProject();
proj.ReadFromFile(pbxprojFile);
string targetGUID = proj.GetUnityFrameworkTargetGuid();
// 移除旧的libil2cpp.a
var libil2cppGUID = proj.FindFileGuidByProjectPath("Libraries/libil2cpp.a");
if (!string.IsNullOrEmpty(libil2cppGUID))
{
proj.RemoveFileFromBuild(targetGUID, libil2cppGUID);
proj.RemoveFile(libil2cppGUID);
File.Delete(Path.Combine(pathToBuiltProject, "Libraries", "libil2cpp.a"));
}
//var lumpGroupGuid = proj.AddFile("Lumps", $"Classes/Lumps", PBXSourceTree.Group);
foreach (var lumpFile in lumpFiles)
{
string lumpFileName = Path.GetFileName(lumpFile.lumpFile);
string projPathOfFile = $"Classes/Lumps/{lumpFileName}";
string relativePathOfFile = GetRelativePathFromProj(lumpFile.lumpFile);
string lumpGuid = proj.FindFileGuidByProjectPath(projPathOfFile);
if (!string.IsNullOrEmpty(lumpGuid))
{
proj.RemoveFileFromBuild(targetGUID, lumpGuid);
proj.RemoveFile(lumpGuid);
}
lumpGuid = proj.AddFile(relativePathOfFile, projPathOfFile, PBXSourceTree.Source);
proj.AddFileToBuild(targetGUID, lumpGuid);
}
foreach (var extraFile in extraFiles)
{
string projPathOfFile = $"Classes/Extrals/{Path.GetFileName(extraFile)}";
string extraFileGuid = proj.FindFileGuidByProjectPath(projPathOfFile);
if (!string.IsNullOrEmpty(extraFileGuid))
{
proj.RemoveFileFromBuild(targetGUID, extraFileGuid);
proj.RemoveFile(extraFileGuid);
//Debug.LogWarning($"remove exist extra file:{projPathOfFile} guid:{extraFileGuid}");
}
var lumpGuid = proj.AddFile(GetRelativePathFromProj(extraFile), projPathOfFile, PBXSourceTree.Source);
proj.AddFileToBuild(targetGUID, lumpGuid);
}
foreach(var configName in proj.BuildConfigNames())
{
//Debug.Log($"build config:{bcn}");
string configGuid = proj.BuildConfigByName(targetGUID, configName);
string headerSearchPaths = "HEADER_SEARCH_PATHS";
string hspProp = proj.GetBuildPropertyForConfig(configGuid, headerSearchPaths);
//Debug.Log($"config guid:{configGuid} prop:{hspProp}");
string newPro = hspProp.Replace("libil2cpp/include", "libil2cpp")
.Replace("Libraries/bdwgc", "Libraries/external/bdwgc");
if (!newPro.Contains("Libraries/libil2cpp/os/ClassLibraryPAL/brotli/include"))
{
newPro += " $(SRCROOT)/Libraries/libil2cpp/os/ClassLibraryPAL/brotli/include";
}
if (!newPro.Contains("Libraries/external/xxHash"))
{
newPro += " $(SRCROOT)/Libraries/external/xxHash";
}
//Debug.Log($"config:{bcn} new prop:{newPro}");
proj.SetBuildPropertyForConfig(configGuid, headerSearchPaths, newPro);
string cflagKey = "OTHER_CFLAGS";
string cfProp = proj.GetBuildPropertyForConfig(configGuid, cflagKey);
foreach (var flag in cflags)
{
if (!cfProp.Contains(flag))
{
cfProp += " " + flag;
}
}
if (configName.Contains("Debug") && !cfProp.Contains("-DIL2CPP_DEBUG="))
{
cfProp += " -DIL2CPP_DEBUG=1 -DDEBUG=1";
}
proj.SetBuildPropertyForConfig(configGuid, cflagKey, cfProp);
}
proj.WriteToFile(pbxprojFile);
}
private static void CopyLibil2cppToXcodeProj(string srcLibil2cppDir, string dstLibil2cppDir)
{
BashUtil.RemoveDir(dstLibil2cppDir);
BashUtil.CopyDir(srcLibil2cppDir, dstLibil2cppDir, true);
}
private static void CopyExternalToXcodeProj(string srcExternalDir, string dstExternalDir)
{
BashUtil.RemoveDir(dstExternalDir);
BashUtil.CopyDir(srcExternalDir, dstExternalDir, true);
string baselibPlatfromsDir = $"{dstExternalDir}/baselib/Platforms";
BashUtil.RemoveDir($"{baselibPlatfromsDir}/IOS");
BashUtil.CopyDir($"{baselibPlatfromsDir}/OSX", $"{baselibPlatfromsDir}/IOS", true);
}
class LumpFile
{
public List<string> cppFiles = new List<string>();
public readonly string lumpFile;
public readonly string il2cppConfigFile;
public LumpFile(string lumpFile, string il2cppConfigFile)
{
this.lumpFile = lumpFile;
this.il2cppConfigFile = il2cppConfigFile;
this.cppFiles.Add(il2cppConfigFile);
}
public void SaveFile()
{
var lumpFileContent = new List<string>();
foreach (var file in cppFiles)
{
lumpFileContent.Add($"#include \"{GetRelativePathFromProj(file)}\"");
}
File.WriteAllLines(lumpFile, lumpFileContent, Encoding.UTF8);
Debug.Log($"create lump file:{lumpFile}");
}
}
private static List<LumpFile> CreateLumps(string libil2cppDir, string outputDir)
{
BashUtil.RecreateDir(outputDir);
string il2cppConfigFile = $"{libil2cppDir}/il2cpp-config.h";
var lumpFiles = new List<LumpFile>();
int lumpFileIndex = 0;
foreach (var cppDir in Directory.GetDirectories(libil2cppDir, "*", SearchOption.AllDirectories).Concat(new string[] {libil2cppDir}))
{
var lumpFile = new LumpFile($"{outputDir}/lump_{Path.GetFileName(cppDir)}_{lumpFileIndex}.cpp", il2cppConfigFile);
foreach (var file in Directory.GetFiles(cppDir, "*.cpp", SearchOption.TopDirectoryOnly))
{
lumpFile.cppFiles.Add(file);
}
lumpFile.SaveFile();
lumpFiles.Add(lumpFile);
++lumpFileIndex;
}
var mmFiles = Directory.GetFiles(libil2cppDir, "*.mm", SearchOption.AllDirectories);
if (mmFiles.Length > 0)
{
var lumpFile = new LumpFile($"{outputDir}/lump_mm.mm", il2cppConfigFile);
foreach (var file in mmFiles)
{
lumpFile.cppFiles.Add(file);
}
lumpFile.SaveFile();
lumpFiles.Add(lumpFile);
}
return lumpFiles;
}
private static List<string> GetExtraSourceFiles(string externalDir, string libil2cppDir)
{
var files = new List<string>();
foreach (string extraDir in new string[]
{
$"{externalDir}/zlib",
$"{externalDir}/xxHash",
$"{libil2cppDir}/os/ClassLibraryPAL/brotli",
})
{
if (!Directory.Exists(extraDir))
{
continue;
}
files.AddRange(Directory.GetFiles(extraDir, "*.c", SearchOption.AllDirectories));
}
return files;
}
}
}
#endif

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 61948fcb1bc40ba47b8c10b0ae801ebb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,57 +0,0 @@
using HybridCLR.Editor.Installer;
using HybridCLR.Editor.Settings;
using System.IO;
using System.Text;
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Callbacks;
using UnityEngine;
#if UNITY_2022_2_OR_NEWER && UNITY_IOS
namespace HybridCLR.Editor.BuildProcessors
{
public static class AddLil2cppSourceCodeToXcodeproj2022OrNewer
{
//[MenuItem("HybridCLR/Modfiyxcode")]
//public static void Modify()
//{
// OnPostProcessBuild(BuildTarget.iOS, $"{SettingsUtil.ProjectDir}/Build-iOS");
//}
[PostProcessBuild]
public static void OnPostProcessBuild(BuildTarget target, string pathToBuiltProject)
{
if (target != BuildTarget.iOS || !HybridCLRSettings.Instance.enable)
return;
string pbxprojFile = $"{pathToBuiltProject}/Unity-iPhone.xcodeproj/project.pbxproj";
RemoveExternalLibil2cppOption(pbxprojFile);
CopyLibil2cppToXcodeProj(pathToBuiltProject);
}
private static void RemoveExternalLibil2cppOption(string pbxprojFile)
{
string pbxprojContent = File.ReadAllText(pbxprojFile, Encoding.UTF8);
string removeBuildOption = @"--external-lib-il2-cpp=\""$PROJECT_DIR/Libraries/libil2cpp.a\""";
if (!pbxprojContent.Contains(removeBuildOption))
{
//throw new BuildFailedException("modified project.pbxproj fail");
Debug.LogError("[AddLil2cppSourceCodeToXcodeproj] modified project.pbxproj fail");
return;
}
pbxprojContent = pbxprojContent.Replace(removeBuildOption, "");
File.WriteAllText(pbxprojFile, pbxprojContent, Encoding.UTF8);
Debug.Log($"[AddLil2cppSourceCodeToXcodeproj] remove il2cpp build option '{removeBuildOption}' from file '{pbxprojFile}'");
}
private static void CopyLibil2cppToXcodeProj(string pathToBuiltProject)
{
string srcLibil2cppDir = $"{SettingsUtil.LocalIl2CppDir}/libil2cpp";
string destLibil2cppDir = $"{pathToBuiltProject}/Il2CppOutputProject/IL2CPP/libil2cpp";
BashUtil.RemoveDir(destLibil2cppDir);
BashUtil.CopyDir(srcLibil2cppDir, destLibil2cppDir, true);
}
}
}
#endif

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: a4ce072f7e4a17248a3d9ebfd011356b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,72 +0,0 @@
using HybridCLR.Editor.Settings;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEngine;
using static UnityEngine.GraphicsBuffer;
namespace HybridCLR.Editor.BuildProcessors
{
internal class CheckSettings : IPreprocessBuildWithReport
{
public int callbackOrder => 0;
public void OnPreprocessBuild(BuildReport report)
{
HybridCLRSettings globalSettings = SettingsUtil.HybridCLRSettings;
if (!globalSettings.enable || globalSettings.useGlobalIl2cpp)
{
string oldIl2cppPath = Environment.GetEnvironmentVariable("UNITY_IL2CPP_PATH");
if (!string.IsNullOrEmpty(oldIl2cppPath))
{
Environment.SetEnvironmentVariable("UNITY_IL2CPP_PATH", "");
Debug.Log($"[CheckSettings] clean process environment variable: UNITY_IL2CPP_PATH, old vlaue:'{oldIl2cppPath}'");
}
}
else
{
string curIl2cppPath = Environment.GetEnvironmentVariable("UNITY_IL2CPP_PATH");
if (curIl2cppPath != SettingsUtil.LocalIl2CppDir)
{
Environment.SetEnvironmentVariable("UNITY_IL2CPP_PATH", SettingsUtil.LocalIl2CppDir);
Debug.Log($"[CheckSettings] UNITY_IL2CPP_PATH old value:'{curIl2cppPath}' new value:'{SettingsUtil.LocalIl2CppDir}'");
}
}
if (!globalSettings.enable)
{
return;
}
BuildTargetGroup buildTargetGroup = BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget);
ScriptingImplementation curScriptingImplementation = PlayerSettings.GetScriptingBackend(buildTargetGroup);
ScriptingImplementation targetScriptingImplementation = ScriptingImplementation.IL2CPP;
if (curScriptingImplementation != targetScriptingImplementation)
{
Debug.LogError($"[CheckSettings] current ScriptingBackend:{curScriptingImplementation}have been switched to:{targetScriptingImplementation} automatically");
PlayerSettings.SetScriptingBackend(buildTargetGroup, targetScriptingImplementation);
}
var installer = new Installer.InstallerController();
if (!installer.HasInstalledHybridCLR())
{
throw new BuildFailedException($"You have not initialized HybridCLR, please install it via menu 'HybridCLR/Installer'");
}
if (installer.PackageVersion != installer.InstalledLibil2cppVersion)
{
throw new BuildFailedException($"You must run `HybridCLR/Installer` after upgrading package");
}
HybridCLRSettings gs = SettingsUtil.HybridCLRSettings;
if (((gs.hotUpdateAssemblies?.Length + gs.hotUpdateAssemblyDefinitions?.Length) ?? 0) == 0)
{
Debug.LogWarning("[CheckSettings] No hot update modules configured in HybridCLRSettings");
}
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: fb4ba063068b17247b2d0233420aa5f0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,107 +0,0 @@
using HybridCLR.Editor.Installer;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEditor.Il2Cpp;
using UnityEditor.UnityLinker;
using UnityEngine;
namespace HybridCLR.Editor.BuildProcessors
{
internal class CopyStrippedAOTAssemblies : IPostprocessBuildWithReport, IPreprocessBuildWithReport
#if !UNITY_2021_1_OR_NEWER
, IIl2CppProcessor
#endif
{
public int callbackOrder => 0;
#if UNITY_2021_1_OR_NEWER
public static string GetStripAssembliesDir2021(BuildTarget target)
{
string projectDir = SettingsUtil.ProjectDir;
switch (target)
{
case BuildTarget.StandaloneWindows:
case BuildTarget.StandaloneWindows64:
return $"{projectDir}/Library/Bee/artifacts/WinPlayerBuildProgram/ManagedStripped";
case BuildTarget.StandaloneLinux64:
return $"{projectDir}/Library/Bee/artifacts/LinuxPlayerBuildProgram/ManagedStripped";
case BuildTarget.Android:
return $"{projectDir}/Library/Bee/artifacts/Android/ManagedStripped";
case BuildTarget.iOS:
return $"{projectDir}/Library/Bee/artifacts/iOS/ManagedStripped";
case BuildTarget.WebGL:
return $"{projectDir}/Library/Bee/artifacts/WebGL/ManagedStripped";
case BuildTarget.StandaloneOSX:
return $"{projectDir}/Library/Bee/artifacts/MacStandalonePlayerBuildProgram/ManagedStripped";
case BuildTarget.PS4:
return $"{projectDir}/Library/Bee/artifacts/PS4PlayerBuildProgram/ManagedStripped";
case BuildTarget.PS5:
return $"{projectDir}/Library/Bee/artifacts/PS5PlayerBuildProgram/ManagedStripped";
default: return "";
}
}
#else
private string GetStripAssembliesDir2020(BuildTarget target)
{
string subPath = target == BuildTarget.Android ?
"assets/bin/Data/Managed" :
"Data/Managed/";
return $"{SettingsUtil.ProjectDir}/Temp/StagingArea/{subPath}";
}
public void OnBeforeConvertRun(BuildReport report, Il2CppBuildPipelineData data)
{
// 此回调只在 2020中调用
CopyStripDlls(GetStripAssembliesDir2020(data.target), data.target);
}
#endif
public static void CopyStripDlls(string srcStripDllPath, BuildTarget target)
{
if (!SettingsUtil.Enable)
{
Debug.Log($"[CopyStrippedAOTAssemblies] disabled");
return;
}
Debug.Log($"[CopyStrippedAOTAssemblies] CopyScripDlls. src:{srcStripDllPath} target:{target}");
var dstPath = SettingsUtil.GetAssembliesPostIl2CppStripDir(target);
Directory.CreateDirectory(dstPath);
foreach (var fileFullPath in Directory.GetFiles(srcStripDllPath, "*.dll"))
{
var file = Path.GetFileName(fileFullPath);
Debug.Log($"[CopyStrippedAOTAssemblies] copy strip dll {fileFullPath} ==> {dstPath}/{file}");
File.Copy($"{fileFullPath}", $"{dstPath}/{file}", true);
}
}
public void OnPostprocessBuild(BuildReport report)
{
#if UNITY_2021_1_OR_NEWER
BuildTarget target = EditorUserBuildSettings.activeBuildTarget;
string srcStripDllPath = GetStripAssembliesDir2021(target);
if (!string.IsNullOrEmpty(srcStripDllPath) && Directory.Exists(srcStripDllPath))
{
CopyStripDlls(srcStripDllPath, target);
}
#endif
}
public void OnPreprocessBuild(BuildReport report)
{
BuildTarget target = EditorUserBuildSettings.activeBuildTarget;
var dstPath = SettingsUtil.GetAssembliesPostIl2CppStripDir(target);
BashUtil.RecreateDir(dstPath);
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: f7884710ec2f8e545b3fe9aa05def5a8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,68 +0,0 @@
using HybridCLR.Editor.Meta;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEditor;
using UnityEditor.Build;
using UnityEngine;
namespace HybridCLR.Editor.BuildProcessors
{
/// <summary>
/// 将热更新dll从Build过程中过滤防止打包到主工程中
/// </summary>
internal class FilterHotFixAssemblies : IFilterBuildAssemblies
{
public int callbackOrder => 0;
public string[] OnFilterAssemblies(BuildOptions buildOptions, string[] assemblies)
{
if (!SettingsUtil.Enable)
{
Debug.Log($"[FilterHotFixAssemblies] disabled");
return assemblies;
}
List<string> allHotUpdateDllNames = SettingsUtil.HotUpdateAssemblyNamesExcludePreserved;
// 检查是否重复填写
var hotUpdateDllSet = new HashSet<string>();
foreach(var hotUpdateDll in allHotUpdateDllNames)
{
if (string.IsNullOrWhiteSpace(hotUpdateDll))
{
throw new BuildFailedException($"hot update assembly name cann't be empty");
}
if (!hotUpdateDllSet.Add(hotUpdateDll))
{
throw new BuildFailedException($"hot update assembly:{hotUpdateDll} is duplicated");
}
}
var assResolver = MetaUtil.CreateHotUpdateAssemblyResolver(EditorUserBuildSettings.activeBuildTarget, allHotUpdateDllNames);
// 检查是否填写了正确的dll名称
foreach (var hotUpdateDllName in allHotUpdateDllNames)
{
if (assemblies.Select(Path.GetFileNameWithoutExtension).All(ass => ass != hotUpdateDllName)
&& string.IsNullOrEmpty(assResolver.ResolveAssembly(hotUpdateDllName, false)))
{
throw new BuildFailedException($"hot update assembly:{hotUpdateDllName} doesn't exist");
}
}
// 将热更dll从打包列表中移除
return assemblies.Where(ass =>
{
string assName = Path.GetFileNameWithoutExtension(ass);
bool reserved = allHotUpdateDllNames.All(dll => !assName.Equals(dll, StringComparison.Ordinal));
if (!reserved)
{
Debug.Log($"[FilterHotFixAssemblies] filter assembly:{assName}");
}
return reserved;
}).ToArray();
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 9dec2922e3df5464aa047b636eb19e0d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,32 +0,0 @@
#if UNITY_EDITOR
using System;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
namespace HybridCLR.Editor.BuildProcessors
{
public class MsvcStdextWorkaround : IPreprocessBuildWithReport
{
const string kWorkaroundFlag = "/D_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS";
public int callbackOrder => 0;
public void OnPreprocessBuild(BuildReport report)
{
var clEnv = Environment.GetEnvironmentVariable("_CL_");
if (string.IsNullOrEmpty(clEnv))
{
Environment.SetEnvironmentVariable("_CL_", kWorkaroundFlag);
}
else if (!clEnv.Contains(kWorkaroundFlag))
{
clEnv += " " + kWorkaroundFlag;
Environment.SetEnvironmentVariable("_CL_", clEnv);
}
}
}
}
#endif // UNITY_EDITOR

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 8bff6cadf0b8db54b87ba51b24d080f6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,117 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEditor;
using UnityEditor.Android;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEditor.Il2Cpp;
using UnityEditor.UnityLinker;
using UnityEngine;
namespace HybridCLR.Editor.BuildProcessors
{
public class PatchScriptingAssemblyList :
#if UNITY_ANDROID
IPostGenerateGradleAndroidProject,
#endif
IPostprocessBuildWithReport
#if !UNITY_2021_1_OR_NEWER && UNITY_WEBGL
, IIl2CppProcessor
#endif
#if UNITY_PS5
, IUnityLinkerProcessor
#endif
{
public int callbackOrder => 0;
public void OnPostGenerateGradleAndroidProject(string path)
{
// 如果直接打包apk没有机会在PostprocessBuild中修改ScriptingAssemblies.json。
// 因此需要在这个时机处理
// Unity有bug偶然情况下会传入apk的路径导致替换失败
if (Directory.Exists(path))
{
PathScriptingAssembilesFile(path);
}
else
{
PathScriptingAssembilesFile($"{SettingsUtil.ProjectDir}/Library");
}
}
public void OnPostprocessBuild(BuildReport report)
{
// 如果target为Android,由于已经在OnPostGenerateGradelAndroidProject中处理过
// 这里不再重复处理
#if !UNITY_ANDROID && !UNITY_WEBGL
PathScriptingAssembilesFile(report.summary.outputPath);
#endif
}
#if UNITY_PS5
/// <summary>
/// 打包模式如果是 Package 需要在这个阶段提前处理 .json , PC Hosted 和 GP5 模式不受影响
/// </summary>
public string GenerateAdditionalLinkXmlFile(UnityEditor.Build.Reporting.BuildReport report, UnityEditor.UnityLinker.UnityLinkerBuildPipelineData data)
{
string path = $"{SettingsUtil.ProjectDir}/Library/PlayerDataCache/PS5/Data";
PathScriptingAssembilesFile(path);
return null;
}
#endif
public void PathScriptingAssembilesFile(string path)
{
if (!SettingsUtil.Enable)
{
Debug.Log($"[PatchScriptingAssemblyList] disabled");
return;
}
Debug.Log($"[PatchScriptingAssemblyList]. path:{path}");
if (!Directory.Exists(path))
{
path = Path.GetDirectoryName(path);
Debug.Log($"[PatchScriptingAssemblyList] get path parent:{path}");
}
AddHotFixAssembliesToScriptingAssembliesJson(path);
}
private void AddHotFixAssembliesToScriptingAssembliesJson(string path)
{
Debug.Log($"[PatchScriptingAssemblyList]. path:{path}");
/*
* ScriptingAssemblies.json 文件中记录了所有的dll名称此列表在游戏启动时自动加载
* 不在此列表中的dll在资源反序列化时无法被找到其类型
* 因此 OnFilterAssemblies 中移除的条目需要再加回来
*/
string[] jsonFiles = Directory.GetFiles(path, SettingsUtil.ScriptingAssembliesJsonFile, SearchOption.AllDirectories);
if (jsonFiles.Length == 0)
{
Debug.LogWarning($"can not find file {SettingsUtil.ScriptingAssembliesJsonFile}");
return;
}
foreach (string file in jsonFiles)
{
var patcher = new ScriptingAssembliesJsonPatcher();
patcher.Load(file);
patcher.AddScriptingAssemblies(SettingsUtil.HotUpdateAssemblyFilesIncludePreserved);
patcher.Save(file);
}
}
#if UNITY_WEBGL
public void OnBeforeConvertRun(BuildReport report, Il2CppBuildPipelineData data)
{
PathScriptingAssembilesFile($"{SettingsUtil.ProjectDir}/Temp/StagingArea/Data");
}
#endif
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 9bb6e2908d8948648979c9ff6bb7937d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,50 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace HybridCLR.Editor.BuildProcessors
{
public class ScriptingAssembliesJsonPatcher
{
[Serializable]
private class ScriptingAssemblies
{
public List<string> names;
public List<int> types;
}
private string _file;
ScriptingAssemblies _scriptingAssemblies;
public void Load(string file)
{
_file = file;
string content = File.ReadAllText(file);
_scriptingAssemblies = JsonUtility.FromJson<ScriptingAssemblies>(content);
}
public void AddScriptingAssemblies(List<string> assemblies)
{
foreach (string name in assemblies)
{
if (!_scriptingAssemblies.names.Contains(name))
{
_scriptingAssemblies.names.Add(name);
_scriptingAssemblies.types.Add(16); // user dll type
Debug.Log($"[PatchScriptAssembliesJson] add hotfix assembly:{name} to {_file}");
}
}
}
public void Save(string jsonFile)
{
string content = JsonUtility.ToJson(_scriptingAssemblies);
File.WriteAllText(jsonFile, content);
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 4455f7304f8678f408dd6cf21734f55e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 92f51c069d2607447ae2f61de80540fb
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,46 +0,0 @@
using HybridCLR.Editor.AOT;
using HybridCLR.Editor.Meta;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEditor;
using UnityEngine;
namespace HybridCLR.Editor.Commands
{
using Analyzer = HybridCLR.Editor.AOT.Analyzer;
public static class AOTReferenceGeneratorCommand
{
[MenuItem("HybridCLR/Generate/AOTGenericReference", priority = 102)]
public static void CompileAndGenerateAOTGenericReference()
{
BuildTarget target = EditorUserBuildSettings.activeBuildTarget;
CompileDllCommand.CompileDll(target);
GenerateAOTGenericReference(target);
}
public static void GenerateAOTGenericReference(BuildTarget target)
{
var gs = SettingsUtil.HybridCLRSettings;
List<string> hotUpdateDllNames = SettingsUtil.HotUpdateAssemblyNamesExcludePreserved;
using (AssemblyReferenceDeepCollector collector = new AssemblyReferenceDeepCollector(MetaUtil.CreateHotUpdateAndAOTAssemblyResolver(target, hotUpdateDllNames), hotUpdateDllNames))
{
var analyzer = new Analyzer(new Analyzer.Options
{
MaxIterationCount = Math.Min(20, gs.maxGenericReferenceIteration),
Collector = collector,
});
analyzer.Run();
var writer = new GenericReferenceWriter();
writer.Write(analyzer.AotGenericTypes.ToList(), analyzer.AotGenericMethods.ToList(), $"{Application.dataPath}/{gs.outputAOTGenericReferenceFile}");
AssetDatabase.Refresh();
}
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 2b464872c07f6ba4f9a4e4a02ca9a28c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,90 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEditor;
using UnityEditor.Build.Player;
using UnityEngine;
namespace HybridCLR.Editor.Commands
{
public class CompileDllCommand
{
public static void CompileDll(string buildDir, BuildTarget target, bool developmentBuild)
{
var group = BuildPipeline.GetBuildTargetGroup(target);
ScriptCompilationSettings scriptCompilationSettings = new ScriptCompilationSettings();
scriptCompilationSettings.group = group;
scriptCompilationSettings.target = target;
scriptCompilationSettings.options = developmentBuild ? ScriptCompilationOptions.DevelopmentBuild : ScriptCompilationOptions.None;
Directory.CreateDirectory(buildDir);
ScriptCompilationResult scriptCompilationResult = PlayerBuildInterface.CompilePlayerScripts(scriptCompilationSettings, buildDir);
#if UNITY_2022
UnityEditor.EditorUtility.ClearProgressBar();
#endif
Debug.Log("compile finish!!!");
}
public static void CompileDll(BuildTarget target, bool developmentBuild = false)
{
CompileDll(SettingsUtil.GetHotUpdateDllsOutputDirByTarget(target), target, developmentBuild);
}
[MenuItem("HybridCLR/CompileDll/ActiveBuildTarget", priority = 100)]
public static void CompileDllActiveBuildTarget()
{
CompileDll(EditorUserBuildSettings.activeBuildTarget);
}
[MenuItem("HybridCLR/CompileDll/ActiveBuildTarget_Development", priority = 101)]
public static void CompileDllActiveBuildTargetDevelopment()
{
CompileDll(EditorUserBuildSettings.activeBuildTarget, true);
}
[MenuItem("HybridCLR/CompileDll/Win32", priority = 200)]
public static void CompileDllWin32()
{
CompileDll(BuildTarget.StandaloneWindows);
}
[MenuItem("HybridCLR/CompileDll/Win64", priority = 201)]
public static void CompileDllWin64()
{
CompileDll(BuildTarget.StandaloneWindows64);
}
[MenuItem("HybridCLR/CompileDll/MacOS", priority = 202)]
public static void CompileDllMacOS()
{
CompileDll(BuildTarget.StandaloneOSX);
}
[MenuItem("HybridCLR/CompileDll/Linux", priority = 203)]
public static void CompileDllLinux()
{
CompileDll(BuildTarget.StandaloneLinux64);
}
[MenuItem("HybridCLR/CompileDll/Android", priority = 210)]
public static void CompileDllAndroid()
{
CompileDll(BuildTarget.Android);
}
[MenuItem("HybridCLR/CompileDll/IOS", priority = 220)]
public static void CompileDllIOS()
{
CompileDll(BuildTarget.iOS);
}
[MenuItem("HybridCLR/CompileDll/WebGL", priority = 230)]
public static void CompileDllWebGL()
{
CompileDll(BuildTarget.WebGL);
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: bf11b6c8bbc5afd4cb4a11921e5bd81e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,30 +0,0 @@
using HybridCLR.Editor.Link;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;
namespace HybridCLR.Editor.Commands
{
public static class Il2CppDefGeneratorCommand
{
[MenuItem("HybridCLR/Generate/Il2CppDef", priority = 104)]
public static void GenerateIl2CppDef()
{
var options = new Il2CppDef.Il2CppDefGenerator.Options()
{
UnityVersion = Application.unityVersion,
HotUpdateAssemblies = SettingsUtil.HotUpdateAssemblyNamesIncludePreserved,
OutputFile = $"{SettingsUtil.LocalIl2CppDir}/libil2cpp/hybridclr/generated/UnityVersion.h",
OutputFile2 = $"{SettingsUtil.LocalIl2CppDir}/libil2cpp/hybridclr/generated/AssemblyManifest.cpp",
};
var g = new Il2CppDef.Il2CppDefGenerator(options);
g.Generate();
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 5165a065d05497c43a2fff885f31ed07
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,39 +0,0 @@
using HybridCLR.Editor.Link;
using HybridCLR.Editor.Meta;
using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEditor;
using UnityEngine;
namespace HybridCLR.Editor.Commands
{
using Analyzer = HybridCLR.Editor.Link.Analyzer;
public static class LinkGeneratorCommand
{
[MenuItem("HybridCLR/Generate/LinkXml", priority = 100)]
public static void GenerateLinkXml()
{
BuildTarget target = EditorUserBuildSettings.activeBuildTarget;
CompileDllCommand.CompileDll(target);
GenerateLinkXml(target);
}
public static void GenerateLinkXml(BuildTarget target)
{
var ls = SettingsUtil.HybridCLRSettings;
List<string> hotfixAssemblies = SettingsUtil.HotUpdateAssemblyNamesExcludePreserved;
var analyzer = new Analyzer(MetaUtil.CreateHotUpdateAndAOTAssemblyResolver(target, hotfixAssemblies));
var refTypes = analyzer.CollectRefs(hotfixAssemblies);
Debug.Log($"[LinkGeneratorCommand] hotfix assembly count:{hotfixAssemblies.Count}, ref type count:{refTypes.Count} output:{Application.dataPath}/{ls.outputLinkFile}");
var linkXmlWriter = new LinkXmlWriter();
linkXmlWriter.Write($"{Application.dataPath}/{ls.outputLinkFile}", refTypes);
AssetDatabase.Refresh();
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 4f5b96abdbc4c424eb1bc3bc34b3a1a4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,81 +0,0 @@
using HybridCLR.Editor;
using HybridCLR.Editor.ABI;
using HybridCLR.Editor.Meta;
using HybridCLR.Editor.MethodBridge;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using UnityEditor;
using UnityEditor.Build;
using UnityEngine;
namespace HybridCLR.Editor.Commands
{
using Analyzer = HybridCLR.Editor.MethodBridge.Analyzer;
public class MethodBridgeGeneratorCommand
{
public static void CleanIl2CppBuildCache()
{
string il2cppBuildCachePath = SettingsUtil.Il2CppBuildCacheDir;
if (!Directory.Exists(il2cppBuildCachePath))
{
return;
}
Debug.Log($"clean il2cpp build cache:{il2cppBuildCachePath}");
Directory.Delete(il2cppBuildCachePath, true);
}
private static void GenerateMethodBridgeCppFile(Analyzer analyzer, string outputFile)
{
string templateCode = File.ReadAllText(outputFile, Encoding.UTF8);
var g = new Generator(new Generator.Options()
{
TemplateCode = templateCode,
OutputFile = outputFile,
GenericMethods = analyzer.GenericMethods,
});
g.PrepareMethods();
g.Generate();
Debug.LogFormat("[MethodBridgeGeneratorCommand] output:{0}", outputFile);
}
[MenuItem("HybridCLR/Generate/MethodBridge", priority = 101)]
public static void CompileAndGenerateMethodBridge()
{
BuildTarget target = EditorUserBuildSettings.activeBuildTarget;
GenerateMethodBridge(target);
}
public static void GenerateMethodBridge(BuildTarget target)
{
string aotDllDir = SettingsUtil.GetAssembliesPostIl2CppStripDir(target);
List<string> aotAssemblyNames = Directory.Exists(aotDllDir) ?
Directory.GetFiles(aotDllDir, "*.dll", SearchOption.TopDirectoryOnly).Select(Path.GetFileNameWithoutExtension).ToList()
: new List<string>();
if (aotAssemblyNames.Count == 0)
{
throw new Exception($"no aot assembly found. please run `HybridCLR/Generate/All` or `HybridCLR/Generate/AotDlls` to generate aot dlls before runing `HybridCLR/Generate/MethodBridge`");
}
using (AssemblyReferenceDeepCollector collector = new AssemblyReferenceDeepCollector(MetaUtil.CreateAOTAssemblyResolver(target), aotAssemblyNames))
{
var analyzer = new Analyzer(new Analyzer.Options
{
MaxIterationCount = Math.Min(20, SettingsUtil.HybridCLRSettings.maxMethodBridgeGenericIteration),
Collector = collector,
});
analyzer.Run();
string outputFile = $"{SettingsUtil.GeneratedCppDir}/MethodBridge.cpp";
GenerateMethodBridgeCppFile(analyzer, outputFile);
}
CleanIl2CppBuildCache();
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 46bc62d5236f5e941850776c435a9560
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,34 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEditor;
namespace HybridCLR.Editor.Commands
{
public static class PrebuildCommand
{
/// <summary>
/// 按照必要的顺序,执行所有生成操作,适合打包前操作
/// </summary>
[MenuItem("HybridCLR/Generate/All", priority = 200)]
public static void GenerateAll()
{
BuildTarget target = EditorUserBuildSettings.activeBuildTarget;
CompileDllCommand.CompileDll(target);
Il2CppDefGeneratorCommand.GenerateIl2CppDef();
// 这几个生成依赖HotUpdateDlls
LinkGeneratorCommand.GenerateLinkXml(target);
// 生成裁剪后的aot dll
StripAOTDllCommand.GenerateStripedAOTDlls(target);
// 桥接函数生成依赖于AOT dll必须保证已经build过生成AOT dll
MethodBridgeGeneratorCommand.GenerateMethodBridge(target);
ReversePInvokeWrapperGeneratorCommand.GenerateReversePInvokeWrapper(target);
AOTReferenceGeneratorCommand.GenerateAOTGenericReference(target);
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: c20f09bfbe3f32143aae872d3813d9e9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,49 +0,0 @@
using HybridCLR.Editor.ABI;
using HybridCLR.Editor.Link;
using HybridCLR.Editor.Meta;
using HybridCLR.Editor.ReversePInvokeWrap;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using UnityEditor;
using UnityEngine;
namespace HybridCLR.Editor.Commands
{
public static class ReversePInvokeWrapperGeneratorCommand
{
[MenuItem("HybridCLR/Generate/ReversePInvokeWrapper", priority = 103)]
public static void CompileAndGenerateReversePInvokeWrapper()
{
BuildTarget target = EditorUserBuildSettings.activeBuildTarget;
CompileDllCommand.CompileDll(target);
GenerateReversePInvokeWrapper(target);
}
public static void GenerateReversePInvokeWrapper(BuildTarget target)
{
List<string> hotUpdateDlls = SettingsUtil.HotUpdateAssemblyNamesExcludePreserved;
using (var cache = new AssemblyCache(MetaUtil.CreateHotUpdateAndAOTAssemblyResolver(target, hotUpdateDlls)))
{
var analyzer = new ReversePInvokeWrap.Analyzer(cache, hotUpdateDlls);
analyzer.Run();
string outputFile = $"{SettingsUtil.GeneratedCppDir}/ReversePInvokeMethodStub.cpp";
List<ABIReversePInvokeMethodInfo> methods = analyzer.BuildABIMethods();
Debug.Log($"GenerateReversePInvokeWrapper. wraperCount:{methods.Sum(m => m.Count)} output:{outputFile}");
var generator = new Generator();
generator.Generate(methods, outputFile);
Debug.LogFormat("[ReversePInvokeWrapperGeneratorCommand] output:{0}", outputFile);
}
MethodBridgeGeneratorCommand.CleanIl2CppBuildCache();
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 7db18e1736f593c4089c85d764cf8620
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,162 +0,0 @@
using HybridCLR.Editor.Installer;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using UnityEditor;
using UnityEngine;
using static UnityEngine.Networking.UnityWebRequest;
namespace HybridCLR.Editor.Commands
{
public static class StripAOTDllCommand
{
[MenuItem("HybridCLR/Generate/AOTDlls", priority = 105)]
public static void GenerateStripedAOTDlls()
{
GenerateStripedAOTDlls(EditorUserBuildSettings.activeBuildTarget);
}
static BuildOptions GetBuildPlayerOptions(BuildTarget buildTarget)
{
BuildOptions options = BuildOptions.None;
bool development = EditorUserBuildSettings.development;
if (development)
{
options |= BuildOptions.Development;
}
if (EditorUserBuildSettings.allowDebugging && development)
{
options |= BuildOptions.AllowDebugging;
}
if (EditorUserBuildSettings.connectProfiler && (development || buildTarget == BuildTarget.WSAPlayer))
{
options |= BuildOptions.ConnectWithProfiler;
}
if (EditorUserBuildSettings.buildWithDeepProfilingSupport && development)
{
options |= BuildOptions.EnableDeepProfilingSupport;
}
#if UNITY_2021_2_OR_NEWER
options |= BuildOptions.CleanBuildCache;
#endif
return options;
}
private static string GetLocationPathName(string buildDir, BuildTarget target)
{
switch(target)
{
case BuildTarget.StandaloneWindows:
case BuildTarget.StandaloneWindows64: return $"{buildDir}/{target}";
case BuildTarget.StandaloneOSX: return buildDir;
case BuildTarget.iOS: return buildDir;
case BuildTarget.Android: return buildDir;
case BuildTarget.StandaloneLinux64: return buildDir;
default: return buildDir;
}
}
public static void GenerateStripedAOTDlls(BuildTarget target)
{
string outputPath = $"{SettingsUtil.HybridCLRDataDir}/StrippedAOTDllsTempProj/{target}";
BashUtil.RemoveDir(outputPath);
var buildOptions = GetBuildPlayerOptions(target);
#if UNITY_2021_2_OR_NEWER
buildOptions |= BuildOptions.CleanBuildCache;
#endif
bool oldExportAndroidProj = EditorUserBuildSettings.exportAsGoogleAndroidProject;
#if UNITY_EDITOR_OSX
bool oldCreateSolution = UnityEditor.OSXStandalone.UserBuildSettings.createXcodeProject;
#elif UNITY_EDITOR_WIN
bool oldCreateSolution = UnityEditor.WindowsStandalone.UserBuildSettings.createSolution;
#endif
bool oldBuildScriptsOnly = EditorUserBuildSettings.buildScriptsOnly;
EditorUserBuildSettings.buildScriptsOnly = true;
string location = GetLocationPathName(outputPath, target);
string oldBuildLocation = EditorUserBuildSettings.GetBuildLocation(target);
EditorUserBuildSettings.SetBuildLocation(target, location);
switch (target)
{
case BuildTarget.StandaloneWindows:
case BuildTarget.StandaloneWindows64:
{
#if UNITY_EDITOR_WIN
UnityEditor.WindowsStandalone.UserBuildSettings.createSolution = true;
#endif
break;
}
case BuildTarget.StandaloneOSX:
{
#if UNITY_EDITOR_OSX
UnityEditor.OSXStandalone.UserBuildSettings.createXcodeProject = true;
#endif
break;
}
case BuildTarget.Android:
{
EditorUserBuildSettings.exportAsGoogleAndroidProject = true;
break;
}
}
Debug.Log($"GenerateStripedAOTDlls build option:{buildOptions}");
BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions()
{
scenes = EditorBuildSettings.scenes.Where(s => s.enabled).Select(s => s.path).ToArray(),
locationPathName = location,
options = buildOptions,
target = target,
targetGroup = BuildPipeline.GetBuildTargetGroup(target),
};
var report = BuildPipeline.BuildPlayer(buildPlayerOptions);
EditorUserBuildSettings.buildScriptsOnly = oldBuildScriptsOnly;
EditorUserBuildSettings.SetBuildLocation(target, oldBuildLocation);
switch (target)
{
case BuildTarget.StandaloneWindows:
case BuildTarget.StandaloneWindows64:
{
#if UNITY_EDITOR_WIN
UnityEditor.WindowsStandalone.UserBuildSettings.createSolution = oldCreateSolution;
#endif
break;
}
case BuildTarget.StandaloneOSX:
{
#if UNITY_EDITOR_OSX
UnityEditor.OSXStandalone.UserBuildSettings.createXcodeProject = oldCreateSolution;
#endif
break;
}
case BuildTarget.Android:
{
EditorUserBuildSettings.exportAsGoogleAndroidProject = oldExportAndroidProj;
break;
}
}
if (report.summary.result != UnityEditor.Build.Reporting.BuildResult.Succeeded)
{
throw new Exception("GenerateStripedAOTDlls failed");
}
Debug.Log($"GenerateStripedAOTDlls target:{target} path:{outputPath}");
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 21fb0a02f23185141a4a3df67fe61789
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,28 +0,0 @@
using dnlib.DotNet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HybridCLR.Editor
{
public static class HashUtil
{
public static int CombineHash(int hash1, int hash2)
{
return hash1 * 1566083941 + hash2;
}
public static int ComputHash(List<TypeSig> sigs)
{
int hash = 135781321;
TypeEqualityComparer tc = TypeEqualityComparer.Instance;
foreach (var sig in sigs)
{
hash = hash * 1566083941 + tc.GetHashCode(sig);
}
return hash;
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 5d4ae4a5c0bba49469c525887d812717
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,18 +0,0 @@
{
"name": "HybridCLR.Editor",
"rootNamespace": "",
"references": [
"HybridCLR.Runtime"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": true,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@@ -1,7 +0,0 @@
fileFormatVersion: 2
guid: 2373f786d14518f44b0f475db77ba4de
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: da46bc9f1a4dece41a5c193166be9a30
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,86 +0,0 @@
using HybridCLR.Editor.ABI;
using HybridCLR.Editor.Template;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using UnityEngine;
namespace HybridCLR.Editor.Il2CppDef
{
public class Il2CppDefGenerator
{
public class Options
{
public List<string> HotUpdateAssemblies { get; set; }
public string OutputFile { get; set; }
public string OutputFile2 { get; set; }
public string UnityVersion { get; set; }
}
private readonly Options _options;
public Il2CppDefGenerator(Options options)
{
_options = options;
}
private static readonly Regex s_unityVersionPat = new Regex(@"(\d+)\.(\d+)\.(\d+)");
public void Generate()
{
GenerateIl2CppConfig();
GeneratePlaceHolderAssemblies();
}
private void GenerateIl2CppConfig()
{
var frr = new FileRegionReplace(File.ReadAllText(_options.OutputFile));
List<string> lines = new List<string>();
var match = s_unityVersionPat.Matches(_options.UnityVersion)[0];
int majorVer = int.Parse(match.Groups[1].Value);
int minorVer1 = int.Parse(match.Groups[2].Value);
int minorVer2 = int.Parse(match.Groups[3].Value);
lines.Add($"#define HYBRIDCLR_UNITY_VERSION {majorVer}{minorVer1.ToString("D2")}{minorVer2.ToString("D2")}");
lines.Add($"#define HYBRIDCLR_UNITY_{majorVer} 1");
for (int ver = 2019; ver <= 2024; ver++)
{
if (majorVer >= ver)
{
lines.Add($"#define HYBRIDCLR_UNITY_{ver}_OR_NEW 1");
}
}
frr.Replace("UNITY_VERSION", string.Join("\n", lines));
frr.Commit(_options.OutputFile);
Debug.Log($"[HybridCLR.Editor.Il2CppDef.Generator] output:{_options.OutputFile}");
}
private void GeneratePlaceHolderAssemblies()
{
var frr = new FileRegionReplace(File.ReadAllText(_options.OutputFile2));
List<string> lines = new List<string>();
foreach (var ass in _options.HotUpdateAssemblies)
{
lines.Add($"\t\t\"{ass}\",");
}
frr.Replace("PLACE_HOLDER", string.Join("\n", lines));
frr.Commit(_options.OutputFile2);
Debug.Log($"[HybridCLR.Editor.Il2CppDef.Generator] output:{_options.OutputFile2}");
}
}
}

Some files were not shown because too many files have changed in this diff Show More