mirror of
https://github.com/par274/sharpemu.git
synced 2026-07-30 22:49:53 +08:00
initial commit
This commit is contained in:
@@ -0,0 +1,275 @@
|
||||
// Copyright (C) 2026 SharpEmu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SharpEmu.Core.Cpu.Native;
|
||||
|
||||
public static unsafe class JitStubs
|
||||
{
|
||||
public const int XsaveBufferSize = 2688;
|
||||
|
||||
public const ulong XsaveChkGuard = 0xDeadBeef5533CCAAu;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct JmpWithIndex
|
||||
{
|
||||
private fixed byte _code[16];
|
||||
|
||||
public static ReadOnlySpan<byte> Template => new byte[]
|
||||
{
|
||||
0x68, 0x00, 0x00, 0x00, 0x00, // push <index>
|
||||
0xE9, 0x00, 0x00, 0x00, 0x00, // jmp <handler>
|
||||
0x90, 0x90, 0x90, 0x90, 0x90, 0x90 // nop padding
|
||||
};
|
||||
|
||||
public static int Size => 16;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
fixed (byte* code = _code)
|
||||
{
|
||||
Template.CopyTo(new Span<byte>(code, 16));
|
||||
}
|
||||
}
|
||||
|
||||
public void SetIndex(uint index)
|
||||
{
|
||||
fixed (byte* code = _code)
|
||||
{
|
||||
*(uint*)(code + 1) = index;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetHandler(void* handler)
|
||||
{
|
||||
fixed (byte* code = _code)
|
||||
{
|
||||
var funcAddr = (long)handler;
|
||||
var ripAddr = (long)(code + 10); // After push + jmp
|
||||
var offset64 = funcAddr - ripAddr;
|
||||
var offset32 = (uint)(ulong)offset64;
|
||||
|
||||
*(uint*)(code + 6) = offset32;
|
||||
}
|
||||
}
|
||||
|
||||
public byte* GetCodePointer()
|
||||
{
|
||||
fixed (byte* code = _code)
|
||||
{
|
||||
return code;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct Call9
|
||||
{
|
||||
private fixed byte _code[9];
|
||||
|
||||
public static ReadOnlySpan<byte> Template => new byte[]
|
||||
{
|
||||
0xE8, 0x00, 0x00, 0x00, 0x00, // call func
|
||||
0x48, 0x89, 0xC0, // mov rax,rax
|
||||
0x90 // nop
|
||||
};
|
||||
|
||||
public static int Size => 9;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
fixed (byte* code = _code)
|
||||
{
|
||||
Template.CopyTo(new Span<byte>(code, 9));
|
||||
}
|
||||
}
|
||||
|
||||
public void SetFunc(void* func)
|
||||
{
|
||||
fixed (byte* code = _code)
|
||||
{
|
||||
var funcAddr = (long)func;
|
||||
var ripAddr = (long)(code + 5); // After call instruction
|
||||
var offset64 = funcAddr - ripAddr;
|
||||
var offset32 = (uint)(ulong)offset64;
|
||||
|
||||
*(uint*)(code + 1) = offset32;
|
||||
}
|
||||
}
|
||||
|
||||
public byte* GetCodePointer()
|
||||
{
|
||||
fixed (byte* code = _code)
|
||||
{
|
||||
return code;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct JmpRax
|
||||
{
|
||||
private fixed byte _code[12];
|
||||
|
||||
public static ReadOnlySpan<byte> Template => new byte[]
|
||||
{
|
||||
0x48, 0xB8, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, // movabs rax,<addr>
|
||||
0xFF, 0xE0 // jmp rax
|
||||
};
|
||||
|
||||
public static int Size => 12;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
fixed (byte* code = _code)
|
||||
{
|
||||
Template.CopyTo(new Span<byte>(code, 12));
|
||||
}
|
||||
}
|
||||
|
||||
public void SetTarget(void* target)
|
||||
{
|
||||
fixed (byte* code = _code)
|
||||
{
|
||||
*(ulong*)(code + 2) = (ulong)target;
|
||||
}
|
||||
}
|
||||
|
||||
public byte* GetCodePointer()
|
||||
{
|
||||
fixed (byte* code = _code)
|
||||
{
|
||||
return code;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class SafeCall
|
||||
{
|
||||
public static ReadOnlySpan<byte> Template => new byte[]
|
||||
{
|
||||
0x51,
|
||||
0x52,
|
||||
0x41, 0x50,
|
||||
0x41, 0x51,
|
||||
0x41, 0x52,
|
||||
0x41, 0x53,
|
||||
0x57,
|
||||
0x56,
|
||||
0x48, 0xBF, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11,
|
||||
0x48, 0xBE, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11,
|
||||
0x48, 0xB9, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11,
|
||||
0xB0, 0x01,
|
||||
0x86, 0x07,
|
||||
0x84, 0xC0,
|
||||
0x75, 0xF8,
|
||||
0xB8, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xBA, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x0F, 0xAE, 0x26,
|
||||
0x48, 0x83, 0xEC, 0x08,
|
||||
0xFF, 0xD1,
|
||||
0x48, 0x83, 0xC4, 0x08,
|
||||
0x48, 0x89, 0xC1,
|
||||
0xB8, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xBA, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x0F, 0xAE, 0x2E,
|
||||
0x48, 0x89, 0xC8,
|
||||
0xC6, 0x07, 0x00,
|
||||
0x5E,
|
||||
0x5F,
|
||||
0x41, 0x5B,
|
||||
0x41, 0x5A,
|
||||
0x41, 0x59,
|
||||
0x41, 0x58,
|
||||
0x5A,
|
||||
0x59,
|
||||
0xC3
|
||||
};
|
||||
|
||||
public static int Size => Template.Length; // 0x6c = 108 bytes
|
||||
}
|
||||
|
||||
public static ReadOnlySpan<byte> TlsAccessPattern => new byte[]
|
||||
{
|
||||
0x64, 0x48, 0x8B, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
public static void CreateJmpWithIndex(byte* location, uint index, void* handler)
|
||||
{
|
||||
|
||||
var code = location;
|
||||
|
||||
code[0] = 0x68;
|
||||
*(uint*)(code + 1) = index;
|
||||
|
||||
code[5] = 0xE9;
|
||||
var handlerAddr = (long)handler;
|
||||
var ripAddr = (long)(code + 10); // After push + jmp
|
||||
var offset64 = handlerAddr - ripAddr;
|
||||
*(uint*)(code + 6) = (uint)(ulong)offset64;
|
||||
|
||||
for (int i = 10; i < 16; i++)
|
||||
{
|
||||
code[i] = 0x90;
|
||||
}
|
||||
}
|
||||
|
||||
public static void CreateCall9(byte* location, void* func)
|
||||
{
|
||||
|
||||
var code = location;
|
||||
|
||||
code[0] = 0xE8;
|
||||
var funcAddr = (long)func;
|
||||
var ripAddr = (long)(code + 5);
|
||||
var offset64 = funcAddr - ripAddr;
|
||||
*(uint*)(code + 1) = (uint)(ulong)offset64;
|
||||
|
||||
code[5] = 0x48;
|
||||
code[6] = 0x89;
|
||||
code[7] = 0xC0;
|
||||
|
||||
code[8] = 0x90;
|
||||
}
|
||||
|
||||
public static void CreateJmpRax(byte* location, void* target)
|
||||
{
|
||||
|
||||
var code = location;
|
||||
|
||||
code[0] = 0x48;
|
||||
code[1] = 0xB8;
|
||||
*(ulong*)(code + 2) = (ulong)target;
|
||||
|
||||
code[10] = 0xFF;
|
||||
code[11] = 0xE0;
|
||||
}
|
||||
|
||||
public static List<nint> FindTlsAccessPatterns(byte* start, int length)
|
||||
{
|
||||
var results = new List<nint>();
|
||||
var pattern = TlsAccessPattern;
|
||||
var end = start + length - pattern.Length;
|
||||
|
||||
for (var ptr = start; ptr < end; ptr++)
|
||||
{
|
||||
if (MatchesPattern(ptr, pattern))
|
||||
{
|
||||
results.Add((nint)ptr);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private static bool MatchesPattern(byte* ptr, ReadOnlySpan<byte> pattern)
|
||||
{
|
||||
for (var i = 0; i < pattern.Length; i++)
|
||||
{
|
||||
if (ptr[i] != pattern[i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user