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).
/// Call to will allocate a single page of this size.
///
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;
///
/// Platform-specific instance of page allocator.
///
public static PageAllocator Instance => instance ??= Init();
///
/// Allocates a single page of size near the provided address.
/// Attempts to allocate the page within the +-1GB region of the hinted address.
///
/// Address near which to attempt to allocate the page.
/// Address to the allocated page.
public abstract IntPtr Allocate(IntPtr hint);
///
/// Frees the page allocated with
///
///
public abstract void Free(IntPtr page);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected static long RoundUp(long num, long unit)
{
return (num + unit - 1) & ~ (unit - 1);
}
///
/// Checks if the given address is within the relative jump range.
///
/// Source address to jump from.
/// Destination address to jump to.
/// True, if the distance between the addresses is within the relative jump range (usually 1GB), otherwise false.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public 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();
}
}
}