using System; using System.Runtime.CompilerServices; using MonoMod.Utils; namespace BepInEx.IL2CPP { /// /// A general purpose page allocator for patching purposes. /// Allows to allocate pages (4k memory chunks) within the 1GB radius of a given address. /// /// Based on https://github.com/kubo/funchook internal abstract class PageAllocator { /// /// Common page size on Unix and Windows (4k). /// public const int PAGE_SIZE = 0x1000; /// /// Allocation granularity on Windows (but can be reused in other implementations). /// protected const int ALLOCATION_UNIT = 0x100000; protected const int PAGES_PER_UNIT = ALLOCATION_UNIT / PAGE_SIZE; private static PageAllocator instance; public static PageAllocator Instance => instance ??= Init(); public abstract IntPtr Allocate(IntPtr hint); public abstract void Free(IntPtr page); [MethodImpl(MethodImplOptions.AggressiveInlining)] protected static long RoundDown(long num, long unit) { return num & ~(unit - 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] protected static long RoundUp(long num, long unit) { return (num + unit - 1) & ~ (unit - 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] protected static bool IsInRelJmpRange(IntPtr src, IntPtr dst) { long diff = dst.ToInt64() - src.ToInt64(); return int.MinValue <= diff && diff <= int.MaxValue; } private static PageAllocator Init() { if (PlatformHelper.Is(Platform.Windows)) return new WindowsPageAllocator(); if (PlatformHelper.Is(Platform.Unix)) return new UnixPageAllocator(); throw new NotImplementedException(); } } }