Fills in the syscall numbers necessary to call *Native variants of syscalls from FEX under wine.
| 207 | |
| 208 | // Fills in the syscall numbers necessary to call *Native variants of syscalls from FEX under wine. |
| 209 | void ParseWineSyscallNumbers(HMODULE NtDll) { |
| 210 | ULONG Size; |
| 211 | const auto* Exports = reinterpret_cast<IMAGE_EXPORT_DIRECTORY*>(RtlImageDirectoryEntryToData(NtDll, true, IMAGE_DIRECTORY_ENTRY_EXPORT, &Size)); |
| 212 | const auto* NameTable = reinterpret_cast<uint32_t*>(NtDllBase + Exports->AddressOfNames); |
| 213 | const auto* FunctionTable = reinterpret_cast<uint32_t*>(NtDllBase + Exports->AddressOfFunctions); |
| 214 | const auto* OrdinalTable = reinterpret_cast<uint16_t*>(NtDllBase + Exports->AddressOfNameOrdinals); |
| 215 | struct SyscallEntry { |
| 216 | const char* Name; |
| 217 | uint32_t RVA; |
| 218 | |
| 219 | bool operator<(const SyscallEntry& Other) const { |
| 220 | return RVA < Other.RVA; |
| 221 | } |
| 222 | }; |
| 223 | |
| 224 | // Cannot use any syscalls at this stage, so rely on a stack-allocated array |
| 225 | std::array<SyscallEntry, 0x200> SyscallTable; |
| 226 | auto SyscallTableEnd = SyscallTable.begin(); |
| 227 | |
| 228 | // Windows/Wine orders syscalls in memory by their ID, take advantage of that to find the syscall indices for those |
| 229 | // which we need to manually issue. Note that all functions starting with Nt besides NtGetTickCount are syscalls. |
| 230 | for (uint32_t Idx = 0; Idx < Exports->NumberOfNames; Idx++) { |
| 231 | const char* Name = reinterpret_cast<const char*>(NtDllBase + NameTable[Idx]); |
| 232 | if (Name[0] == 'N' && Name[1] == 't' && strcmp(Name, "NtGetTickCount") != 0) { |
| 233 | *SyscallTableEnd++ = {Name, FunctionTable[OrdinalTable[Idx]]}; |
| 234 | } |
| 235 | } |
| 236 | |
| 237 | // Sort such that index 0 is now syscall 0, etc |
| 238 | std::sort(SyscallTable.begin(), SyscallTableEnd); |
| 239 | |
| 240 | for (auto it = SyscallTable.begin(); it != SyscallTableEnd; it++) { |
| 241 | uint32_t CurSyscallId = static_cast<uint32_t>(std::distance(SyscallTable.begin(), it)); |
| 242 | if (strcmp(it->Name, "NtContinue") == 0) { |
| 243 | WineNtContinueSyscallId = CurSyscallId; |
| 244 | } else if (strcmp(it->Name, "NtAllocateVirtualMemory") == 0) { |
| 245 | WineNtAllocateVirtualMemorySyscallId = CurSyscallId; |
| 246 | } else if (strcmp(it->Name, "NtProtectVirtualMemory") == 0) { |
| 247 | WineNtProtectVirtualMemorySyscallId = CurSyscallId; |
| 248 | } |
| 249 | } |
| 250 | } |
| 251 | |
| 252 | // Syscall thunks may have been patched before FEX has loaded, the default call checker installed by ntdll into FEX will |
| 253 | // try to invoke the JIT when calling such patched syscalls but this obviously doesn't work before FEX is initalised. |