feat: implement cosf, time, ctype tables, tracked heap access, IL2CPP lookup ABI paths (#542)

* fix: add Messenger CRT and AGC compatibility shims

* fix: keep Messenger IL2CPP bootstrap on HLE shims

* Fix Messenger compatibility ABI handling

* Make IL2CPP ABI regression tests portable
This commit is contained in:
Kurt Himebauch
2026-07-23 08:35:59 -04:00
committed by GitHub
parent 7b950166d7
commit 2764aaab3f
8 changed files with 570 additions and 20 deletions
+78
View File
@@ -45,7 +45,11 @@ public static class LibcStdioExports
private const ushort CtypeBlank = 0x400; // _XB ' ' and '\t'
private static readonly object _ctypeTableGate = new();
private static readonly object _ctypeLowerTableGate = new();
private static readonly object _ctypeUpperTableGate = new();
private static nint _ctypeTableBase;
private static nint _ctypeLowerTableBase;
private static nint _ctypeUpperTableBase;
[SysAbiExport(
Nid = "xeYO4u7uyJ0",
@@ -716,6 +720,28 @@ public static class LibcStdioExports
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
}
[SysAbiExport(
Nid = "1uJgoVq3bQU",
ExportName = "_Getptolower",
Target = Generation.Gen4 | Generation.Gen5,
LibraryName = "libc")]
public static int GetPtolower(CpuContext ctx)
{
ctx[CpuRegister.Rax] = unchecked((ulong)EnsureCtypeLowerTable());
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
}
[SysAbiExport(
Nid = "rcQCUr0EaRU",
ExportName = "_Getptoupper",
Target = Generation.Gen4 | Generation.Gen5,
LibraryName = "libc")]
public static int GetPtoupper(CpuContext ctx)
{
ctx[CpuRegister.Rax] = unchecked((ulong)EnsureCtypeUpperTable());
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
}
private static unsafe nint EnsureCtypeTable()
{
lock (_ctypeTableGate)
@@ -740,6 +766,58 @@ public static class LibcStdioExports
}
}
private static unsafe nint EnsureCtypeLowerTable()
{
lock (_ctypeLowerTableGate)
{
if (_ctypeLowerTableBase != 0)
{
return _ctypeLowerTableBase;
}
var storage = Marshal.AllocHGlobal(CtypeTableEntryCount * sizeof(ushort));
var entries = new Span<ushort>((void*)storage, CtypeTableEntryCount);
for (var i = 0; i < CtypeTableEntryCount; i++)
{
var c = i + CtypeTableLowerBound;
entries[i] = c == -1
? ushort.MaxValue
: c is >= 0 and <= 0x7F
? (ushort)char.ToLowerInvariant((char)c)
: (ushort)(c & 0xFF);
}
_ctypeLowerTableBase = storage - (CtypeTableLowerBound * sizeof(ushort));
return _ctypeLowerTableBase;
}
}
private static unsafe nint EnsureCtypeUpperTable()
{
lock (_ctypeUpperTableGate)
{
if (_ctypeUpperTableBase != 0)
{
return _ctypeUpperTableBase;
}
var storage = Marshal.AllocHGlobal(CtypeTableEntryCount * sizeof(ushort));
var entries = new Span<ushort>((void*)storage, CtypeTableEntryCount);
for (var i = 0; i < CtypeTableEntryCount; i++)
{
var c = i + CtypeTableLowerBound;
entries[i] = c == -1
? ushort.MaxValue
: c is >= 0 and <= 0x7F
? (ushort)char.ToUpperInvariant((char)c)
: (ushort)(c & 0xFF);
}
_ctypeUpperTableBase = storage - (CtypeTableLowerBound * sizeof(ushort));
return _ctypeUpperTableBase;
}
}
private static ushort ComputeCtypeFlags(int c)
{
var isUpper = c is >= 'A' and <= 'Z';