Skip to content

Commit

Permalink
ARM64EC: Dynamically determine syscall numbers under wine
Browse files Browse the repository at this point in the history
Takes advantage of the consistent alphabetical syscall ordering that
wine follows.
  • Loading branch information
bylaws committed Sep 29, 2024
1 parent e902ad5 commit 2dd3635
Showing 1 changed file with 32 additions and 5 deletions.
37 changes: 32 additions & 5 deletions Source/Windows/ARM64EC/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,9 @@ uint32_t NtDllRedirectionLUTSize;

// Wine doesn't support issuing direct system calls with SVC, and unlike Windows it doesn't have a 'stable' syscall number for NtContinue
void* WineSyscallDispatcher;
// TODO: this really shouldn't be hardcoded, once wine gains proper syscall thunks this can be dropped.
uint64_t WineNtContinueSyscallId = 0x1a;
uint64_t WineNtAllocateVirtualMemorySyscallId = 0xb;
uint64_t WineNtProtectVirtualMemorySyscallId = 0x76;
uint64_t WineNtContinueSyscallId;
uint64_t WineNtAllocateVirtualMemorySyscallId;
uint64_t WineNtProtectVirtualMemorySyscallId;

NTSTATUS NtContinueNative(ARM64_NT_CONTEXT* NativeContext, BOOLEAN Alert);
NTSTATUS NtAllocateVirtualMemoryNative(HANDLE, PVOID*, ULONG_PTR, SIZE_T*, ULONG, ULONG);
Expand Down Expand Up @@ -151,7 +150,6 @@ bool IsDispatcherAddress(uint64_t Address) {


void FillNtDllLUTs(HMODULE NtDll) {
NtDllBase = reinterpret_cast<uintptr_t>(NtDll);
ULONG Size;
const auto* LoadConfig =
reinterpret_cast<_IMAGE_LOAD_CONFIG_DIRECTORY64*>(RtlImageDirectoryEntryToData(NtDll, true, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &Size));
Expand Down Expand Up @@ -196,6 +194,32 @@ void PatchCallChecker() {
WriteModuleRVA(Module, CHPEMetadata->__os_arm64x_dispatch_icall_cfg, &CheckCall);
}

// Fills in the syscall numbers necessary to call *Native variants of syscalls from FEX under wine.
void ParseWineSyscallNumbers(HMODULE NtDll) {
ULONG Size;
const auto* Exports = reinterpret_cast<IMAGE_EXPORT_DIRECTORY*>(RtlImageDirectoryEntryToData(NtDll, true, IMAGE_DIRECTORY_ENTRY_EXPORT, &Size));
const auto* NameTable = reinterpret_cast<uint32_t*>(NtDllBase + Exports->AddressOfNames);

// Wine orders syscalls alphabetically, take advantage of that to find the syscall indices for those which we need to
// manually issue. Note that all functions starting with Nt besides NtGetTickCount are syscalls and the syscall ID must
// be incremented by 1 for each.
uint32_t CurSyscallId = 0;
for (uint32_t Idx = 0; Idx < Exports->NumberOfNames; Idx++) {
const char* Name = reinterpret_cast<const char*>(NtDllBase + NameTable[Idx]);
if (Name[0] == 'N' && Name[1] == 't' && strcmp(Name, "NtGetTickCount") != 0) {
if (strcmp(Name, "NtContinue") == 0) {
WineNtContinueSyscallId = CurSyscallId;
} else if (strcmp(Name, "NtAllocateVirtualMemory") == 0) {
WineNtAllocateVirtualMemorySyscallId = CurSyscallId;
} else if (strcmp(Name, "NtProtectVirtualMemory") == 0) {
WineNtProtectVirtualMemorySyscallId = CurSyscallId;
}

CurSyscallId++;
}
}
}

// Syscall thunks may have been patched before FEX has loaded, the default call checker installed by ntdll into FEX will
// try to invoke the JIT when calling such patched syscalls but this obviously doesn't work before FEX is initalised.
// This function parses ntdll and sets up a custom call checker to prevent this, as such it must avoid using any syscall
Expand All @@ -204,9 +228,12 @@ void InitSyscalls() {
// The ntdll exports called by GetModuleHandle/GetProcAddress aren't known to be patched before JIT init by any current
// software so are safe to call, but if that changes the loader structures in the PEB could be parsed manually.
const auto NtDll = GetModuleHandle("ntdll.dll");
NtDllBase = reinterpret_cast<uintptr_t>(NtDll);

const auto WineSyscallDispatcherPtr = reinterpret_cast<void**>(GetProcAddress(NtDll, "__wine_syscall_dispatcher"));
if (WineSyscallDispatcherPtr) {
WineSyscallDispatcher = *WineSyscallDispatcherPtr;
ParseWineSyscallNumbers(NtDll);
}

FillNtDllLUTs(NtDll);
Expand Down

0 comments on commit 2dd3635

Please sign in to comment.