Experimental 64-bit host support

This commit is contained in:
2025-11-04 22:07:51 -07:00
parent 463686d01a
commit 3dd9fb77ff
64 changed files with 1993 additions and 844 deletions

View File

@@ -1,10 +1,5 @@
cmake_minimum_required(VERSION 3.13)
set(CMAKE_C_FLAGS_INIT "-m32")
set(CMAKE_CXX_FLAGS_INIT "-m32 -fno-exceptions -fno-rtti")
set(CMAKE_EXE_LINKER_FLAGS_INIT "-m32")
set(CMAKE_SHARED_LINKER_FLAGS_INIT "-m32")
project(wibo LANGUAGES ASM C CXX)
set(WIBO_VERSION "" CACHE STRING "Version string for the wibo binary; if empty, attempts to use git describe")
@@ -46,11 +41,21 @@ configure_file(
@ONLY
)
option(WIBO_64 "Build wibo for 64-bit host" OFF)
option(WIBO_ENABLE_FIXTURE_TESTS "Enable Win32 fixture tests (requires i686-w64-mingw32)" ON)
option(WIBO_ENABLE_LIBURING "Enable liburing for asynchronous I/O" OFF)
set(WIBO_ENABLE_LTO "AUTO" CACHE STRING "Enable link-time optimization (LTO)")
set_property(CACHE WIBO_ENABLE_LTO PROPERTY STRINGS "AUTO" "ON" "OFF")
add_compile_options(
$<IF:$<BOOL:${WIBO_64}>,-m64,-m32>
$<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions>
$<$<COMPILE_LANGUAGE:CXX>:-fno-rtti>
)
add_link_options(
$<IF:$<BOOL:${WIBO_64}>,-m64,-m32>
)
if (WIBO_ENABLE_LTO STREQUAL "AUTO")
if (CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
include(CheckIPOSupported)
@@ -88,6 +93,10 @@ FetchContent_MakeAvailable(mimalloc)
# Disable `note: the alignment of '_Atomic long long int' fields changed in GCC 11.1`
target_compile_options(mimalloc-obj PRIVATE -Wno-psabi)
target_compile_definitions(mimalloc-obj PRIVATE MI_USE_BUILTIN_THREAD_POINTER=1)
if (WIBO_64)
# Disable a noisy warning on startup
target_compile_definitions(mimalloc-obj PRIVATE MI_DEBUG=0)
endif()
if (WIBO_ENABLE_LIBURING)
FetchContent_Declare(
@@ -126,12 +135,12 @@ endif()
add_executable(wibo
dll/advapi32.cpp
dll/advapi32/md5.c
dll/advapi32/processthreadsapi.cpp
dll/advapi32/securitybaseapi.cpp
dll/advapi32/winbase.cpp
dll/advapi32/wincrypt.cpp
dll/advapi32/winreg.cpp
dll/advapi32/md5.c
dll/bcrypt.cpp
dll/crt.cpp
dll/kernel32.cpp
@@ -144,8 +153,8 @@ add_executable(wibo
dll/kernel32/interlockedapi.cpp
dll/kernel32/ioapiset.cpp
dll/kernel32/libloaderapi.cpp
dll/kernel32/namedpipeapi.cpp
dll/kernel32/memoryapi.cpp
dll/kernel32/namedpipeapi.cpp
dll/kernel32/processenv.cpp
dll/kernel32/processthreadsapi.cpp
dll/kernel32/profileapi.cpp
@@ -162,8 +171,8 @@ add_executable(wibo
dll/mscoree.cpp
dll/msvcrt.cpp
dll/ntdll.cpp
dll/rpcrt4.cpp
dll/ole32.cpp
dll/rpcrt4.cpp
dll/user32.cpp
dll/vcruntime.cpp
dll/version.cpp
@@ -173,21 +182,22 @@ add_executable(wibo
src/errors.cpp
src/files.cpp
src/handles.cpp
src/loader.cpp
src/heap.cpp
src/loader.cpp
src/main.cpp
src/modules.cpp
src/processes.cpp
src/resources.cpp
src/setup.S
src/strutil.cpp
src/tls.cpp
)
target_compile_definitions(wibo PRIVATE _GNU_SOURCE _FILE_OFFSET_BITS=64 _TIME_BITS=64)
target_compile_features(wibo PRIVATE cxx_std_20)
target_compile_options(wibo PRIVATE -Wall -Wextra)
target_link_options(wibo PRIVATE -no-pie -Wl,--image-base=0x90000000)
target_link_options(wibo PRIVATE -no-pie -Wl,--image-base=0x70000000)
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
target_compile_options(wibo PRIVATE -fno-pie -maccumulate-outgoing-args)
target_compile_options(wibo PRIVATE -maccumulate-outgoing-args)
target_link_options(wibo PRIVATE -maccumulate-outgoing-args)
endif()
target_include_directories(wibo PRIVATE dll src ${WIBO_GENERATED_HEADER_DIR})
@@ -242,15 +252,17 @@ function(wibo_codegen_module)
--dll ${module_NAME}
--headers ${module_HEADERS}
--namespace ${module_NAME}
--arch x86
--arch $<IF:$<BOOL:${WIBO_64}>,x86_64,x86>
--out-asm ${out_asm}
--out-hdr ${out_hdr}
-I ${CMAKE_CURRENT_SOURCE_DIR}
-I ${CMAKE_CURRENT_SOURCE_DIR}/dll
-I ${CMAKE_CURRENT_SOURCE_DIR}/src
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/gen_trampolines.py ${module_HEADERS})
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/gen_trampolines.py
${module_HEADERS}
)
target_sources(wibo PRIVATE ${out_asm})
set_source_files_properties(${out_asm} PROPERTIES COMPILE_FLAGS "-m32")
set_source_files_properties(${out_asm} PROPERTIES COMPILE_FLAGS $<IF:$<BOOL:${WIBO_64}>,-m64,-m32>)
endfunction()
wibo_codegen_module(NAME advapi32 HEADERS

View File

@@ -53,6 +53,46 @@
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"name": "debug64",
"displayName": "Debug (64-bit)",
"inherits": ["ninja-base"],
"binaryDir": "${sourceDir}/build/debug64",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"WIBO_64": "ON"
}
},
{
"name": "release64",
"displayName": "Release (64-bit)",
"inherits": ["ninja-base"],
"binaryDir": "${sourceDir}/build/release64",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"WIBO_64": "ON"
}
},
{
"name": "debug64-clang",
"displayName": "Debug (64-bit, Clang)",
"inherits": ["ninja-base", "clang-base"],
"binaryDir": "${sourceDir}/build/debug64-clang",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"WIBO_64": "ON"
}
},
{
"name": "release64-clang",
"displayName": "Release (64-bit, Clang)",
"inherits": ["ninja-base", "clang-base"],
"binaryDir": "${sourceDir}/build/release64-clang",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"WIBO_64": "ON"
}
}
],
"buildPresets": [
@@ -83,6 +123,34 @@
"configurePreset": "release-clang",
"targets": ["wibo", "wibo_test_fixtures"],
"configuration": "Release"
},
{
"name": "debug64",
"displayName": "Build (Debug, 64-bit)",
"configurePreset": "debug64",
"targets": ["wibo", "wibo_test_fixtures"],
"configuration": "Debug"
},
{
"name": "release64",
"displayName": "Build (Release, 64-bit)",
"configurePreset": "release64",
"targets": ["wibo", "wibo_test_fixtures"],
"configuration": "Release"
},
{
"name": "debug64-clang",
"displayName": "Build (Debug, 64-bit, Clang)",
"configurePreset": "debug64-clang",
"targets": ["wibo", "wibo_test_fixtures"],
"configuration": "Debug"
},
{
"name": "release64-clang",
"displayName": "Build (Release, 64-bit, Clang)",
"configurePreset": "release64-clang",
"targets": ["wibo", "wibo_test_fixtures"],
"configuration": "Release"
}
],
"testPresets": [
@@ -125,6 +193,46 @@
"outputOnFailure": true,
"shortProgress": true
}
},
{
"name": "debug64",
"displayName": "Run tests (Debug, 64-bit)",
"configurePreset": "debug64",
"configuration": "Debug",
"output": {
"outputOnFailure": true,
"shortProgress": true
}
},
{
"name": "release64",
"displayName": "Run tests (Release, 64-bit)",
"configurePreset": "release64",
"configuration": "Release",
"output": {
"outputOnFailure": true,
"shortProgress": true
}
},
{
"name": "debug64-clang",
"displayName": "Run tests (Debug, 64-bit, Clang)",
"configurePreset": "debug64-clang",
"configuration": "Debug",
"output": {
"outputOnFailure": true,
"shortProgress": true
}
},
{
"name": "release64-clang",
"displayName": "Run tests (Release, 64-bit, Clang)",
"configurePreset": "release64-clang",
"configuration": "Release",
"output": {
"outputOnFailure": true,
"shortProgress": true
}
}
]
}

View File

@@ -6,8 +6,6 @@
constexpr DWORD SECURITY_LOCAL_SYSTEM_RID = 18;
constexpr BYTE kNtAuthority[6] = {0, 0, 0, 0, 0, 5};
struct TokenObject : ObjectBase {
static constexpr ObjectType kType = ObjectType::Token;

View File

@@ -6,6 +6,7 @@
#include "handles.h"
#include "internal.h"
#include "kernel32/internal.h"
#include "types.h"
#include <algorithm>
#include <cstring>
@@ -13,6 +14,8 @@
namespace {
constexpr BYTE kNtAuthority[6] = {0, 0, 0, 0, 0, 5};
constexpr size_t kAceAlignment = 4;
constexpr DWORD ERROR_REVISION_MISMATCH = 1306;
constexpr DWORD ERROR_INVALID_ACL = 1336;
@@ -202,14 +205,14 @@ BOOL WINAPI AddAccessAllowedAce(PACL pAcl, DWORD dwAceRevision, DWORD AccessMask
return TRUE;
}
BOOL WINAPI FindFirstFreeAce(PACL pAcl, LPVOID *pAce) {
BOOL WINAPI FindFirstFreeAce(PACL pAcl, GUEST_PTR *pAce) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("FindFirstFreeAce(%p, %p)\n", pAcl, pAce);
if (!pAce) {
kernel32::setLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
*pAce = nullptr;
*pAce = GUEST_NULL;
if (!pAcl) {
kernel32::setLastError(ERROR_INVALID_PARAMETER);
return FALSE;
@@ -220,12 +223,12 @@ BOOL WINAPI FindFirstFreeAce(PACL pAcl, LPVOID *pAce) {
kernel32::setLastError(ERROR_INVALID_ACL);
return FALSE;
}
*pAce = reinterpret_cast<BYTE *>(pAcl) + used;
*pAce = toGuestPtr(reinterpret_cast<BYTE *>(pAcl) + used);
pAcl->AclSize = static_cast<WORD>(std::max<size_t>(pAcl->AclSize, used));
return TRUE;
}
BOOL WINAPI GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, LPBOOL lpbDaclPresent, PACL *pDacl,
BOOL WINAPI GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, LPBOOL lpbDaclPresent, GUEST_PTR *pDacl,
LPBOOL lpbDaclDefaulted) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("GetSecurityDescriptorDacl(%p, %p, %p, %p)\n", pSecurityDescriptor, lpbDaclPresent, pDacl,
@@ -246,7 +249,7 @@ BOOL WINAPI GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor,
*lpbDaclPresent = hasDacl;
if (!hasDacl) {
if (pDacl) {
*pDacl = nullptr;
*pDacl = GUEST_NULL;
}
if (lpbDaclDefaulted) {
*lpbDaclDefaulted = FALSE;
@@ -425,10 +428,10 @@ BOOL WINAPI InitializeSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescripto
pSecurityDescriptor->Revision = static_cast<BYTE>(dwRevision);
pSecurityDescriptor->Sbz1 = 0;
pSecurityDescriptor->Control = 0;
pSecurityDescriptor->Owner = nullptr;
pSecurityDescriptor->Group = nullptr;
pSecurityDescriptor->Sacl = nullptr;
pSecurityDescriptor->Dacl = nullptr;
pSecurityDescriptor->Owner = GUEST_NULL;
pSecurityDescriptor->Group = GUEST_NULL;
pSecurityDescriptor->Sacl = GUEST_NULL;
pSecurityDescriptor->Dacl = GUEST_NULL;
return TRUE;
}
@@ -446,9 +449,9 @@ BOOL WINAPI SetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor,
if (bDaclDefaulted) {
control = static_cast<WORD>(control | SE_DACL_DEFAULTED);
}
pSecurityDescriptor->Dacl = pDacl;
pSecurityDescriptor->Dacl = toGuestPtr(pDacl);
} else {
pSecurityDescriptor->Dacl = nullptr;
pSecurityDescriptor->Dacl = GUEST_NULL;
}
pSecurityDescriptor->Control = control;
return TRUE;

View File

@@ -30,10 +30,10 @@ struct SECURITY_DESCRIPTOR {
BYTE Revision;
BYTE Sbz1;
WORD Control;
void *Owner;
void *Group;
ACL *Sacl;
ACL *Dacl;
GUEST_PTR Owner;
GUEST_PTR Group;
GUEST_PTR Sacl;
GUEST_PTR Dacl;
};
using PSECURITY_DESCRIPTOR = SECURITY_DESCRIPTOR *;
@@ -85,7 +85,7 @@ namespace advapi32 {
BOOL WINAPI InitializeAcl(PACL pAcl, DWORD nAclLength, DWORD dwAclRevision);
BOOL WINAPI AddAccessAllowedAce(PACL pAcl, DWORD dwAceRevision, DWORD AccessMask, PSID pSid);
BOOL WINAPI FindFirstFreeAce(PACL pAcl, LPVOID *pAce);
BOOL WINAPI FindFirstFreeAce(PACL pAcl, GUEST_PTR *pAce);
PSID_IDENTIFIER_AUTHORITY WINAPI GetSidIdentifierAuthority(PSID pSid);
PUCHAR WINAPI GetSidSubAuthorityCount(PSID pSid);
PDWORD WINAPI GetSidSubAuthority(PSID pSid, DWORD nSubAuthority);
@@ -95,7 +95,7 @@ BOOL WINAPI DuplicateTokenEx(HANDLE hExistingToken, DWORD dwDesiredAccess, void
BOOL WINAPI CopySid(DWORD nDestinationSidLength, PSID pDestinationSid, PSID pSourceSid);
BOOL WINAPI InitializeSid(PSID sid, PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority, BYTE nSubAuthorityCount);
BOOL WINAPI EqualSid(PSID pSid1, PSID pSid2);
BOOL WINAPI GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, LPBOOL lpbDaclPresent, PACL *pDacl,
BOOL WINAPI GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, LPBOOL lpbDaclPresent, GUEST_PTR *pDacl,
LPBOOL lpbDaclDefaulted);
BOOL WINAPI SetKernelObjectSecurity(HANDLE Handle, SECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR SecurityDescriptor);

View File

@@ -15,6 +15,7 @@ namespace {
constexpr WCHAR kAccountSystem[] = {u'S', u'Y', u'S', u'T', u'E', u'M', u'\0'};
constexpr WCHAR kDomainNtAuthority[] = {u'N', u'T', u' ', u'A', u'U', u'T', u'H', u'O', u'R', u'I', u'T', u'Y', u'\0'};
constexpr BYTE kNtAuthority[6] = {0, 0, 0, 0, 0, 5};
std::mutex g_privilegeMapMutex;
std::unordered_map<std::string, LUID> g_privilegeLuidCache;

View File

@@ -17,8 +17,8 @@ enum SID_NAME_USE : DWORD {
namespace advapi32 {
BOOL WINAPI LookupAccountSidW(LPCWSTR lpSystemName, PSID Sid, LPWSTR Name, LPDWORD cchName,
LPWSTR ReferencedDomainName, LPDWORD cchReferencedDomainName, SID_NAME_USE *peUse);
BOOL WINAPI LookupAccountSidW(LPCWSTR lpSystemName, PSID Sid, LPWSTR Name, LPDWORD cchName, LPWSTR ReferencedDomainName,
LPDWORD cchReferencedDomainName, SID_NAME_USE *peUse);
BOOL WINAPI LookupPrivilegeValueA(LPCSTR lpSystemName, LPCSTR lpName, PLUID lpLuid);
BOOL WINAPI LookupPrivilegeValueW(LPCWSTR lpSystemName, LPCWSTR lpName, PLUID lpLuid);
BOOL WINAPI GetUserNameA(LPSTR lpBuffer, LPDWORD pcbBuffer);

View File

@@ -29,17 +29,17 @@ struct RegistryKeyObject : ObjectBase {
};
struct PredefinedKeyInfo {
uintptr_t value;
HKEY value;
const char16_t *name;
};
constexpr PredefinedKeyInfo kPredefinedKeyInfos[] = {
{static_cast<uintptr_t>(0x80000000u), u"HKEY_CLASSES_ROOT"},
{static_cast<uintptr_t>(0x80000001u), u"HKEY_CURRENT_USER"},
{static_cast<uintptr_t>(0x80000002u), u"HKEY_LOCAL_MACHINE"},
{static_cast<uintptr_t>(0x80000003u), u"HKEY_USERS"},
{static_cast<uintptr_t>(0x80000004u), u"HKEY_PERFORMANCE_DATA"},
{static_cast<uintptr_t>(0x80000005u), u"HKEY_CURRENT_CONFIG"},
{static_cast<HKEY>(0x80000000u), u"HKEY_CLASSES_ROOT"},
{static_cast<HKEY>(0x80000001u), u"HKEY_CURRENT_USER"},
{static_cast<HKEY>(0x80000002u), u"HKEY_LOCAL_MACHINE"},
{static_cast<HKEY>(0x80000003u), u"HKEY_USERS"},
{static_cast<HKEY>(0x80000004u), u"HKEY_PERFORMANCE_DATA"},
{static_cast<HKEY>(0x80000005u), u"HKEY_CURRENT_CONFIG"},
};
constexpr size_t kPredefinedKeyCount = std::size(kPredefinedKeyInfos);
@@ -82,7 +82,7 @@ std::u16string canonicalizeKeySegment(LPCWSTR input) {
return canonicalizeKeySegment(wide);
}
Pin<RegistryKeyObject> predefinedHandleForValue(uintptr_t value) {
Pin<RegistryKeyObject> predefinedHandleForValue(HKEY value) {
static std::array<Pin<RegistryKeyObject>, kPredefinedKeyCount> g_predefinedHandles = [] {
std::array<Pin<RegistryKeyObject>, kPredefinedKeyCount> arr;
for (size_t i = 0; i < kPredefinedKeyCount; ++i) {
@@ -101,11 +101,10 @@ Pin<RegistryKeyObject> predefinedHandleForValue(uintptr_t value) {
}
Pin<RegistryKeyObject> handleDataFromHKeyLocked(HKEY hKey) {
uintptr_t raw = reinterpret_cast<uintptr_t>(hKey);
if (raw == 0) {
if (hKey == NO_HANDLE) {
return {};
}
if (auto predefined = predefinedHandleForValue(raw)) {
if (auto predefined = predefinedHandleForValue(hKey)) {
return predefined;
}
auto obj = wibo::handles().getAs<RegistryKeyObject>(hKey);
@@ -116,9 +115,8 @@ Pin<RegistryKeyObject> handleDataFromHKeyLocked(HKEY hKey) {
}
bool isPredefinedKeyHandle(HKEY hKey) {
uintptr_t raw = reinterpret_cast<uintptr_t>(hKey);
return std::any_of(std::begin(kPredefinedKeyInfos), std::end(kPredefinedKeyInfos),
[raw](const PredefinedKeyInfo &info) { return info.value == raw; });
[hKey](const PredefinedKeyInfo &info) { return info.value == hKey; });
}
} // namespace
@@ -139,7 +137,7 @@ LSTATUS WINAPI RegCreateKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD Reserved, LPWS
kernel32::setLastError(ERROR_INVALID_PARAMETER);
return ERROR_INVALID_PARAMETER;
}
*phkResult = nullptr;
*phkResult = NO_HANDLE;
if (Reserved != 0) {
kernel32::setLastError(ERROR_INVALID_PARAMETER);
return ERROR_INVALID_PARAMETER;
@@ -220,7 +218,7 @@ LSTATUS WINAPI RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSA
kernel32::setLastError(ERROR_INVALID_PARAMETER);
return ERROR_INVALID_PARAMETER;
}
*phkResult = nullptr;
*phkResult = NO_HANDLE;
if ((ulOptions & ~REG_OPTION_OPEN_LINK) != 0) {
kernel32::setLastError(ERROR_INVALID_PARAMETER);
return ERROR_INVALID_PARAMETER;

View File

@@ -34,11 +34,9 @@ constexpr REGSAM KEY_WOW64_32KEY = 0x00000200;
namespace advapi32 {
LSTATUS WINAPI RegCreateKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD Reserved, LPSTR lpClass, DWORD dwOptions,
REGSAM samDesired, void *lpSecurityAttributes, PHKEY phkResult,
LPDWORD lpdwDisposition);
REGSAM samDesired, void *lpSecurityAttributes, PHKEY phkResult, LPDWORD lpdwDisposition);
LSTATUS WINAPI RegCreateKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD Reserved, LPWSTR lpClass, DWORD dwOptions,
REGSAM samDesired, void *lpSecurityAttributes, PHKEY phkResult,
LPDWORD lpdwDisposition);
REGSAM samDesired, void *lpSecurityAttributes, PHKEY phkResult, LPDWORD lpdwDisposition);
LSTATUS WINAPI RegOpenKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult);
LSTATUS WINAPI RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult);
LSTATUS WINAPI RegQueryValueExA(HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, BYTE *lpData,

View File

@@ -6,6 +6,7 @@
#include "heap.h"
#include "kernel32/internal.h"
#include "modules.h"
#include "types.h"
#include <csignal>
#include <cstdarg>
@@ -42,24 +43,29 @@ int _fmode = 0;
std::vector<_PVFV> atexitFuncs;
_invalid_parameter_handler invalidParameterHandler = nullptr;
void CDECL _initterm(const _PVFV *ppfn, const _PVFV *end) {
GUEST_PTR guestArgv = GUEST_NULL;
GUEST_PTR guestEnviron = GUEST_NULL;
void CDECL _initterm(GUEST_PTR *ppfn, GUEST_PTR *end) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("_initterm(%p, %p)\n", ppfn, end);
do {
if (_PVFV pfn = *++ppfn) {
if (GUEST_PTR pfn = *++ppfn) {
DEBUG_LOG("-> calling %p\n", pfn);
call__PVFV(pfn);
auto fn = reinterpret_cast<_PVFV>(fromGuestPtr(pfn));
call__PVFV(fn);
}
} while (ppfn < end);
}
int CDECL _initterm_e(const _PIFV *ppfn, const _PIFV *end) {
int CDECL _initterm_e(GUEST_PTR *ppfn, GUEST_PTR *end) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("_initterm_e(%p, %p)\n", ppfn, end);
do {
if (_PIFV pfn = *++ppfn) {
if (GUEST_PTR pfn = *++ppfn) {
DEBUG_LOG("-> calling %p\n", pfn);
int err = call__PIFV(pfn);
auto fn = reinterpret_cast<_PIFV>(fromGuestPtr(pfn));
int err = call__PIFV(fn);
if (err)
return err;
}
@@ -80,16 +86,16 @@ int CDECL _set_fmode(int mode) {
return 0;
}
int *CDECL __p__commode() {
GUEST_PTR CDECL __p__commode() {
HOST_CONTEXT_GUARD();
DEBUG_LOG("__p__commode()\n");
return &_commode;
return toGuestPtr(&_commode);
}
int *CDECL __p__fmode() {
GUEST_PTR CDECL __p__fmode() {
HOST_CONTEXT_GUARD();
DEBUG_LOG("__p__fmode()\n");
return &_fmode;
return toGuestPtr(&_fmode);
}
int CDECL _crt_atexit(void (*func)()) {
@@ -137,28 +143,79 @@ int CDECL _set_new_mode(int newhandlermode) {
return 0;
}
char **CDECL _get_initial_narrow_environment() {
GUEST_PTR CDECL _get_initial_narrow_environment() {
HOST_CONTEXT_GUARD();
DEBUG_LOG("_get_initial_narrow_environment()\n");
return environ;
if (guestEnviron == GUEST_NULL) {
int count = 0;
while (environ[count]) {
count++;
}
GUEST_PTR *buf = reinterpret_cast<GUEST_PTR *>(wibo::heap::guestMalloc(count * sizeof(GUEST_PTR)));
if (!buf) {
return GUEST_NULL;
}
for (int i = 0; i < count; i++) {
size_t len = ::strlen(environ[i]);
char *str = reinterpret_cast<char *>(wibo::heap::guestMalloc(len + 1));
::memcpy(str, environ[i], len + 1);
buf[i] = toGuestPtr(str);
}
guestEnviron = toGuestPtr(buf);
}
return guestEnviron;
}
char ***CDECL __p__environ() {
GUEST_PTR CDECL __p__environ() {
HOST_CONTEXT_GUARD();
DEBUG_LOG("__p__environ()\n");
return &environ;
if (guestEnviron == GUEST_NULL) {
int count = 0;
while (environ[count]) {
count++;
}
GUEST_PTR *buf = reinterpret_cast<GUEST_PTR *>(wibo::heap::guestMalloc(count * sizeof(GUEST_PTR)));
if (!buf) {
return GUEST_NULL;
}
for (int i = 0; i < count; i++) {
size_t len = ::strlen(environ[i]);
char *str = reinterpret_cast<char *>(wibo::heap::guestMalloc(len + 1));
::memcpy(str, environ[i], len + 1);
buf[i] = toGuestPtr(str);
}
guestEnviron = toGuestPtr(buf);
}
return toGuestPtr(&environ);
}
char ***CDECL __p___argv() {
GUEST_PTR CDECL __p___argv() {
HOST_CONTEXT_GUARD();
DEBUG_LOG("__p___argv()\n");
return &wibo::argv;
if (guestArgv == GUEST_NULL) {
int count = 0;
while (wibo::argv[count]) {
count++;
}
GUEST_PTR *buf = reinterpret_cast<GUEST_PTR *>(wibo::heap::guestMalloc(count * sizeof(GUEST_PTR)));
if (!buf) {
return GUEST_NULL;
}
for (int i = 0; i < count; i++) {
size_t len = ::strlen(wibo::argv[i]);
char *str = reinterpret_cast<char *>(wibo::heap::guestMalloc(len + 1));
::memcpy(str, wibo::argv[i], len + 1);
buf[i] = toGuestPtr(str);
}
guestArgv = toGuestPtr(buf);
}
return toGuestPtr(&guestArgv);
}
int *CDECL __p___argc() {
GUEST_PTR CDECL __p___argc() {
HOST_CONTEXT_GUARD();
DEBUG_LOG("__p___argc()\n");
return &wibo::argc;
return toGuestPtr(&wibo::argc);
}
SIZE_T CDECL strlen(const char *str) {
@@ -258,9 +315,9 @@ int CDECL _initialize_onexit_table(_onexit_table_t *table) {
return -1;
if (table->first != table->last)
return 0;
table->first = nullptr;
table->last = nullptr;
table->end = nullptr;
table->first = GUEST_NULL;
table->last = GUEST_NULL;
table->end = GUEST_NULL;
return 0;
}
@@ -269,20 +326,23 @@ int CDECL _register_onexit_function(_onexit_table_t *table, _onexit_t func) {
DEBUG_LOG("_register_onexit_function(%p, %p)\n", table, func);
if (!table || !func)
return -1;
if (table->last == table->end) {
size_t count = table->end - table->first;
GUEST_PTR *first = reinterpret_cast<GUEST_PTR *>(fromGuestPtr(table->first));
GUEST_PTR *last = reinterpret_cast<GUEST_PTR *>(fromGuestPtr(table->last));
GUEST_PTR *end = reinterpret_cast<GUEST_PTR *>(fromGuestPtr(table->end));
if (last == end) {
size_t count = end - first;
size_t newCount = count + 1;
if (newCount <= 0)
return -1;
_onexit_t *newTable =
static_cast<_onexit_t *>(wibo::heap::guestRealloc(table->first, newCount * sizeof(_onexit_t)));
GUEST_PTR *newTable = static_cast<GUEST_PTR *>(wibo::heap::guestRealloc(first, newCount * sizeof(GUEST_PTR)));
if (!newTable)
return -1;
table->first = newTable;
table->last = newTable + count;
table->end = newTable + newCount;
table->first = toGuestPtr(newTable);
last = newTable + count;
table->end = toGuestPtr(newTable + newCount);
}
*table->last++ = func;
*last = toGuestPtr(reinterpret_cast<void *>(func));
table->last = toGuestPtr(last + 1);
return 0;
}
@@ -291,9 +351,12 @@ int CDECL _execute_onexit_table(_onexit_table_t *table) {
DEBUG_LOG("_execute_onexit_table(%p)\n", table);
if (!table)
return -1;
for (auto it = table->first; it != table->last; ++it) {
DEBUG_LOG("Calling onexit_table function %p\n", *it);
call__onexit_t(*it);
GUEST_PTR *first = reinterpret_cast<GUEST_PTR *>(fromGuestPtr(table->first));
GUEST_PTR *last = reinterpret_cast<GUEST_PTR *>(fromGuestPtr(table->last));
for (auto it = first; it != last; ++it) {
_onexit_t fn = reinterpret_cast<_onexit_t>(fromGuestPtr(*it));
DEBUG_LOG("Calling onexit_table function %p\n", fn);
call__onexit_t(fn);
}
return 0;
}
@@ -345,7 +408,7 @@ void *CDECL __acrt_iob_func(unsigned int index) {
return nullptr;
}
int CDECL_NO_CONV __stdio_common_vfprintf(unsigned long long options, _FILE *stream, const char *format, void *locale,
int CDECL_NO_CONV __stdio_common_vfprintf(ULONGLONG options, _FILE *stream, const char *format, void *locale,
va_list args) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("__stdio_common_vfprintf(%llu, %p, %s, %p, %p)\n", options, stream, format, locale, args);
@@ -355,8 +418,8 @@ int CDECL_NO_CONV __stdio_common_vfprintf(unsigned long long options, _FILE *str
return vfprintf(hostFile, format, args);
}
int CDECL_NO_CONV __stdio_common_vsprintf(unsigned long long options, char *buffer, SIZE_T len, const char *format,
void *locale, va_list args) {
int CDECL_NO_CONV __stdio_common_vsprintf(ULONGLONG options, char *buffer, SIZE_T len, const char *format, void *locale,
va_list args) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("__stdio_common_vsprintf(%llu, %p, %zu, %s, %p, ...)\n", options, buffer, len, format, locale);
if (!buffer || !format)

View File

@@ -23,9 +23,9 @@ typedef int(_CC_CDECL *sort_compare)(const void *, const void *);
typedef int(_CC_CDECL *_onexit_t)();
struct _onexit_table_t {
_onexit_t *first;
_onexit_t *last;
_onexit_t *end;
GUEST_PTR first;
GUEST_PTR last;
GUEST_PTR end;
};
namespace crt {
@@ -33,23 +33,23 @@ namespace crt {
extern int _commode;
extern int _fmode;
void CDECL _initterm(const _PVFV *ppfn, const _PVFV *end);
int CDECL _initterm_e(const _PIFV *ppfn, const _PIFV *end);
void CDECL _initterm(GUEST_PTR *ppfn, GUEST_PTR *end);
int CDECL _initterm_e(GUEST_PTR *ppfn, GUEST_PTR *end);
void CDECL _set_app_type(_crt_app_type type);
int CDECL _set_fmode(int mode);
int *CDECL __p__commode();
int *CDECL __p__fmode();
int CDECL _crt_atexit(void (*func)());
GUEST_PTR CDECL __p__commode();
GUEST_PTR CDECL __p__fmode();
int CDECL _crt_atexit(_PVFV func);
int CDECL _configure_narrow_argv(_crt_argv_mode mode);
_invalid_parameter_handler CDECL _set_invalid_parameter_handler(_invalid_parameter_handler newHandler);
int CDECL _controlfp_s(unsigned int *currentControl, unsigned int newControl, unsigned int mask);
int CDECL _configthreadlocale(int per_thread_locale_type);
int CDECL _initialize_narrow_environment();
int CDECL _set_new_mode(int newhandlermode);
char **CDECL _get_initial_narrow_environment();
char ***CDECL __p__environ();
char ***CDECL __p___argv();
int *CDECL __p___argc();
GUEST_PTR CDECL _get_initial_narrow_environment();
GUEST_PTR CDECL __p__environ();
GUEST_PTR CDECL __p___argv();
GUEST_PTR CDECL __p___argc();
SIZE_T CDECL strlen(const char *str);
int CDECL strcmp(const char *lhs, const char *rhs);
int CDECL strncmp(const char *lhs, const char *rhs, SIZE_T count);
@@ -74,10 +74,12 @@ void CDECL _exit(int status);
void CDECL abort();
signal_handler CDECL signal(int signum, signal_handler handler);
void *CDECL __acrt_iob_func(unsigned int index);
int CDECL_NO_CONV __stdio_common_vfprintf(unsigned long long options, _FILE *stream, const char *format, void *locale,
#ifndef __x86_64__ // TODO
int CDECL_NO_CONV __stdio_common_vfprintf(ULONGLONG options, _FILE *stream, const char *format, void *locale,
va_list args);
int CDECL_NO_CONV __stdio_common_vsprintf(unsigned long long options, char *buffer, SIZE_T len, const char *format,
int CDECL_NO_CONV __stdio_common_vsprintf(ULONGLONG options, char *buffer, SIZE_T len, const char *format,
void *locale, va_list args);
#endif
void CDECL qsort(void *base, SIZE_T num, SIZE_T size, sort_compare compare);
int CDECL puts(const char *str);

View File

@@ -7,14 +7,14 @@ constexpr DWORD EXCEPTION_MAXIMUM_PARAMETERS = 15;
struct EXCEPTION_RECORD {
DWORD ExceptionCode;
DWORD ExceptionFlags;
EXCEPTION_RECORD *ExceptionRecord;
PVOID ExceptionAddress;
GUEST_PTR ExceptionRecord;
GUEST_PTR ExceptionAddress;
DWORD NumberParameters;
ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
};
using PEXCEPTION_RECORD = EXCEPTION_RECORD *;
using PCONTEXT = void *;
using PEXCEPTION_RECORD = GUEST_PTR;
using PCONTEXT = GUEST_PTR;
struct EXCEPTION_POINTERS {
PEXCEPTION_RECORD ExceptionRecord;

View File

@@ -12,6 +12,7 @@
#include "overlapped_util.h"
#include "strutil.h"
#include "timeutil.h"
#include "types.h"
#include <algorithm>
#include <cctype>
@@ -146,24 +147,24 @@ struct FindSearchHandle {
};
std::mutex g_findHandleMutex;
std::unordered_map<FindSearchHandle *, std::unique_ptr<FindSearchHandle>> g_findHandles;
HANDLE g_nextFindHandle = 1;
std::unordered_map<HANDLE, std::unique_ptr<FindSearchHandle>> g_findHandles;
HANDLE registerFindHandle(std::unique_ptr<FindSearchHandle> handle) {
if (!handle) {
return INVALID_HANDLE_VALUE;
}
FindSearchHandle *raw = handle.get();
std::lock_guard lk(g_findHandleMutex);
HANDLE raw = g_nextFindHandle++;
g_findHandles.emplace(raw, std::move(handle));
return reinterpret_cast<HANDLE>(raw);
return raw;
}
FindSearchHandle *lookupFindHandleLocked(HANDLE handle) {
if (handle == nullptr) {
if (handle == NO_HANDLE) {
return nullptr;
}
auto *raw = reinterpret_cast<FindSearchHandle *>(handle);
auto it = g_findHandles.find(raw);
auto it = g_findHandles.find(handle);
if (it == g_findHandles.end()) {
return nullptr;
}
@@ -172,8 +173,7 @@ FindSearchHandle *lookupFindHandleLocked(HANDLE handle) {
std::unique_ptr<FindSearchHandle> detachFindHandle(HANDLE handle) {
std::lock_guard lk(g_findHandleMutex);
auto *raw = reinterpret_cast<FindSearchHandle *>(handle);
auto it = g_findHandles.find(raw);
auto it = g_findHandles.find(handle);
if (it == g_findHandles.end()) {
return nullptr;
}
@@ -1185,7 +1185,7 @@ DWORD WINAPI SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistance
HOST_CONTEXT_GUARD();
DEBUG_LOG("SetFilePointer(%p, %ld, %p, %u)\n", hFile, static_cast<long>(lDistanceToMove), lpDistanceToMoveHigh,
dwMoveMethod);
if (hFile == nullptr) {
if (hFile == NO_HANDLE) {
setLastError(ERROR_INVALID_HANDLE);
return INVALID_SET_FILE_POINTER;
}
@@ -1224,7 +1224,8 @@ DWORD WINAPI SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistance
BOOL WINAPI SetFilePointerEx(HANDLE hFile, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER lpNewFilePointer,
DWORD dwMoveMethod) {
HOST_CONTEXT_GUARD();
if (hFile == nullptr) {
DEBUG_LOG("SetFilePointerEx(%p, %lld, %p, %u)\n", hFile, liDistanceToMove.QuadPart, lpNewFilePointer, dwMoveMethod);
if (hFile == NO_HANDLE) {
setLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
@@ -1537,12 +1538,12 @@ DWORD WINAPI GetFileType(HANDLE hFile) {
return type;
}
DWORD WINAPI GetFullPathNameA(LPCSTR lpFileName, DWORD nBufferLength, LPSTR lpBuffer, LPSTR *lpFilePart) {
DWORD WINAPI GetFullPathNameA(LPCSTR lpFileName, DWORD nBufferLength, LPSTR lpBuffer, GUEST_PTR *lpFilePart) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("GetFullPathNameA(%s, %u)\n", lpFileName ? lpFileName : "(null)", nBufferLength);
if (lpFilePart) {
*lpFilePart = nullptr;
*lpFilePart = GUEST_NULL;
}
if (!lpFileName) {
@@ -1580,21 +1581,21 @@ DWORD WINAPI GetFullPathNameA(LPCSTR lpFileName, DWORD nBufferLength, LPSTR lpBu
if (lpFilePart) {
if (info.filePartOffset != std::string::npos && info.filePartOffset < pathLen) {
*lpFilePart = lpBuffer + info.filePartOffset;
*lpFilePart = toGuestPtr(lpBuffer + info.filePartOffset);
} else {
*lpFilePart = nullptr;
*lpFilePart = GUEST_NULL;
}
}
return static_cast<DWORD>(pathLen);
}
DWORD WINAPI GetFullPathNameW(LPCWSTR lpFileName, DWORD nBufferLength, LPWSTR lpBuffer, LPWSTR *lpFilePart) {
DWORD WINAPI GetFullPathNameW(LPCWSTR lpFileName, DWORD nBufferLength, LPWSTR lpBuffer, GUEST_PTR *lpFilePart) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("GetFullPathNameW(%p, %u)\n", lpFileName, nBufferLength);
if (lpFilePart) {
*lpFilePart = nullptr;
*lpFilePart = GUEST_NULL;
}
if (!lpFileName) {
@@ -1633,9 +1634,9 @@ DWORD WINAPI GetFullPathNameW(LPCWSTR lpFileName, DWORD nBufferLength, LPWSTR lp
if (lpFilePart) {
if (info.filePartOffset != std::string::npos && info.filePartOffset < info.path.size()) {
*lpFilePart = lpBuffer + info.filePartOffset;
*lpFilePart = toGuestPtr(lpBuffer + info.filePartOffset);
} else {
*lpFilePart = nullptr;
*lpFilePart = GUEST_NULL;
}
}
@@ -1883,7 +1884,7 @@ BOOL WINAPI FindNextFileW(HANDLE hFindFile, LPWIN32_FIND_DATAW lpFindFileData) {
BOOL WINAPI FindClose(HANDLE hFindFile) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("FindClose(%p)\n", hFindFile);
if (hFindFile == nullptr) {
if (hFindFile == NO_HANDLE) {
DEBUG_LOG(" -> ERROR_INVALID_HANDLE\n");
setLastError(ERROR_INVALID_HANDLE);
return FALSE;

View File

@@ -56,8 +56,8 @@ constexpr DWORD INVALID_FILE_SIZE = 0xFFFFFFFF;
namespace kernel32 {
DWORD WINAPI GetFullPathNameA(LPCSTR lpFileName, DWORD nBufferLength, LPSTR lpBuffer, LPSTR *lpFilePart);
DWORD WINAPI GetFullPathNameW(LPCWSTR lpFileName, DWORD nBufferLength, LPWSTR lpBuffer, LPWSTR *lpFilePart);
DWORD WINAPI GetFullPathNameA(LPCSTR lpFileName, DWORD nBufferLength, LPSTR lpBuffer, GUEST_PTR *lpFilePart);
DWORD WINAPI GetFullPathNameW(LPCWSTR lpFileName, DWORD nBufferLength, LPWSTR lpBuffer, GUEST_PTR *lpFilePart);
DWORD WINAPI GetShortPathNameA(LPCSTR lpszLongPath, LPSTR lpszShortPath, DWORD cchBuffer);
DWORD WINAPI GetShortPathNameW(LPCWSTR lpszLongPath, LPWSTR lpszShortPath, DWORD cchBuffer);
UINT WINAPI GetTempFileNameA(LPCSTR lpPathName, LPCSTR lpPrefixString, UINT uUnique, LPSTR lpTempFileName);

View File

@@ -18,7 +18,7 @@ using kernel32::HeapObject;
namespace {
std::once_flag g_processHeapInitFlag;
HANDLE g_processHeapHandle = nullptr;
HANDLE g_processHeapHandle = NO_HANDLE;
HeapObject *g_processHeapRecord = nullptr;
void ensureProcessHeapInitialized() {
@@ -71,7 +71,7 @@ HeapObject::~HeapObject() {
heap = nullptr;
}
if (isProcessHeap) {
g_processHeapHandle = nullptr;
g_processHeapHandle = NO_HANDLE;
g_processHeapRecord = nullptr;
}
}
@@ -83,13 +83,13 @@ HANDLE WINAPI HeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximum
DEBUG_LOG("HeapCreate(%u, %zu, %zu)\n", flOptions, dwInitialSize, dwMaximumSize);
if (dwMaximumSize != 0 && dwInitialSize > dwMaximumSize) {
setLastError(ERROR_INVALID_PARAMETER);
return nullptr;
return NO_HANDLE;
}
mi_heap_t *heap = wibo::heap::createGuestHeap();
if (!heap) {
setLastError(ERROR_NOT_ENOUGH_MEMORY);
return nullptr;
return NO_HANDLE;
}
auto record = make_pin<HeapObject>(heap);

View File

@@ -5,13 +5,13 @@
namespace kernel32 {
struct SLIST_ENTRY {
SLIST_ENTRY *Next;
GUEST_PTR Next;
};
using PSLIST_ENTRY = SLIST_ENTRY *;
struct SLIST_HEADER {
SLIST_ENTRY *Head;
GUEST_PTR Head;
unsigned short Depth;
unsigned short Sequence;
};

View File

@@ -160,17 +160,15 @@ struct HeapObject : public ObjectBase {
[[nodiscard]] inline bool canAccess() const { return isProcessHeap || (isOwner() && heap != nullptr); }
};
inline constexpr uintptr_t kPseudoCurrentProcessHandleValue = static_cast<uintptr_t>(-1);
inline constexpr uintptr_t kPseudoCurrentThreadHandleValue = static_cast<uintptr_t>(-2);
inline constexpr HANDLE kPseudoCurrentProcessHandleValue = static_cast<HANDLE>(-1);
inline constexpr HANDLE kPseudoCurrentThreadHandleValue = static_cast<HANDLE>(-2);
inline bool isPseudoCurrentProcessHandle(HANDLE h) {
uintptr_t rawHandle = reinterpret_cast<uintptr_t>(h);
return rawHandle == kPseudoCurrentProcessHandleValue;
return h == kPseudoCurrentProcessHandleValue;
}
inline bool isPseudoCurrentThreadHandle(HANDLE h) {
uintptr_t rawHandle = reinterpret_cast<uintptr_t>(h);
return rawHandle == kPseudoCurrentThreadHandleValue;
return h == kPseudoCurrentThreadHandleValue;
}
void tryMarkExecutable(void *mem);

View File

@@ -6,6 +6,7 @@
#include "modules.h"
#include "resources.h"
#include "strutil.h"
#include "types.h"
#include <algorithm>
#include <cassert>
@@ -20,13 +21,13 @@ HRSRC findResourceInternal(HMODULE hModule, const wibo::ResourceIdentifier &type
auto *exe = wibo::executableFromModule(hModule);
if (!exe) {
kernel32::setLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
return nullptr;
return NO_HANDLE;
}
wibo::ResourceLocation loc;
if (!exe->findResource(type, name, language, loc)) {
return nullptr;
return NO_HANDLE;
}
return reinterpret_cast<HRSRC>(const_cast<void *>(loc.dataEntry));
return toGuestPtr(loc.dataEntry);
}
} // namespace
@@ -58,7 +59,7 @@ HMODULE WINAPI GetModuleHandleA(LPCSTR lpModuleName) {
const auto *module = wibo::findLoadedModule(lpModuleName);
if (!module) {
setLastError(ERROR_MOD_NOT_FOUND);
return nullptr;
return NO_HANDLE;
}
return module->handle;
}
@@ -111,7 +112,7 @@ DWORD WINAPI GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, DWORD nSize)
DWORD WINAPI GetModuleFileNameW(HMODULE hModule, LPWSTR lpFilename, DWORD nSize) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("GetModuleFileNameW(%p, %s, %u)\n", hModule, wideStringToString(lpFilename).c_str(), nSize);
DEBUG_LOG("GetModuleFileNameW(%p, %p, %u)\n", hModule, lpFilename, nSize);
if (!lpFilename) {
setLastError(ERROR_INVALID_PARAMETER);
return 0;
@@ -187,25 +188,25 @@ HGLOBAL WINAPI LoadResource(HMODULE hModule, HRSRC hResInfo) {
DEBUG_LOG("LoadResource %p %p\n", hModule, hResInfo);
if (!hResInfo) {
setLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
return nullptr;
return GUEST_NULL;
}
auto *exe = wibo::executableFromModule(hModule);
if (!exe || !exe->rsrcBase) {
setLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
return nullptr;
return GUEST_NULL;
}
const auto *entry = reinterpret_cast<const wibo::ImageResourceDataEntry *>(hResInfo);
if (!wibo::resourceEntryBelongsToExecutable(*exe, entry)) {
setLastError(ERROR_INVALID_PARAMETER);
return nullptr;
return GUEST_NULL;
}
return const_cast<void *>(exe->fromRVA<const void>(entry->offsetToData));
return toGuestPtr(exe->fromRVA<const void>(entry->offsetToData));
}
LPVOID WINAPI LockResource(HGLOBAL hResData) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("LockResource(%p)\n", hResData);
return hResData;
return (LPVOID)hResData;
}
DWORD WINAPI SizeofResource(HMODULE hModule, HRSRC hResInfo) {
@@ -234,7 +235,7 @@ HMODULE WINAPI LoadLibraryA(LPCSTR lpLibFileName) {
const auto *info = wibo::loadModule(lpLibFileName);
if (!info) {
// lastError is set by loadModule
return nullptr;
return NO_HANDLE;
}
return info->handle;
}
@@ -242,7 +243,7 @@ HMODULE WINAPI LoadLibraryA(LPCSTR lpLibFileName) {
HMODULE WINAPI LoadLibraryW(LPCWSTR lpLibFileName) {
HOST_CONTEXT_GUARD();
if (!lpLibFileName) {
return nullptr;
return NO_HANDLE;
}
auto filename = wideStringToString(lpLibFileName);
DEBUG_LOG("LoadLibraryW(%s)\n", filename.c_str());

View File

@@ -7,6 +7,7 @@
#include "heap.h"
#include "internal.h"
#include "strutil.h"
#include "types.h"
#include <cerrno>
#include <cstring>
@@ -161,8 +162,8 @@ bool mappedViewRegionForAddress(uintptr_t request, uintptr_t pageBase, MEMORY_BA
}
uintptr_t blockStart = viewStart;
uintptr_t blockEnd = alignUp(viewEnd, pageSize);
info.BaseAddress = reinterpret_cast<void *>(blockStart);
info.AllocationBase = reinterpret_cast<void *>(view.viewBase);
info.BaseAddress = toGuestPtr(reinterpret_cast<void *>(blockStart));
info.AllocationBase = toGuestPtr(reinterpret_cast<void *>(view.viewBase));
info.AllocationProtect = view.allocationProtect;
info.RegionSize = blockEnd > blockStart ? blockEnd - blockStart : 0;
info.State = MEM_COMMIT;
@@ -189,7 +190,7 @@ HANDLE WINAPI CreateFileMappingA(HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappi
if (flProtect != PAGE_READONLY && flProtect != PAGE_READWRITE && flProtect != PAGE_WRITECOPY) {
DEBUG_LOG("CreateFileMappingA: unsupported protection 0x%x\n", flProtect);
setLastError(ERROR_INVALID_PARAMETER);
return nullptr;
return NO_HANDLE;
}
auto mapping = make_pin<MappingObject>();
@@ -200,25 +201,25 @@ HANDLE WINAPI CreateFileMappingA(HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappi
mapping->fd = -1;
if (size == 0) {
setLastError(ERROR_INVALID_PARAMETER);
return nullptr;
return NO_HANDLE;
}
mapping->maxSize = size;
} else {
auto file = wibo::handles().getAs<FileObject>(hFile);
if (!file || !file->valid()) {
setLastError(ERROR_INVALID_HANDLE);
return nullptr;
return NO_HANDLE;
}
int dupFd = fcntl(file->fd, F_DUPFD_CLOEXEC, 0);
if (dupFd == -1) {
setLastErrorFromErrno();
return nullptr;
return NO_HANDLE;
}
mapping->fd = dupFd;
if (size == 0) {
off_t fileSize = lseek(dupFd, 0, SEEK_END);
if (fileSize < 0) {
return nullptr;
return NO_HANDLE;
}
size = static_cast<uint64_t>(fileSize);
}

View File

@@ -4,7 +4,7 @@
struct SECURITY_ATTRIBUTES {
DWORD nLength;
LPVOID lpSecurityDescriptor;
GUEST_PTR lpSecurityDescriptor;
BOOL bInheritHandle;
};
@@ -86,7 +86,7 @@ typedef struct _OVERLAPPED {
DWORD Offset;
DWORD OffsetHigh;
};
PVOID Pointer;
GUEST_PTR Pointer;
};
HANDLE hEvent;
} OVERLAPPED, *LPOVERLAPPED;

View File

@@ -355,8 +355,8 @@ BOOL WINAPI CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBU
setLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
*hReadPipe = nullptr;
*hWritePipe = nullptr;
*hReadPipe = NO_HANDLE;
*hWritePipe = NO_HANDLE;
int pipeFds[2];
if (pipe(pipeFds) != 0) {

View File

@@ -1,17 +1,14 @@
#pragma once
#include "errors.h"
#include "handles.h"
#include "internal.h"
#include "minwinbase.h"
#include <cstdint>
namespace kernel32::detail {
inline HANDLE normalizedOverlappedEventHandle(const OVERLAPPED *ov) {
if (!ov || (reinterpret_cast<uintptr_t>(ov->hEvent) & 1U) != 0) {
return nullptr;
if (!ov || (ov->hEvent & 1U) != 0) {
return NO_HANDLE;
}
return ov->hEvent;
}

View File

@@ -6,6 +6,7 @@
#include "heap.h"
#include "internal.h"
#include "strutil.h"
#include "types.h"
#include <cstdlib>
#include <cstring>
@@ -16,6 +17,9 @@
namespace {
GUEST_PTR g_commandLineA = GUEST_NULL;
GUEST_PTR g_commandLineW = GUEST_NULL;
std::string convertEnvValueForWindows(const std::string &name, const char *rawValue) {
if (!rawValue) {
return {};
@@ -42,16 +46,26 @@ std::string convertEnvValueToHost(const std::string &name, const char *rawValue)
namespace kernel32 {
LPSTR WINAPI GetCommandLineA() {
GUEST_PTR WINAPI GetCommandLineA() {
HOST_CONTEXT_GUARD();
DEBUG_LOG("GetCommandLineA() -> %s\n", wibo::commandLine.c_str());
return const_cast<LPSTR>(wibo::commandLine.c_str());
if (g_commandLineA == GUEST_NULL) {
void *tmp = wibo::heap::guestCalloc(1, wibo::commandLine.size() + 1);
memcpy(tmp, wibo::commandLine.c_str(), wibo::commandLine.size());
g_commandLineA = toGuestPtr(tmp);
}
return g_commandLineA;
}
LPWSTR WINAPI GetCommandLineW() {
GUEST_PTR WINAPI GetCommandLineW() {
HOST_CONTEXT_GUARD();
DEBUG_LOG("GetCommandLineW() -> %s\n", wideStringToString(wibo::commandLineW.data()).c_str());
return wibo::commandLineW.data();
if (g_commandLineW == GUEST_NULL) {
void *tmp = wibo::heap::guestCalloc(1, wibo::commandLineW.size() * sizeof(WCHAR) + sizeof(WCHAR));
memcpy(tmp, wibo::commandLineW.data(), wibo::commandLineW.size() * sizeof(WCHAR));
g_commandLineW = toGuestPtr(tmp);
}
return g_commandLineW;
}
HANDLE WINAPI GetStdHandle(DWORD nStdHandle) {
@@ -66,7 +80,11 @@ BOOL WINAPI SetStdHandle(DWORD nStdHandle, HANDLE hHandle) {
return files::setStdHandle(nStdHandle, hHandle);
}
LPCH WINAPI GetEnvironmentStrings() {
GUEST_PTR WINAPI GetEnvironmentStrings() {
return GetEnvironmentStringsA();
}
GUEST_PTR WINAPI GetEnvironmentStringsA() {
HOST_CONTEXT_GUARD();
DEBUG_LOG("GetEnvironmentStrings()\n");
@@ -82,7 +100,7 @@ LPCH WINAPI GetEnvironmentStrings() {
char *buffer = static_cast<char *>(wibo::heap::guestMalloc(bufSize));
if (!buffer) {
setLastError(ERROR_NOT_ENOUGH_MEMORY);
return nullptr;
return GUEST_NULL;
}
char *ptr = buffer;
work = environ;
@@ -96,10 +114,10 @@ LPCH WINAPI GetEnvironmentStrings() {
}
*ptr = 0;
return buffer;
return toGuestPtr(buffer);
}
LPWCH WINAPI GetEnvironmentStringsW() {
GUEST_PTR WINAPI GetEnvironmentStringsW() {
HOST_CONTEXT_GUARD();
DEBUG_LOG("GetEnvironmentStringsW()\n");
@@ -115,7 +133,7 @@ LPWCH WINAPI GetEnvironmentStringsW() {
uint16_t *buffer = static_cast<uint16_t *>(wibo::heap::guestMalloc(bufSizeW * sizeof(uint16_t)));
if (!buffer) {
setLastError(ERROR_NOT_ENOUGH_MEMORY);
return nullptr;
return GUEST_NULL;
}
uint16_t *ptr = buffer;
work = environ;
@@ -131,7 +149,7 @@ LPWCH WINAPI GetEnvironmentStringsW() {
}
*ptr = 0;
return buffer;
return toGuestPtr(buffer);
}
BOOL WINAPI FreeEnvironmentStringsA(LPCH penv) {

View File

@@ -4,12 +4,13 @@
namespace kernel32 {
LPSTR WINAPI GetCommandLineA();
LPWSTR WINAPI GetCommandLineW();
GUEST_PTR WINAPI GetCommandLineA();
GUEST_PTR WINAPI GetCommandLineW();
HANDLE WINAPI GetStdHandle(DWORD nStdHandle);
BOOL WINAPI SetStdHandle(DWORD nStdHandle, HANDLE hHandle);
LPCH WINAPI GetEnvironmentStrings();
LPWCH WINAPI GetEnvironmentStringsW();
GUEST_PTR WINAPI GetEnvironmentStrings();
GUEST_PTR WINAPI GetEnvironmentStringsA();
GUEST_PTR WINAPI GetEnvironmentStringsW();
BOOL WINAPI FreeEnvironmentStringsA(LPCH penv);
BOOL WINAPI FreeEnvironmentStringsW(LPWCH penv);
DWORD WINAPI GetEnvironmentVariableA(LPCSTR lpName, LPSTR lpBuffer, DWORD nSize);

View File

@@ -13,6 +13,7 @@
#include "strutil.h"
#include "timeutil.h"
#include "tls.h"
#include "types.h"
#include <cerrno>
#include <csignal>
@@ -83,7 +84,7 @@ template <typename StartupInfo> void populateStartupInfo(StartupInfo *info) {
info->dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
info->wShowWindow = SW_SHOWNORMAL;
info->cbReserved2 = 0;
info->lpReserved2 = nullptr;
info->lpReserved2 = GUEST_NULL;
info->hStdInput = files::getStdHandle(STD_INPUT_HANDLE);
info->hStdOutput = files::getStdHandle(STD_OUTPUT_HANDLE);
info->hStdError = files::getStdHandle(STD_ERROR_HANDLE);
@@ -182,7 +183,7 @@ BOOL WINAPI IsProcessorFeaturePresent(DWORD ProcessorFeature) {
HANDLE WINAPI GetCurrentProcess() {
HOST_CONTEXT_GUARD();
DEBUG_LOG("GetCurrentProcess() -> %p\n", reinterpret_cast<void *>(static_cast<uintptr_t>(-1)));
return reinterpret_cast<HANDLE>(static_cast<uintptr_t>(-1));
return kPseudoCurrentProcessHandleValue;
}
DWORD WINAPI GetCurrentProcessId() {
@@ -395,9 +396,9 @@ LPVOID WINAPI TlsGetValue(DWORD dwTlsIndex) {
setLastError(ERROR_INVALID_PARAMETER);
return nullptr;
}
void *result = wibo::tls::getValue(dwTlsIndex);
GUEST_PTR result = wibo::tls::getValue(dwTlsIndex);
setLastError(ERROR_SUCCESS);
return result;
return reinterpret_cast<LPVOID>(result);
}
BOOL WINAPI TlsSetValue(DWORD dwTlsIndex, LPVOID lpTlsValue) {
@@ -407,7 +408,7 @@ BOOL WINAPI TlsSetValue(DWORD dwTlsIndex, LPVOID lpTlsValue) {
setLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (!wibo::tls::setValue(dwTlsIndex, lpTlsValue)) {
if (!wibo::tls::setValue(dwTlsIndex, toGuestPtr(lpTlsValue))) {
setLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
@@ -463,7 +464,7 @@ HANDLE WINAPI CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwSt
if ((dwCreationFlags & ~SUPPORTED_FLAGS) != 0) {
DEBUG_LOG("CreateThread: unsupported creation flags 0x%x\n", dwCreationFlags);
setLastError(ERROR_NOT_SUPPORTED);
return nullptr;
return NO_HANDLE;
}
Pin<ThreadObject> obj = make_pin<ThreadObject>(0); // tid set during pthread_create
@@ -554,7 +555,7 @@ int WINAPI GetThreadPriority(HANDLE hThread) {
DWORD WINAPI GetPriorityClass(HANDLE hProcess) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("GetPriorityClass(%p)\n", hProcess);
DEBUG_LOG("STUB: GetPriorityClass(%p)\n", hProcess);
(void)hProcess;
return NORMAL_PRIORITY_CLASS;
}

View File

@@ -15,9 +15,9 @@ using LPPROCESS_INFORMATION = PROCESS_INFORMATION *;
struct STARTUPINFOA {
DWORD cb;
LPSTR lpReserved;
LPSTR lpDesktop;
LPSTR lpTitle;
GUEST_PTR lpReserved;
GUEST_PTR lpDesktop;
GUEST_PTR lpTitle;
DWORD dwX;
DWORD dwY;
DWORD dwXSize;
@@ -28,7 +28,7 @@ struct STARTUPINFOA {
DWORD dwFlags;
WORD wShowWindow;
WORD cbReserved2;
LPBYTE lpReserved2;
GUEST_PTR lpReserved2;
HANDLE hStdInput;
HANDLE hStdOutput;
HANDLE hStdError;
@@ -38,9 +38,9 @@ using LPSTARTUPINFOA = STARTUPINFOA *;
struct STARTUPINFOW {
DWORD cb;
LPWSTR lpReserved;
LPWSTR lpDesktop;
LPWSTR lpTitle;
GUEST_PTR lpReserved;
GUEST_PTR lpDesktop;
GUEST_PTR lpTitle;
DWORD dwX;
DWORD dwY;
DWORD dwXSize;
@@ -51,7 +51,7 @@ struct STARTUPINFOW {
DWORD dwFlags;
WORD wShowWindow;
WORD cbReserved2;
LPBYTE lpReserved2;
GUEST_PTR lpReserved2;
HANDLE hStdInput;
HANDLE hStdOutput;
HANDLE hStdError;

View File

@@ -4,8 +4,10 @@
#include "context.h"
#include "errors.h"
#include "handles.h"
#include "heap.h"
#include "internal.h"
#include "strutil.h"
#include "types.h"
#include <algorithm>
#include <chrono>
@@ -158,7 +160,7 @@ HANDLE WINAPI CreateMutexW(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitia
if (!mu) {
// Name exists but isn't a mutex
setLastError(ERROR_INVALID_HANDLE);
return nullptr;
return NO_HANDLE;
}
HANDLE h = wibo::handles().alloc(std::move(mu), grantedAccess, handleFlags);
setLastError(created ? ERROR_SUCCESS : ERROR_ALREADY_EXISTS);
@@ -222,7 +224,7 @@ HANDLE WINAPI CreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManual
if (!ev) {
// Name exists but isn't an event
setLastError(ERROR_INVALID_HANDLE);
return nullptr;
return NO_HANDLE;
}
HANDLE h = wibo::handles().alloc(std::move(ev), grantedAccess, handleFlags);
DEBUG_LOG("-> %p (created=%d)\n", h, created ? 1 : 0);
@@ -260,7 +262,7 @@ HANDLE WINAPI CreateSemaphoreW(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG
if (!sem) {
// Name exists but isn't an event
setLastError(ERROR_INVALID_HANDLE);
return nullptr;
return NO_HANDLE;
}
HANDLE h = wibo::handles().alloc(std::move(sem), granted, hflags);
setLastError(created ? ERROR_SUCCESS : ERROR_ALREADY_EXISTS);
@@ -545,38 +547,37 @@ DWORD WINAPI WaitForMultipleObjects(DWORD nCount, const HANDLE *lpHandles, BOOL
void WINAPI InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection) {
HOST_CONTEXT_GUARD();
VERBOSE_LOG("STUB: InitializeCriticalSection(%p)\n", lpCriticalSection);
if (!lpCriticalSection) {
return;
}
std::memset(lpCriticalSection, 0, sizeof(*lpCriticalSection));
VERBOSE_LOG("InitializeCriticalSection(%p)\n", lpCriticalSection);
InitializeCriticalSectionEx(lpCriticalSection, 0, 0);
}
BOOL WINAPI InitializeCriticalSectionEx(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount, DWORD Flags) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("STUB: InitializeCriticalSectionEx(%p, %u, 0x%x)\n", lpCriticalSection, dwSpinCount, Flags);
DEBUG_LOG("InitializeCriticalSectionEx(%p, %u, 0x%x)\n", lpCriticalSection, dwSpinCount, Flags);
if (!lpCriticalSection) {
setLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (Flags & ~CRITICAL_SECTION_NO_DEBUG_INFO) {
setLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
std::memset(lpCriticalSection, 0, sizeof(*lpCriticalSection));
if (Flags & RTL_CRITICAL_SECTION_FLAG_NO_DEBUG_INFO) {
lpCriticalSection->DebugInfo = static_cast<GUEST_PTR>(-1);
} else {
auto *debugInfo = reinterpret_cast<RTL_CRITICAL_SECTION_DEBUG *>(
wibo::heap::guestCalloc(1, sizeof(RTL_CRITICAL_SECTION_DEBUG)));
debugInfo->CriticalSection = toGuestPtr(lpCriticalSection);
debugInfo->ProcessLocksList.Blink = toGuestPtr(&debugInfo->ProcessLocksList);
debugInfo->ProcessLocksList.Flink = toGuestPtr(&debugInfo->ProcessLocksList);
lpCriticalSection->DebugInfo = toGuestPtr(debugInfo);
}
lpCriticalSection->LockCount = -1;
lpCriticalSection->SpinCount = dwSpinCount;
return TRUE;
}
BOOL WINAPI InitializeCriticalSectionAndSpinCount(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("STUB: InitializeCriticalSectionAndSpinCount(%p, %u)\n", lpCriticalSection, dwSpinCount);
if (!lpCriticalSection) {
setLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
std::memset(lpCriticalSection, 0, sizeof(*lpCriticalSection));
lpCriticalSection->SpinCount = dwSpinCount;
DEBUG_LOG("InitializeCriticalSectionAndSpinCount(%p, %u)\n", lpCriticalSection, dwSpinCount);
InitializeCriticalSectionEx(lpCriticalSection, dwSpinCount, 0);
return TRUE;
}
@@ -598,7 +599,7 @@ void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection) {
(void)lpCriticalSection;
}
BOOL WINAPI InitOnceBeginInitialize(LPINIT_ONCE lpInitOnce, DWORD dwFlags, PBOOL fPending, LPVOID *lpContext) {
BOOL WINAPI InitOnceBeginInitialize(LPINIT_ONCE lpInitOnce, DWORD dwFlags, PBOOL fPending, GUEST_PTR *lpContext) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("STUB: InitOnceBeginInitialize(%p, %u, %p, %p)\n", lpInitOnce, dwFlags, fPending, lpContext);
if (!lpInitOnce) {
@@ -613,7 +614,7 @@ BOOL WINAPI InitOnceBeginInitialize(LPINIT_ONCE lpInitOnce, DWORD dwFlags, PBOOL
*fPending = TRUE;
}
if (lpContext) {
*lpContext = nullptr;
*lpContext = GUEST_NULL;
}
return TRUE;
}

View File

@@ -15,14 +15,20 @@ constexpr DWORD INIT_ONCE_ASYNC = 0x00000002UL;
constexpr DWORD INIT_ONCE_INIT_FAILED = 0x00000004UL;
constexpr DWORD INIT_ONCE_CTX_RESERVED_BITS = 2;
constexpr DWORD CRITICAL_SECTION_NO_DEBUG_INFO = 0x01000000UL;
constexpr DWORD RTL_CRITICAL_SECTION_FLAG_NO_DEBUG_INFO = 0x01000000UL;
constexpr DWORD RTL_CRITICAL_SECTION_FLAG_DYNAMIC_SPIN = 0x02000000UL;
constexpr DWORD RTL_CRITICAL_SECTION_FLAG_STATIC_INIT = 0x04000000UL;
constexpr DWORD RTL_CRITICAL_SECTION_FLAG_RESOURCE_TYPE = 0x08000000UL;
constexpr DWORD RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO = 0x10000000UL;
constexpr DWORD RTL_CRITICAL_SECTION_ALL_FLAG_BITS = 0xff000000UL;
constexpr DWORD RTL_CRITICAL_SECTION_FLAG_RESERVED = 0xe0000000UL;
struct RTL_CRITICAL_SECTION;
struct RTL_CRITICAL_SECTION_DEBUG {
WORD Type;
WORD CreatorBackTraceIndex;
RTL_CRITICAL_SECTION *CriticalSection;
GUEST_PTR CriticalSection;
LIST_ENTRY ProcessLocksList;
DWORD EntryCount;
DWORD ContentionCount;
@@ -33,7 +39,7 @@ struct RTL_CRITICAL_SECTION_DEBUG {
};
struct RTL_CRITICAL_SECTION {
RTL_CRITICAL_SECTION_DEBUG *DebugInfo;
GUEST_PTR DebugInfo;
LONG LockCount;
LONG RecursionCount;
HANDLE OwningThread;
@@ -47,7 +53,7 @@ using PCRITICAL_SECTION = RTL_CRITICAL_SECTION *;
using PRTL_CRITICAL_SECTION_DEBUG = RTL_CRITICAL_SECTION_DEBUG *;
union RTL_RUN_ONCE {
PVOID Ptr;
GUEST_PTR Ptr;
};
using PRTL_RUN_ONCE = RTL_RUN_ONCE *;
@@ -55,17 +61,17 @@ using INIT_ONCE = RTL_RUN_ONCE;
using PINIT_ONCE = INIT_ONCE *;
using LPINIT_ONCE = INIT_ONCE *;
constexpr INIT_ONCE INIT_ONCE_STATIC_INIT{nullptr};
constexpr INIT_ONCE INIT_ONCE_STATIC_INIT{GUEST_NULL};
union RTL_SRWLOCK {
PVOID Ptr;
GUEST_PTR Ptr;
};
using SRWLOCK = RTL_SRWLOCK;
using PSRWLOCK = SRWLOCK *;
using PRTL_SRWLOCK = SRWLOCK *;
constexpr SRWLOCK SRWLOCK_INIT{nullptr};
constexpr SRWLOCK SRWLOCK_INIT{GUEST_NULL};
namespace kernel32 {
@@ -92,7 +98,7 @@ BOOL WINAPI InitializeCriticalSectionAndSpinCount(LPCRITICAL_SECTION lpCriticalS
void WINAPI DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
BOOL WINAPI InitOnceBeginInitialize(LPINIT_ONCE lpInitOnce, DWORD dwFlags, PBOOL fPending, LPVOID *lpContext);
BOOL WINAPI InitOnceBeginInitialize(LPINIT_ONCE lpInitOnce, DWORD dwFlags, PBOOL fPending, GUEST_PTR *lpContext);
BOOL WINAPI InitOnceComplete(LPINIT_ONCE lpInitOnce, DWORD dwFlags, LPVOID lpContext);
void WINAPI AcquireSRWLockShared(PSRWLOCK SRWLock);
void WINAPI ReleaseSRWLockShared(PSRWLOCK SRWLock);

View File

@@ -4,6 +4,7 @@
#include "context.h"
#include "errors.h"
#include "internal.h"
#include "ntdll.h"
#include "timeutil.h"
#include <cstring>
@@ -52,12 +53,12 @@ void WINAPI GetSystemInfo(LPSYSTEM_INFO lpSystemInfo) {
}
lpSystemInfo->dwPageSize = static_cast<DWORD>(pageSize);
lpSystemInfo->lpMinimumApplicationAddress = reinterpret_cast<LPVOID>(0x00010000);
if (sizeof(void *) == 4) {
lpSystemInfo->lpMaximumApplicationAddress = reinterpret_cast<LPVOID>(0x7FFEFFFF);
} else {
lpSystemInfo->lpMaximumApplicationAddress = reinterpret_cast<LPVOID>(0x00007FFFFFFEFFFFull);
}
lpSystemInfo->lpMinimumApplicationAddress = toGuestPtr(reinterpret_cast<void *>(0x00010000));
#ifdef _WIN64
lpSystemInfo->lpMaximumApplicationAddress = toGuestPtr(reinterpret_cast<void *>(0x00007FFFFFFEFFFFull));
#else
lpSystemInfo->lpMaximumApplicationAddress = toGuestPtr(reinterpret_cast<void *>(0x7FFEFFFF));
#endif
unsigned int cpuCount = 1;
long reported = sysconf(_SC_NPROCESSORS_ONLN);
@@ -198,11 +199,62 @@ BOOL WINAPI GetVersionExA(LPOSVERSIONINFOA lpVersionInformation) {
setLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
std::memset(lpVersionInformation, 0, lpVersionInformation->dwOSVersionInfoSize);
lpVersionInformation->dwMajorVersion = kMajorVersion;
lpVersionInformation->dwMinorVersion = kMinorVersion;
lpVersionInformation->dwBuildNumber = kBuildNumber;
lpVersionInformation->dwPlatformId = 2;
DWORD size = lpVersionInformation->dwOSVersionInfoSize;
if (size < sizeof(OSVERSIONINFOA)) {
setLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
DWORD requestSize = (size >= sizeof(OSVERSIONINFOEXA)) ? sizeof(OSVERSIONINFOEXW) : sizeof(OSVERSIONINFOW);
OSVERSIONINFOEXW wideInfo{};
wideInfo.dwOSVersionInfoSize = requestSize;
NTSTATUS status = ntdll::RtlGetVersion(reinterpret_cast<PRTL_OSVERSIONINFOW>(&wideInfo));
if (status != STATUS_SUCCESS) {
setLastError(wibo::winErrorFromNtStatus(status));
return FALSE;
}
std::memset(lpVersionInformation, 0, size);
lpVersionInformation->dwOSVersionInfoSize = size;
lpVersionInformation->dwMajorVersion = wideInfo.dwMajorVersion;
lpVersionInformation->dwMinorVersion = wideInfo.dwMinorVersion;
lpVersionInformation->dwBuildNumber = wideInfo.dwBuildNumber;
lpVersionInformation->dwPlatformId = wideInfo.dwPlatformId;
if (size >= sizeof(OSVERSIONINFOEXA)) {
auto extended = reinterpret_cast<OSVERSIONINFOEXA *>(lpVersionInformation);
extended->wServicePackMajor = wideInfo.wServicePackMajor;
extended->wServicePackMinor = wideInfo.wServicePackMinor;
extended->wSuiteMask = wideInfo.wSuiteMask;
extended->wProductType = wideInfo.wProductType;
extended->wReserved = wideInfo.wReserved;
}
return TRUE;
}
BOOL WINAPI GetVersionExW(LPOSVERSIONINFOW lpVersionInformation) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("GetVersionExW(%p)\n", lpVersionInformation);
if (!lpVersionInformation) {
setLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
DWORD size = lpVersionInformation->dwOSVersionInfoSize;
if (size < sizeof(OSVERSIONINFOW)) {
setLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
NTSTATUS status = ntdll::RtlGetVersion(reinterpret_cast<PRTL_OSVERSIONINFOW>(lpVersionInformation));
if (status != STATUS_SUCCESS) {
setLastError(wibo::winErrorFromNtStatus(status));
return FALSE;
}
lpVersionInformation->dwOSVersionInfoSize = size;
return TRUE;
}

View File

@@ -12,8 +12,8 @@ struct SYSTEM_INFO {
};
};
DWORD dwPageSize;
LPVOID lpMinimumApplicationAddress;
LPVOID lpMaximumApplicationAddress;
GUEST_PTR lpMinimumApplicationAddress;
GUEST_PTR lpMaximumApplicationAddress;
DWORD_PTR dwActiveProcessorMask;
DWORD dwNumberOfProcessors;
DWORD dwProcessorType;
@@ -35,6 +35,37 @@ struct OSVERSIONINFOA {
using LPOSVERSIONINFOA = OSVERSIONINFOA *;
struct OSVERSIONINFOW {
DWORD dwOSVersionInfoSize;
DWORD dwMajorVersion;
DWORD dwMinorVersion;
DWORD dwBuildNumber;
DWORD dwPlatformId;
WCHAR szCSDVersion[128];
};
using LPOSVERSIONINFOW = OSVERSIONINFOW *;
struct OSVERSIONINFOEXA : OSVERSIONINFOA {
WORD wServicePackMajor;
WORD wServicePackMinor;
WORD wSuiteMask;
BYTE wProductType;
BYTE wReserved;
};
using LPOSVERSIONINFOEXA = OSVERSIONINFOEXA *;
struct OSVERSIONINFOEXW : OSVERSIONINFOW {
WORD wServicePackMajor;
WORD wServicePackMinor;
WORD wSuiteMask;
BYTE wProductType;
BYTE wReserved;
};
using LPOSVERSIONINFOEXW = OSVERSIONINFOEXW *;
namespace kernel32 {
void WINAPI GetSystemInfo(LPSYSTEM_INFO lpSystemInfo);
@@ -44,5 +75,6 @@ void WINAPI GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime);
DWORD WINAPI GetTickCount();
DWORD WINAPI GetVersion();
BOOL WINAPI GetVersionExA(LPOSVERSIONINFOA lpVersionInformation);
BOOL WINAPI GetVersionExW(LPOSVERSIONINFOW lpVersionInformation);
} // namespace kernel32

View File

@@ -235,7 +235,7 @@ bool doFree(void *mem) {
DEBUG_LOG("doFree(%p) -> virtualFree\n", mem);
MEMORY_BASIC_INFORMATION info;
auto result = wibo::heap::virtualQuery(mem, &info);
if (result != wibo::heap::VmStatus::Success || info.BaseAddress != mem) {
if (result != wibo::heap::VmStatus::Success || fromGuestPtr(info.BaseAddress) != mem) {
return false;
}
wibo::heap::virtualFree(mem, info.RegionSize, MEM_RELEASE);
@@ -697,7 +697,7 @@ BOOL WINAPI FindActCtxSectionStringW(DWORD dwFlags, const GUID *lpExtensionGuid,
ReturnedData->ulDataFormatVersion = 1;
ReturnedData->ulFlags = ACTCTX_SECTION_KEYED_DATA_FLAG_FOUND_IN_ACTCTX;
if (dwFlags & FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX) {
ReturnedData->hActCtx = reinterpret_cast<HANDLE>(&g_builtinActCtx);
ReturnedData->hActCtx = toGuestPtr(&g_builtinActCtx);
}
if (!matchedEntry) {
@@ -705,9 +705,9 @@ BOOL WINAPI FindActCtxSectionStringW(DWORD dwFlags, const GUID *lpExtensionGuid,
return FALSE;
}
ReturnedData->lpData = const_cast<ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION *>(&matchedEntry->dllData);
ReturnedData->lpData = toGuestPtr(&matchedEntry->dllData);
ReturnedData->ulLength = matchedEntry->dllData.Size;
ReturnedData->lpSectionBase = const_cast<ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION *>(&matchedEntry->dllData);
ReturnedData->lpSectionBase = toGuestPtr(&matchedEntry->dllData);
ReturnedData->ulSectionTotalLength = matchedEntry->dllData.Size;
ReturnedData->ulAssemblyRosterIndex = 1;
ReturnedData->AssemblyMetadata = {};
@@ -805,20 +805,20 @@ HGLOBAL WINAPI GlobalAlloc(UINT uFlags, SIZE_T dwBytes) {
if (uFlags & GMEM_MOVEABLE) {
// not implemented rn
assert(0);
return nullptr;
return NO_HANDLE;
}
bool zero = (uFlags & GMEM_ZEROINIT) != 0;
void *ret = doAlloc(static_cast<UINT>(dwBytes), zero);
DEBUG_LOG("-> %p\n", ret);
return ret;
return toGuestPtr(ret);
}
HGLOBAL WINAPI GlobalFree(HGLOBAL hMem) {
HOST_CONTEXT_GUARD();
VERBOSE_LOG("GlobalFree(%p)\n", hMem);
if (doFree(hMem)) {
if (doFree(reinterpret_cast<void *>(hMem))) {
DEBUG_LOG("-> success\n");
return nullptr;
return NO_HANDLE;
} else {
DEBUG_LOG("-> failure\n");
return hMem;
@@ -830,12 +830,12 @@ HGLOBAL WINAPI GlobalReAlloc(HGLOBAL hMem, SIZE_T dwBytes, UINT uFlags) {
VERBOSE_LOG("GlobalReAlloc(%p, %zu, %x)\n", hMem, static_cast<size_t>(dwBytes), uFlags);
if (uFlags & GMEM_MODIFY) {
assert(0);
return nullptr;
return NO_HANDLE;
}
bool zero = (uFlags & GMEM_ZEROINIT) != 0;
void *ret = doRealloc(hMem, static_cast<UINT>(dwBytes), zero);
void *ret = doRealloc(reinterpret_cast<void *>(hMem), static_cast<UINT>(dwBytes), zero);
DEBUG_LOG("-> %p\n", ret);
return ret;
return toGuestPtr(ret);
}
UINT WINAPI GlobalFlags(HGLOBAL hMem) {
@@ -855,20 +855,24 @@ HLOCAL WINAPI LocalAlloc(UINT uFlags, SIZE_T uBytes) {
void *result = doAlloc(static_cast<UINT>(uBytes), zero);
if (!result) {
setLastError(ERROR_NOT_SUPPORTED);
return nullptr;
return NO_HANDLE;
}
// Legacy Windows applications (pre-NX and DEP) may expect executable memory from LocalAlloc.
tryMarkExecutable(result);
DEBUG_LOG(" -> %p\n", result);
return result;
return toGuestPtr(result);
}
HLOCAL WINAPI LocalFree(HLOCAL hMem) {
HOST_CONTEXT_GUARD();
VERBOSE_LOG("LocalFree(%p)\n", hMem);
// Windows returns NULL on success.
std::free(hMem);
return nullptr;
if (doFree(reinterpret_cast<void *>(hMem))) {
DEBUG_LOG("-> success\n");
return NO_HANDLE;
} else {
DEBUG_LOG("-> failure\n");
return hMem;
}
}
HLOCAL WINAPI LocalReAlloc(HLOCAL hMem, SIZE_T uBytes, UINT uFlags) {
@@ -878,27 +882,27 @@ HLOCAL WINAPI LocalReAlloc(HLOCAL hMem, SIZE_T uBytes, UINT uFlags) {
if ((uFlags & LMEM_MOVEABLE) != 0) {
DEBUG_LOG(" ignoring LMEM_MOVEABLE\n");
}
void *result = doRealloc(hMem, static_cast<UINT>(uBytes), zero);
void *result = doRealloc(reinterpret_cast<void *>(hMem), static_cast<UINT>(uBytes), zero);
if (!result && uBytes != 0) {
setLastError(ERROR_NOT_SUPPORTED);
return nullptr;
return NO_HANDLE;
}
// Legacy Windows applications (pre-NX and DEP) may expect executable memory from LocalReAlloc.
tryMarkExecutable(result);
DEBUG_LOG(" -> %p\n", result);
return result;
return toGuestPtr(result);
}
HLOCAL WINAPI LocalHandle(LPCVOID pMem) {
HOST_CONTEXT_GUARD();
VERBOSE_LOG("LocalHandle(%p)\n", pMem);
return const_cast<LPVOID>(pMem);
return toGuestPtr(pMem);
}
LPVOID WINAPI LocalLock(HLOCAL hMem) {
HOST_CONTEXT_GUARD();
VERBOSE_LOG("LocalLock(%p)\n", hMem);
return hMem;
return reinterpret_cast<void *>(hMem);
}
BOOL WINAPI LocalUnlock(HLOCAL hMem) {
@@ -911,7 +915,7 @@ BOOL WINAPI LocalUnlock(HLOCAL hMem) {
SIZE_T WINAPI LocalSize(HLOCAL hMem) {
HOST_CONTEXT_GUARD();
VERBOSE_LOG("LocalSize(%p)\n", hMem);
return hMem ? mi_usable_size(hMem) : 0;
return hMem ? mi_usable_size(reinterpret_cast<void *>(hMem)) : 0;
}
UINT WINAPI LocalFlags(HLOCAL hMem) {

View File

@@ -5,21 +5,21 @@
struct GUID;
struct ACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA {
PVOID lpInformation;
PVOID lpSectionBase;
GUEST_PTR lpInformation;
GUEST_PTR lpSectionBase;
ULONG ulSectionLength;
PVOID lpSectionGlobalData;
GUEST_PTR lpSectionGlobalData;
ULONG ulSectionGlobalDataLength;
};
struct ACTCTX_SECTION_KEYED_DATA {
ULONG cbSize;
ULONG ulDataFormatVersion;
PVOID lpData;
GUEST_PTR lpData;
ULONG ulLength;
PVOID lpSectionGlobalData;
GUEST_PTR lpSectionGlobalData;
ULONG ulSectionGlobalDataLength;
PVOID lpSectionBase;
GUEST_PTR lpSectionBase;
ULONG ulSectionTotalLength;
HANDLE hActCtx;
ULONG ulAssemblyRosterIndex;
@@ -68,8 +68,8 @@ ATOM WINAPI AddAtomW(LPCWSTR lpString);
UINT WINAPI GetAtomNameA(ATOM nAtom, LPSTR lpBuffer, int nSize);
UINT WINAPI GetAtomNameW(ATOM nAtom, LPWSTR lpBuffer, int nSize);
UINT WINAPI SetHandleCount(UINT uNumber);
DWORD WINAPI FormatMessageA(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPSTR lpBuffer,
DWORD nSize, va_list *Arguments);
// DWORD WINAPI FormatMessageA(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPSTR lpBuffer,
// DWORD nSize, va_list *Arguments);
PVOID WINAPI EncodePointer(PVOID Ptr);
PVOID WINAPI DecodePointer(PVOID Ptr);
BOOL WINAPI SetDllDirectoryA(LPCSTR lpPathName);

View File

@@ -19,6 +19,9 @@ constexpr DWORD kNormIgnoreCase = 0x00000001;
constexpr DWORD LCID_INSTALLED = 0x00000001;
constexpr DWORD LCID_SUPPORTED = 0x00000002;
constexpr DWORD LCID_ALTERNATE_SORTS = 0x00000004;
constexpr LCID kEnUsLcid = 0x0409;
constexpr LCID kInvariantLcid = 0x007f;
constexpr DWORD LOCALE_ALLOW_NEUTRAL_NAMES = 0x08000000;
int compareStrings(const std::string &a, const std::string &b, DWORD dwCmpFlags) {
for (size_t i = 0;; ++i) {
@@ -102,6 +105,50 @@ LANGID WINAPI GetUserDefaultUILanguage() {
return 0;
}
int WINAPI GetUserDefaultLocaleName(LPWSTR lpLocaleName, int cchLocaleName) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("GetUserDefaultLocaleName(%p, %d)\n", lpLocaleName, cchLocaleName);
if (!lpLocaleName || cchLocaleName < 0) {
setLastError(ERROR_INVALID_PARAMETER);
return 0;
}
constexpr char16_t localeName[] = u"en-US";
constexpr int requiredChars = static_cast<int>(sizeof(localeName) / sizeof(char16_t));
if (cchLocaleName < requiredChars) {
setLastError(ERROR_INSUFFICIENT_BUFFER);
return 0;
}
std::memcpy(lpLocaleName, localeName, sizeof(localeName));
return requiredChars;
}
LCID WINAPI LocaleNameToLCID(LPCWSTR lpName, DWORD dwFlags) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("LocaleNameToLCID(%p, 0x%x)\n", lpName, dwFlags);
if (dwFlags & ~LOCALE_ALLOW_NEUTRAL_NAMES) {
setLastError(ERROR_INVALID_PARAMETER);
return 0;
}
if (!lpName) {
return kEnUsLcid;
}
std::string localeName = wideStringToString(lpName);
if (localeName.empty()) {
return kInvariantLcid;
}
std::string normalized = stringToLower(localeName);
if (normalized == "en-us" || normalized == "en_us" || normalized == "!x-sys-default-locale") {
return kEnUsLcid;
}
setLastError(ERROR_INVALID_PARAMETER);
return 0;
}
BOOL WINAPI GetCPInfo(UINT CodePage, LPCPINFO lpCPInfo) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("GetCPInfo(%u, %p)\n", CodePage, lpCPInfo);

View File

@@ -19,6 +19,8 @@ namespace kernel32 {
UINT WINAPI GetACP();
LANGID WINAPI GetSystemDefaultLangID();
LANGID WINAPI GetUserDefaultUILanguage();
int WINAPI GetUserDefaultLocaleName(LPWSTR lpLocaleName, int cchLocaleName);
LCID WINAPI LocaleNameToLCID(LPCWSTR lpName, DWORD dwFlags);
BOOL WINAPI GetCPInfo(UINT CodePage, LPCPINFO lpCPInfo);
int WINAPI CompareStringA(LCID Locale, DWORD dwCmpFlags, LPCSTR lpString1, int cchCount1, LPCSTR lpString2,
int cchCount2);

View File

@@ -5,14 +5,15 @@
#include "errors.h"
#include "handles.h"
#include "internal.h"
#include "types.h"
namespace kernel32 {
BOOL WINAPI Wow64DisableWow64FsRedirection(PVOID *OldValue) {
BOOL WINAPI Wow64DisableWow64FsRedirection(GUEST_PTR *OldValue) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("STUB: Wow64DisableWow64FsRedirection(%p)\n", OldValue);
if (OldValue) {
*OldValue = nullptr;
*OldValue = GUEST_NULL;
}
return TRUE;
}

View File

@@ -4,7 +4,7 @@
namespace kernel32 {
BOOL WINAPI Wow64DisableWow64FsRedirection(PVOID *OldValue);
BOOL WINAPI Wow64DisableWow64FsRedirection(GUEST_PTR *OldValue);
BOOL WINAPI Wow64RevertWow64FsRedirection(PVOID OldValue);
BOOL WINAPI IsWow64Process(HANDLE hProcess, PBOOL Wow64Process);

View File

@@ -9,6 +9,7 @@
#include "msvcrt_trampolines.h"
#include "processes.h"
#include "strutil.h"
#include "types.h"
#include <algorithm>
#include <array>
@@ -97,10 +98,10 @@ int closeGuestFile(_FILE *file) {
namespace msvcrt {
int _commode;
int _fmode;
char** __initenv;
uint16_t** __winitenv;
uint16_t* _wpgmptr = nullptr;
char* _pgmptr = nullptr;
GUEST_PTR __initenv = GUEST_NULL;
GUEST_PTR __winitenv = GUEST_NULL;
GUEST_PTR _wpgmptr = GUEST_NULL;
GUEST_PTR _pgmptr = GUEST_NULL;
int __mb_cur_max = 1;
_FILE _iob[_IOB_ENTRIES] = {_FILE{STDOUT_FILENO}, _FILE{STDERR_FILENO}, _FILE{STDIN_FILENO}};
@@ -381,11 +382,11 @@ namespace msvcrt {
return mbCodePageSetting;
}
int* CDECL __p___mb_cur_max() {
GUEST_PTR CDECL __p___mb_cur_max() {
HOST_CONTEXT_GUARD();
ensureMbctypeInitialized();
DEBUG_LOG("__p___mb_cur_max() -> %u\n", __mb_cur_max);
return &__mb_cur_max;
return toGuestPtr(&__mb_cur_max);
}
int CDECL _setmbcp(int codepage) {
@@ -414,19 +415,19 @@ namespace msvcrt {
return 0;
}
unsigned char *CDECL __p__mbctype() {
GUEST_PTR CDECL __p__mbctype() {
HOST_CONTEXT_GUARD();
ensureMbctypeInitialized();
DEBUG_LOG("__p__mbctype() -> %p\n", mbctypeTable.data());
return mbctypeTable.data();
return toGuestPtr(mbctypeTable.data());
}
unsigned short **CDECL __p__pctype() {
GUEST_PTR CDECL __p__pctype() {
HOST_CONTEXT_GUARD();
DEBUG_LOG("__p__pctype()\n");
static unsigned short *pointer = nullptr;
pointer = pctypeTable().data() + 1;
return &pointer;
return toGuestPtr(&pointer);
}
int CDECL _isctype(int ch, int mask) {
@@ -502,11 +503,11 @@ namespace msvcrt {
template <typename CharT>
struct StringListStorage {
std::vector<std::unique_ptr<CharT[]>> strings;
std::unique_ptr<CharT*[]> pointers;
std::vector<wibo::heap::guest_ptr<CharT[]>> strings;
wibo::heap::guest_ptr<GUEST_PTR[]> pointers;
template <typename Converter>
CharT **assign(char **source, Converter convert) {
GUEST_PTR *assign(char **source, Converter convert) {
if (!source) {
strings.clear();
pointers.reset();
@@ -520,18 +521,18 @@ namespace msvcrt {
strings.clear();
strings.reserve(count);
pointers = std::make_unique<CharT *[]>(count + 1);
pointers = wibo::heap::make_guest_unique<GUEST_PTR[]>(count + 1);
for (SIZE_T i = 0; i < count; ++i) {
auto data = convert(source[i]);
auto buffer = std::make_unique<CharT[]>(data.size());
auto buffer = wibo::heap::make_guest_unique<CharT[]>(data.size());
std::copy(data.begin(), data.end(), buffer.get());
CharT *raw = buffer.get();
strings.emplace_back(std::move(buffer));
pointers[i] = raw;
pointers[i] = toGuestPtr(raw);
}
pointers[count] = nullptr;
pointers[count] = GUEST_NULL;
return pointers.get();
}
};
@@ -554,7 +555,7 @@ namespace msvcrt {
template <typename CharT, typename Converter>
// NOLINTNEXTLINE(readability-non-const-parameter)
int getMainArgsCommon(int *argcOut, CharT ***argvOut, CharT ***envOut, Converter convert) {
int getMainArgsCommon(int *argcOut, GUEST_PTR *argvOut, GUEST_PTR *envOut, Converter convert) {
if (argcOut) {
*argcOut = wibo::argc;
}
@@ -563,18 +564,18 @@ namespace msvcrt {
static StringListStorage<CharT> envStorage;
if (argvOut) {
*argvOut = argvStorage.assign(wibo::argv, convert);
*argvOut = toGuestPtr(argvStorage.assign(wibo::argv, convert));
}
CharT **envData = envStorage.assign(environ, convert);
GUEST_PTR *envData = envStorage.assign(environ, convert);
if (envOut) {
*envOut = envData;
*envOut = toGuestPtr(envData);
}
if constexpr (std::is_same_v<CharT, uint16_t>) {
__winitenv = envData;
__winitenv = toGuestPtr(envData);
} else if constexpr (std::is_same_v<CharT, char>) {
__initenv = envData;
__initenv = toGuestPtr(envData);
}
return 0;
@@ -633,7 +634,7 @@ namespace msvcrt {
if (!__winitenv) {
getMainArgsCommon<uint16_t>(nullptr, nullptr, nullptr, copyWideString);
}
return __winitenv;
return reinterpret_cast<uint16_t**>(__winitenv);
}
} // namespace
@@ -644,42 +645,44 @@ namespace msvcrt {
(void)at;
}
int* CDECL __p__fmode() {
GUEST_PTR CDECL __p__fmode() {
HOST_CONTEXT_GUARD();
DEBUG_LOG("__p__fmode() -> %p\n", &_fmode);
return &_fmode;
return toGuestPtr(&_fmode);
}
int* CDECL __p__commode() {
GUEST_PTR CDECL __p__commode() {
HOST_CONTEXT_GUARD();
DEBUG_LOG("__p__commode() -> %p\n", &_commode);
return &_commode;
return toGuestPtr(&_commode);
}
void CDECL _initterm(const _PVFV *ppfn, const _PVFV* end) {
void CDECL _initterm(GUEST_PTR *ppfn, GUEST_PTR *end) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("_initterm(%p, %p)\n", ppfn, end);
for (; ppfn < end; ppfn++) {
_PVFV func = *ppfn;
if (func) {
DEBUG_LOG("_initterm: calling %p\n", func);
call__PVFV(func);
}
do {
if (GUEST_PTR pfn = *++ppfn) {
DEBUG_LOG("-> calling %p\n", pfn);
auto fn = reinterpret_cast<_PVFV>(fromGuestPtr(pfn));
call__PVFV(fn);
}
} while (ppfn < end);
}
int CDECL _initterm_e(const _PIFV *ppfn, const _PIFV *end) {
int CDECL _initterm_e(GUEST_PTR *ppfn, GUEST_PTR *end) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("_initterm_e(%p, %p)\n", ppfn, end);
for (; ppfn < end; ppfn++) {
_PIFV func = *ppfn;
if (func) {
int err = call__PIFV(func);
DEBUG_LOG("_initterm_e: calling %p -> %d\n", func, err);
if (err != 0)
do {
if (GUEST_PTR pfn = *++ppfn) {
DEBUG_LOG("-> calling %p\n", pfn);
auto fn = reinterpret_cast<_PIFV>(fromGuestPtr(pfn));
int err = call__PIFV(fn);
if (err)
return err;
}
}
} while (ppfn < end);
return 0;
}
@@ -720,7 +723,7 @@ namespace msvcrt {
}
// NOLINTNEXTLINE(readability-non-const-parameter)
int CDECL __wgetmainargs(int *wargc, uint16_t ***wargv, uint16_t ***wenv, int doWildcard, int *startInfo) {
int CDECL __wgetmainargs(int *wargc, GUEST_PTR *wargv, GUEST_PTR *wenv, int doWildcard, int *startInfo) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("__wgetmainargs(doWildcard=%d)\n", doWildcard);
(void)startInfo;
@@ -733,7 +736,7 @@ namespace msvcrt {
}
// NOLINTNEXTLINE(readability-non-const-parameter)
int CDECL __getmainargs(int *argc, char ***argv, char ***env, int doWildcard, int *startInfo) {
int CDECL __getmainargs(int *argc, GUEST_PTR *argv, GUEST_PTR *env, int doWildcard, int *startInfo) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("__getmainargs(doWildcard=%d)\n", doWildcard);
(void)startInfo;
@@ -749,10 +752,10 @@ namespace msvcrt {
return std::getenv(varname);
}
char*** CDECL __p___initenv() {
GUEST_PTR CDECL __p___initenv() {
HOST_CONTEXT_GUARD();
DEBUG_LOG("__p___initenv() -> %p\n", &__initenv);
return &__initenv;
return toGuestPtr(&__initenv);
}
char* CDECL strcat(char *dest, const char *src) {
@@ -881,7 +884,7 @@ namespace msvcrt {
}
if (!prev) {
long diff = static_cast<long>(current - start);
LONG diff = static_cast<LONG>(current - start);
DEBUG_LOG("_mbsdec fallback start=%p current=%p diff=%ld first-bytes=%02x %02x %02x %02x\n",
start, current, diff,
start ? start[0] : 0, start ? start[1] : 0,
@@ -1166,11 +1169,11 @@ namespace msvcrt {
return ::close(fd);
}
long CDECL _lseek(int fd, long offset, int origin) {
LONG CDECL _lseek(int fd, LONG offset, int origin) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("_lseek(%d, %ld, %d)\n", fd, offset, origin);
off_t result = ::lseek(fd, static_cast<off_t>(offset), origin);
return static_cast<long>(result);
return static_cast<LONG>(result);
}
int CDECL _unlink(const char *path) {
@@ -1199,7 +1202,7 @@ namespace msvcrt {
return ::utime(hostPath.c_str(), &native);
}
int CDECL _chsize(int fd, long size) {
int CDECL _chsize(int fd, LONG size) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("_chsize(%d, %ld)\n", fd, size);
return ::ftruncate(fd, static_cast<off_t>(size));
@@ -1238,13 +1241,13 @@ namespace msvcrt {
return std::strtok(str, delim);
}
long CDECL _adj_fdiv_r(long value) {
LONG CDECL _adj_fdiv_r(LONG value) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("STUB: _adj_fdiv_r(%ld)\n", value);
return value;
}
void CDECL _adjust_fdiv(long n) {
void CDECL _adjust_fdiv(LONG n) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("STUB: _adjust_fdiv(%ld)\n", n);
(void)n;
@@ -1261,14 +1264,14 @@ namespace msvcrt {
if (gettimeofday(&tv, nullptr) != 0) {
return -1;
}
timeptr->time = tv.tv_sec;
timeptr->time = static_cast<LONG>(tv.tv_sec);
timeptr->millitm = static_cast<unsigned short>(tv.tv_usec / 1000);
timeptr->timezone = 0;
timeptr->dstflag = 0;
return 0;
}
unsigned long CDECL _ultoa(unsigned long value, char *str, int radix) {
ULONG CDECL _ultoa(ULONG value, char *str, int radix) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("_ultoa(%lu, %p, %d)\n", value, str, radix);
if (!str || radix < 2 || radix > 36) {
@@ -1282,15 +1285,15 @@ namespace msvcrt {
*--cursor = '0';
}
while (value > 0) {
unsigned long digit = value % static_cast<unsigned long>(radix);
value /= static_cast<unsigned long>(radix);
ULONG digit = value % static_cast<ULONG>(radix);
value /= static_cast<ULONG>(radix);
*--cursor = static_cast<char>(digit < 10 ? '0' + digit : 'A' + (digit - 10));
}
std::strcpy(str, cursor);
return static_cast<unsigned long>(std::strlen(str));
return static_cast<ULONG>(std::strlen(str));
}
char* CDECL _ltoa(long value, char *str, int radix) {
char* CDECL _ltoa(LONG value, char *str, int radix) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("_ltoa(%ld, %p, %d)\n", value, str, radix);
if (!str || radix < 2 || radix > 36) {
@@ -1298,9 +1301,9 @@ namespace msvcrt {
return nullptr;
}
bool negative = value < 0;
unsigned long absValue = negative ? static_cast<unsigned long>(-value) : static_cast<unsigned long>(value);
ULONG absValue = negative ? static_cast<ULONG>(-value) : static_cast<ULONG>(value);
char buffer[65];
unsigned long length = _ultoa(absValue, buffer, radix);
ULONG length = _ultoa(absValue, buffer, radix);
std::string result;
if (negative) {
result.push_back('-');
@@ -1437,7 +1440,7 @@ namespace msvcrt {
TIME_T CDECL time(TIME_T *t) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("time(%p)\n", t);
TIME_T result = std::time(nullptr);
TIME_T result = static_cast<TIME_T>(std::time(nullptr));
if (t) {
*t = result;
}
@@ -1468,11 +1471,11 @@ namespace msvcrt {
return result;
}
int CDECL _wdupenv_s(uint16_t **buffer, SIZE_T *numberOfElements, const uint16_t *varname){
int CDECL _wdupenv_s(GUEST_PTR *buffer, SIZE_T *numberOfElements, const uint16_t *varname){
HOST_CONTEXT_GUARD();
DEBUG_LOG("_wdupenv_s(%p, %p, %s)\n", buffer, numberOfElements, wideStringToString(varname).c_str());
if (buffer) {
*buffer = nullptr;
*buffer = GUEST_NULL;
}
if (numberOfElements) {
*numberOfElements = 0;
@@ -1504,7 +1507,7 @@ namespace msvcrt {
wstrncpy(copy, match->value, value_len);
copy[value_len] = 0;
*buffer = copy;
*buffer = toGuestPtr(copy);
if (numberOfElements) {
*numberOfElements = value_len + 1;
}
@@ -1678,10 +1681,18 @@ namespace msvcrt {
return copy;
}
unsigned long CDECL strtoul(const char *str, char **endptr, int base) {
ULONG CDECL strtoul(const char *str, GUEST_PTR *endptr, int base) {
HOST_CONTEXT_GUARD();
VERBOSE_LOG("strtoul(%s, %p, %d)\n", str, endptr, base);
return ::strtoul(str, endptr, base);
int ret;
if (endptr != nullptr) {
char *endptr_host = reinterpret_cast<char*>(fromGuestPtr(*endptr));
ret = ::strtoul(str, &endptr_host, base);
*endptr = toGuestPtr(endptr_host);
} else {
ret = ::strtoul(str, nullptr, base);
}
return ret;
}
void* CDECL malloc(SIZE_T size){
@@ -1728,7 +1739,7 @@ namespace msvcrt {
lockTable()[static_cast<SIZE_T>(locknum)].unlock();
}
_onexit_t CDECL __dllonexit(_onexit_t func, _onexit_t **pbegin, _onexit_t **pend) {
_onexit_t CDECL __dllonexit(_onexit_t func, GUEST_PTR *pbegin, GUEST_PTR *pend) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("__dllonexit(%p, %p, %p)\n", func, pbegin, pend);
if (!pbegin || !pend) {
@@ -1740,13 +1751,13 @@ namespace msvcrt {
return nullptr;
}
_onexit_t *table = static_cast<_onexit_t *>(wibo::heap::guestRealloc(pbegin, len * sizeof(_onexit_t)));
GUEST_PTR *table = static_cast<GUEST_PTR *>(wibo::heap::guestRealloc(pbegin, len * sizeof(GUEST_PTR)));
if (!table) {
return nullptr;
}
*pbegin = table;
*pend = table + len;
table[len - 1] = func;
*pbegin = toGuestPtr(table);
*pend = toGuestPtr(table + len);
table[len - 1] = toGuestPtr(reinterpret_cast<void *>(func));
return func;
}
@@ -1827,14 +1838,14 @@ namespace msvcrt {
return isatty(fd);
}
int CDECL fseek(_FILE *stream, long offset, int origin) {
int CDECL fseek(_FILE *stream, LONG offset, int origin) {
HOST_CONTEXT_GUARD();
VERBOSE_LOG("fseek(%p, %ld, %d)\n", stream, offset, origin);
FILE* host = mapToHostFile(stream);
return std::fseek(host, offset, origin);
}
long CDECL ftell(_FILE *stream) {
LONG CDECL ftell(_FILE *stream) {
HOST_CONTEXT_GUARD();
VERBOSE_LOG("ftell(%p)\n", stream);
FILE* host = mapToHostFile(stream);
@@ -1895,7 +1906,7 @@ namespace msvcrt {
return std::fgetwc(host);
}
int CDECL _wfopen_s(_FILE **stream, const uint16_t *filename, const uint16_t *mode) {
int CDECL _wfopen_s(GUEST_PTR *stream, const uint16_t *filename, const uint16_t *mode) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("_wfopen_s(%p, %s, %s)\n", stream, wideStringToString(filename).c_str(),
wideStringToString(mode).c_str());
@@ -1907,10 +1918,10 @@ namespace msvcrt {
std::string narrowMode = wideStringToString(mode);
FILE *handle = std::fopen(narrowName.c_str(), narrowMode.c_str());
if (!handle) {
*stream = nullptr;
*stream = GUEST_NULL;
return errno ? errno : EINVAL;
}
*stream = mapToGuestFile(handle);
*stream = toGuestPtr(mapToGuestFile(handle));
return 0;
}
@@ -2061,13 +2072,13 @@ namespace msvcrt {
return 0;
}
unsigned long CDECL wcsspn(const uint16_t *str1, const uint16_t *str2) {
ULONG CDECL wcsspn(const uint16_t *str1, const uint16_t *str2) {
HOST_CONTEXT_GUARD();
VERBOSE_LOG("wcsspn(%p, %p)\n", str1, str2);
if (!str1 || !str2) {
return 0;
}
unsigned long count = 0;
ULONG count = 0;
for (const uint16_t *p = str1; *p; ++p) {
bool match = false;
for (const uint16_t *q = str2; *q; ++q) {
@@ -2084,7 +2095,7 @@ namespace msvcrt {
return count;
}
long CDECL _wtol(const uint16_t *str) {
LONG CDECL _wtol(const uint16_t *str) {
HOST_CONTEXT_GUARD();
VERBOSE_LOG("_wtol(%p)\n", str);
return wstrtol(str, nullptr, 10);
@@ -2341,13 +2352,13 @@ namespace msvcrt {
return 0;
}
long CDECL _XcptFilter(unsigned long code, void *) {
LONG CDECL _XcptFilter(ULONG code, void *) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("STUB: _XcptFilter(%lu)\n", code);
return 0;
}
int CDECL _get_wpgmptr(uint16_t **pValue) {
int CDECL _get_wpgmptr(GUEST_PTR *pValue) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("_get_wpgmptr(%p)\n", pValue);
if (!pValue) {
@@ -2358,22 +2369,25 @@ namespace msvcrt {
return 0;
}
const auto wStr = stringToWideString(wibo::guestExecutablePath.c_str());
delete[] _wpgmptr;
// TODO
// const auto wStr = stringToWideString(wibo::guestExecutablePath.c_str());
// delete[] _wpgmptr;
_wpgmptr = new uint16_t[wStr.size() + 1];
std::copy(wStr.begin(), wStr.end(), _wpgmptr);
_wpgmptr[wStr.size()] = 0;
// _wpgmptr = new uint16_t[wStr.size() + 1];
// std::copy(wStr.begin(), wStr.end(), _wpgmptr);
// _wpgmptr[wStr.size()] = 0;
*pValue = _wpgmptr;
// *pValue = _wpgmptr;
return 0;
}
char** CDECL __p__pgmptr() {
GUEST_PTR CDECL __p__pgmptr() {
HOST_CONTEXT_GUARD();
DEBUG_LOG("__p__pgmptr()\n");
_pgmptr = const_cast<char *>(wibo::guestExecutablePath.c_str());
return &_pgmptr;
// TODO
// _pgmptr = const_cast<char *>(wibo::guestExecutablePath.c_str());
// return &_pgmptr;
return GUEST_NULL;
}
int CDECL _wsplitpath_s(const uint16_t * path, uint16_t * drive, SIZE_T driveNumberOfElements, uint16_t *dir, SIZE_T dirNumberOfElements,
@@ -2564,7 +2578,7 @@ namespace msvcrt {
return wstrtol(str, nullptr, 10);
}
int CDECL _ltoa_s(long value, char *buffer, SIZE_T sizeInChars, int radix) {
int CDECL _ltoa_s(LONG value, char *buffer, SIZE_T sizeInChars, int radix) {
HOST_CONTEXT_GUARD();
VERBOSE_LOG("_ltoa_s(%ld, %p, %zu, %d)\n", value, buffer, sizeInChars, radix);
if (!buffer || sizeInChars == 0) {
@@ -2782,10 +2796,18 @@ namespace msvcrt {
return wstrrchr(str, c);
}
unsigned long CDECL wcstoul(const uint16_t *strSource, uint16_t **endptr, int base){
ULONG CDECL wcstoul(const uint16_t *strSource, GUEST_PTR *endptr, int base){
HOST_CONTEXT_GUARD();
VERBOSE_LOG("wcstoul(%p, %p, %d)\n", strSource, endptr, base);
return wstrtoul(strSource, endptr, base);
int ret;
if (endptr != nullptr) {
uint16_t *endptr_host = reinterpret_cast<uint16_t*>(fromGuestPtr(*endptr));
ret = ::wstrtoul(strSource, &endptr_host, base);
*endptr = toGuestPtr(endptr_host);
} else {
ret = ::wstrtoul(strSource, nullptr, base);
}
return ret;
}
_FILE* CDECL _wfsopen(const uint16_t* filename, const uint16_t* mode, int shflag){
@@ -2842,7 +2864,7 @@ namespace msvcrt {
return &errno;
}
LONG_PTR CDECL _wspawnvp(int mode, const uint16_t* cmdname, const uint16_t* const * argv) {
LONG_PTR CDECL _wspawnvp(int mode, const uint16_t* cmdname, GUEST_PTR *argv) {
HOST_CONTEXT_GUARD();
if (!cmdname || !argv) {
errno = EINVAL;
@@ -2853,8 +2875,9 @@ namespace msvcrt {
DEBUG_LOG("_wspawnvp(%d, %s)\n", mode, command.c_str());
std::vector<std::string> argStorage;
for (const uint16_t *const *cursor = argv; *cursor; ++cursor) {
argStorage.emplace_back(wideStringToString(*cursor));
for (GUEST_PTR *cursor = argv; *cursor; ++cursor) {
const WCHAR *arg = reinterpret_cast<const WCHAR*>(fromGuestPtr(*cursor));
argStorage.emplace_back(wideStringToString(arg));
}
auto resolved = wibo::resolveExecutable(command, false);
@@ -2891,7 +2914,7 @@ namespace msvcrt {
return static_cast<intptr_t>(po->pid);
}
LONG_PTR CDECL _spawnvp(int mode, const char *cmdname, const char * const *argv) {
LONG_PTR CDECL _spawnvp(int mode, const char *cmdname, GUEST_PTR *argv) {
HOST_CONTEXT_GUARD();
if (!cmdname || !argv) {
errno = EINVAL;
@@ -2902,8 +2925,9 @@ namespace msvcrt {
DEBUG_LOG("_spawnvp(%d, %s)\n", mode, command.c_str());
std::vector<std::string> argStorage;
for (const char * const *cursor = argv; *cursor; ++cursor) {
argStorage.emplace_back(*cursor);
for (GUEST_PTR *cursor = argv; *cursor; ++cursor) {
const char *arg = reinterpret_cast<const char*>(fromGuestPtr(*cursor));
argStorage.emplace_back(arg);
}
auto resolved = wibo::resolveExecutable(command, false);

View File

@@ -12,8 +12,8 @@ typedef void(_CC_CDECL *signal_handler)(int);
typedef int(_CC_CDECL *sort_compare)(const void *, const void *);
struct _utimbuf {
long actime;
long modtime;
LONG actime;
LONG modtime;
};
struct _timeb {
@@ -29,10 +29,10 @@ namespace msvcrt {
extern int _commode;
extern int _fmode;
extern char **__initenv;
extern WCHAR **__winitenv;
extern WCHAR *_wpgmptr;
extern char *_pgmptr;
extern GUEST_PTR __initenv;
extern GUEST_PTR __winitenv;
extern GUEST_PTR _wpgmptr;
extern GUEST_PTR _pgmptr;
extern int __mb_cur_max;
extern _FILE _iob[_IOB_ENTRIES];
@@ -42,23 +42,23 @@ void CDECL setbuf(_FILE *stream, char *buffer);
void CDECL _splitpath(const char *path, char *drive, char *dir, char *fname, char *ext);
int CDECL _fileno(_FILE *stream);
int CDECL _getmbcp();
int *CDECL __p___mb_cur_max();
GUEST_PTR CDECL __p___mb_cur_max();
int CDECL _setmbcp(int codepage);
unsigned char *CDECL __p__mbctype();
unsigned short **CDECL __p__pctype();
GUEST_PTR CDECL __p__mbctype();
GUEST_PTR CDECL __p__pctype();
int CDECL _isctype(int ch, int mask);
void CDECL __set_app_type(int at);
int *CDECL __p__fmode();
int *CDECL __p__commode();
void CDECL _initterm(const _PVFV *ppfn, const _PVFV *end);
int CDECL _initterm_e(const _PIFV *ppfn, const _PIFV *end);
GUEST_PTR CDECL __p__fmode();
GUEST_PTR CDECL __p__commode();
void CDECL _initterm(GUEST_PTR *ppfn, GUEST_PTR *end);
int CDECL _initterm_e(GUEST_PTR *ppfn, GUEST_PTR *end);
unsigned int CDECL _controlfp(unsigned int newControl, unsigned int mask);
int CDECL _controlfp_s(unsigned int *currentControl, unsigned int newControl, unsigned int mask);
_onexit_t CDECL _onexit(_onexit_t func);
int CDECL __wgetmainargs(int *wargc, WCHAR ***wargv, WCHAR ***wenv, int doWildcard, int *startInfo);
int CDECL __getmainargs(int *argc, char ***argv, char ***env, int doWildcard, int *startInfo);
int CDECL __wgetmainargs(int *wargc, GUEST_PTR *wargv, GUEST_PTR *wenv, int doWildcard, int *startInfo);
int CDECL __getmainargs(int *argc, GUEST_PTR *argv, GUEST_PTR *env, int doWildcard, int *startInfo);
char *CDECL getenv(const char *varname);
char ***CDECL __p___initenv();
GUEST_PTR CDECL __p___initenv();
char *CDECL strcat(char *dest, const char *src);
char *CDECL strcpy(char *dest, const char *src);
int CDECL _access(const char *path, int mode);
@@ -84,31 +84,33 @@ int CDECL _ismbcdigit(unsigned int ch);
int CDECL _stricmp(const char *lhs, const char *rhs);
int CDECL _strnicmp(const char *lhs, const char *rhs, SIZE_T count);
int CDECL _memicmp(const void *lhs, const void *rhs, SIZE_T count);
#ifndef __x86_64__ // TODO
int CDECL_NO_CONV _vsnprintf(char *buffer, SIZE_T count, const char *format, va_list args);
int CDECL_NO_CONV _snprintf(char *buffer, SIZE_T count, const char *format, ...);
int CDECL_NO_CONV sprintf(char *buffer, const char *format, ...);
int CDECL_NO_CONV printf(const char *format, ...);
int CDECL_NO_CONV sscanf(const char *buffer, const char *format, ...);
#endif
char *CDECL fgets(char *str, int count, _FILE *stream);
SIZE_T CDECL fread(void *buffer, SIZE_T size, SIZE_T count, _FILE *stream);
_FILE *CDECL _fsopen(const char *filename, const char *mode, int shflag);
int CDECL _sopen(const char *path, int oflag, int shflag, int pmode);
int CDECL _read(int fd, void *buffer, unsigned int count);
int CDECL _close(int fd);
long CDECL _lseek(int fd, long offset, int origin);
LONG CDECL _lseek(int fd, LONG offset, int origin);
int CDECL _unlink(const char *path);
int CDECL _utime(const char *path, const _utimbuf *times);
int CDECL _chsize(int fd, long size);
int CDECL _chsize(int fd, LONG size);
char *CDECL strncpy(char *dest, const char *src, SIZE_T count);
char *CDECL strpbrk(const char *str, const char *accept);
char *CDECL strstr(const char *haystack, const char *needle);
char *CDECL strrchr(const char *str, int ch);
char *CDECL strtok(char *str, const char *delim);
long CDECL _adj_fdiv_r(long value);
void CDECL _adjust_fdiv(long n);
LONG CDECL _adj_fdiv_r(LONG value);
void CDECL _adjust_fdiv(LONG n);
int CDECL _ftime(struct _timeb *timeptr);
unsigned long CDECL _ultoa(unsigned long value, char *str, int radix);
char *CDECL _ltoa(long value, char *str, int radix);
ULONG CDECL _ultoa(ULONG value, char *str, int radix);
char *CDECL _ltoa(LONG value, char *str, int radix);
char *CDECL _makepath(char *path, const char *drive, const char *dir, const char *fname, const char *ext);
char *CDECL _fullpath(char *absPath, const char *relPath, SIZE_T maxLength);
int CDECL _putenv(const char *envString);
@@ -119,7 +121,7 @@ TIME_T CDECL time(TIME_T *t);
char *CDECL __unDName(char *outputString, const char *mangledName, int maxStringLength, void *(*allocFunc)(SIZE_T),
void (*freeFunc)(void *), unsigned short);
char *CDECL setlocale(int category, const char *locale);
int CDECL _wdupenv_s(WCHAR **buffer, SIZE_T *numberOfElements, const WCHAR *varname);
int CDECL _wdupenv_s(GUEST_PTR *buffer, SIZE_T *numberOfElements, const WCHAR *varname);
int CDECL _wgetenv_s(SIZE_T *pReturnValue, WCHAR *buffer, SIZE_T numberOfElements, const WCHAR *varname);
SIZE_T CDECL strlen(const char *str);
int CDECL strcmp(const char *lhs, const char *rhs);
@@ -129,38 +131,40 @@ int CDECL strcpy_s(char *dest, SIZE_T dest_size, const char *src);
int CDECL strcat_s(char *dest, SIZE_T numberOfElements, const char *src);
int CDECL strncpy_s(char *dest, SIZE_T dest_size, const char *src, SIZE_T count);
char *CDECL _strdup(const char *strSource);
unsigned long CDECL strtoul(const char *str, char **endptr, int base);
ULONG CDECL strtoul(const char *str, GUEST_PTR *endptr, int base);
void *CDECL malloc(SIZE_T size);
void *CDECL calloc(SIZE_T count, SIZE_T size);
void *CDECL realloc(void *ptr, SIZE_T size);
void *CDECL _malloc_crt(SIZE_T size);
void CDECL _lock(int locknum);
void CDECL _unlock(int locknum);
_onexit_t CDECL __dllonexit(_onexit_t func, _onexit_t **pbegin, _onexit_t **pend);
_onexit_t CDECL __dllonexit(_onexit_t func, GUEST_PTR *pbegin, GUEST_PTR *pend);
void CDECL free(void *ptr);
void *CDECL memcpy(void *dest, const void *src, SIZE_T count);
void *CDECL memmove(void *dest, const void *src, SIZE_T count);
int CDECL memcmp(const void *lhs, const void *rhs, SIZE_T count);
void CDECL qsort(void *base, SIZE_T num, SIZE_T size, sort_compare compare);
int CDECL fflush(_FILE *stream);
#ifndef __x86_64__ // TODO
int CDECL_NO_CONV vfwprintf(_FILE *stream, const WCHAR *format, va_list args);
#endif
_FILE *CDECL fopen(const char *filename, const char *mode);
int CDECL _dup2(int fd1, int fd2);
int CDECL _isatty(int fd);
int CDECL fseek(_FILE *stream, long offset, int origin);
long CDECL ftell(_FILE *stream);
int CDECL fseek(_FILE *stream, LONG offset, int origin);
LONG CDECL ftell(_FILE *stream);
int CDECL feof(_FILE *stream);
int CDECL fputws(const WCHAR *str, _FILE *stream);
int CDECL _cputws(const WCHAR *string);
WCHAR *CDECL fgetws(WCHAR *buffer, int size, _FILE *stream);
WINT_T CDECL fgetwc(_FILE *stream);
int CDECL _wfopen_s(_FILE **stream, const WCHAR *filename, const WCHAR *mode);
int CDECL _wfopen_s(GUEST_PTR *stream, const WCHAR *filename, const WCHAR *mode);
int CDECL _wcsicmp(const WCHAR *lhs, const WCHAR *rhs);
int CDECL _wmakepath_s(WCHAR *path, SIZE_T sizeInWords, const WCHAR *drive, const WCHAR *dir, const WCHAR *fname,
const WCHAR *ext);
int CDECL _wputenv_s(const WCHAR *varname, const WCHAR *value);
unsigned long CDECL wcsspn(const WCHAR *str1, const WCHAR *str2);
long CDECL _wtol(const WCHAR *str);
ULONG CDECL wcsspn(const WCHAR *str1, const WCHAR *str2);
LONG CDECL _wtol(const WCHAR *str);
int CDECL _wcsupr_s(WCHAR *str, SIZE_T size);
int CDECL _wcslwr_s(WCHAR *str, SIZE_T size);
WINT_T CDECL towlower(WINT_T ch);
@@ -172,8 +176,10 @@ int CDECL _crt_debugger_hook(int value);
int CDECL _configthreadlocale(int mode);
void CDECL __setusermatherr(void *handler);
void CDECL _cexit();
#ifndef __x86_64__ // TODO
int CDECL_NO_CONV vfprintf(_FILE *stream, const char *format, va_list args);
int CDECL_NO_CONV fprintf(_FILE *stream, const char *format, ...);
#endif
int CDECL fputc(int ch, _FILE *stream);
SIZE_T CDECL fwrite(const void *buffer, SIZE_T size, SIZE_T count, _FILE *stream);
char *CDECL strerror(int errnum);
@@ -188,9 +194,9 @@ void CDECL _invoke_watson(const WCHAR *, const WCHAR *, const WCHAR *, UINT, UIN
void CDECL terminateShim();
int CDECL _purecall();
int CDECL _except_handler4_common(void *, void *, void *, void *);
long CDECL _XcptFilter(unsigned long code, void *);
int CDECL _get_wpgmptr(WCHAR **pValue);
char **CDECL __p__pgmptr();
LONG CDECL _XcptFilter(ULONG code, void *);
int CDECL _get_wpgmptr(GUEST_PTR *pValue);
GUEST_PTR CDECL __p__pgmptr();
int CDECL _wsplitpath_s(const WCHAR *path, WCHAR *drive, SIZE_T driveNumberOfElements, WCHAR *dir,
SIZE_T dirNumberOfElements, WCHAR *fname, SIZE_T nameNumberOfElements, WCHAR *ext,
SIZE_T extNumberOfElements);
@@ -202,28 +208,32 @@ int CDECL wcsncpy_s(WCHAR *strDest, SIZE_T numberOfElements, const WCHAR *strSou
int CDECL wcsncat_s(WCHAR *strDest, SIZE_T numberOfElements, const WCHAR *strSource, SIZE_T count);
int CDECL _itow_s(int value, WCHAR *buffer, SIZE_T size, int radix);
int CDECL _wtoi(const WCHAR *str);
int CDECL _ltoa_s(long value, char *buffer, SIZE_T sizeInChars, int radix);
int CDECL _ltoa_s(LONG value, char *buffer, SIZE_T sizeInChars, int radix);
int CDECL wcscpy_s(WCHAR *dest, SIZE_T dest_size, const WCHAR *src);
#ifndef __x86_64__ // TODO
int CDECL_NO_CONV swprintf_s(WCHAR *buffer, SIZE_T sizeOfBuffer, const WCHAR *format, ...);
int CDECL_NO_CONV swscanf_s(const WCHAR *buffer, const WCHAR *format, ...);
#endif
int *CDECL _get_osfhandle(int fd);
int CDECL _write(int fd, const void *buffer, unsigned int count);
void CDECL exit(int status);
int CDECL wcsncmp(const WCHAR *string1, const WCHAR *string2, SIZE_T count);
#ifndef __x86_64__ // TODO
int CDECL_NO_CONV _vswprintf_c_l(WCHAR *buffer, SIZE_T size, const WCHAR *format, ...);
#endif
const WCHAR *CDECL wcsstr(const WCHAR *dest, const WCHAR *src);
int CDECL iswspace(WINT_T w);
int CDECL iswdigit(WINT_T w);
const WCHAR *CDECL wcschr(const WCHAR *str, WCHAR c);
const WCHAR *CDECL wcsrchr(const WCHAR *str, WCHAR c);
unsigned long CDECL wcstoul(const WCHAR *strSource, WCHAR **endptr, int base);
ULONG CDECL wcstoul(const WCHAR *strSource, GUEST_PTR *endptr, int base);
_FILE *CDECL _wfsopen(const WCHAR *filename, const WCHAR *mode, int shflag);
int CDECL puts(const char *str);
int CDECL fclose(_FILE *stream);
int CDECL _flushall();
int *CDECL _errno();
LONG_PTR CDECL _wspawnvp(int mode, const WCHAR *cmdname, const WCHAR *const *argv);
LONG_PTR CDECL _spawnvp(int mode, const char *cmdname, const char *const *argv);
LONG_PTR CDECL _wspawnvp(int mode, const WCHAR *cmdname, GUEST_PTR *argv);
LONG_PTR CDECL _spawnvp(int mode, const char *cmdname, GUEST_PTR *argv);
int CDECL _wunlink(const WCHAR *filename);
WCHAR *CDECL _wfullpath(WCHAR *absPath, const WCHAR *relPath, SIZE_T maxLength);

View File

@@ -24,7 +24,7 @@ namespace {
struct PROCESS_BASIC_INFORMATION {
NTSTATUS ExitStatus;
PEB *PebBaseAddress;
GUEST_PTR PebBaseAddress;
ULONG_PTR AffinityMask;
LONG BasePriority;
ULONG_PTR UniqueProcessId;
@@ -94,8 +94,8 @@ std::string windowsImagePathFor(const ProcessHandleDetails &details) {
} // namespace
namespace kernel32 {
BOOL WIN_FUNC SetEvent(HANDLE hEvent);
BOOL WIN_FUNC ResetEvent(HANDLE hEvent);
BOOL WINAPI SetEvent(HANDLE hEvent);
BOOL WINAPI ResetEvent(HANDLE hEvent);
} // namespace kernel32
namespace ntdll {
@@ -262,7 +262,7 @@ NTSTATUS WINAPI NtWriteFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE Apc
return status;
}
NTSTATUS WINAPI NtAllocateVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress, ULONG_PTR ZeroBits,
NTSTATUS WINAPI NtAllocateVirtualMemory(HANDLE ProcessHandle, GUEST_PTR *BaseAddress, ULONG_PTR ZeroBits,
PSIZE_T RegionSize, ULONG AllocationType, ULONG Protect) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("NtAllocateVirtualMemory(%p, %p, %lu, %p, %lu, %lu) ", ProcessHandle, BaseAddress, ZeroBits, RegionSize,
@@ -276,20 +276,24 @@ NTSTATUS WINAPI NtAllocateVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress
return STATUS_INVALID_PARAMETER;
}
wibo::heap::VmStatus vmStatus =
wibo::heap::virtualAlloc(reinterpret_cast<void **>(BaseAddress), reinterpret_cast<std::size_t *>(RegionSize),
static_cast<DWORD>(AllocationType), static_cast<DWORD>(Protect));
void *baseAddress = fromGuestPtr(*BaseAddress);
size_t regionSize = static_cast<size_t>(*RegionSize);
wibo::heap::VmStatus vmStatus = wibo::heap::virtualAlloc(
&baseAddress, &regionSize, static_cast<DWORD>(AllocationType), static_cast<DWORD>(Protect));
if (vmStatus != wibo::heap::VmStatus::Success) {
NTSTATUS status = wibo::heap::ntStatusFromVmStatus(vmStatus);
DEBUG_LOG("-> 0x%x\n", status);
return status;
}
*BaseAddress = toGuestPtr(baseAddress);
*RegionSize = static_cast<SIZE_T>(regionSize);
DEBUG_LOG("-> 0x%x\n", STATUS_SUCCESS);
return STATUS_SUCCESS;
}
NTSTATUS WINAPI NtProtectVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress, PSIZE_T NumberOfBytesToProtect,
NTSTATUS WINAPI NtProtectVirtualMemory(HANDLE ProcessHandle, GUEST_PTR *BaseAddress, PSIZE_T NumberOfBytesToProtect,
ULONG NewAccessProtection, PULONG OldAccessProtection) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("NtProtectVirtualMemory(%p, %p, %p, %lu, %p) ", ProcessHandle, BaseAddress, NumberOfBytesToProtect,
@@ -303,8 +307,8 @@ NTSTATUS WINAPI NtProtectVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress,
return STATUS_INVALID_PARAMETER;
}
void *base = *BaseAddress;
std::size_t length = static_cast<std::size_t>(*NumberOfBytesToProtect);
void *base = fromGuestPtr(*BaseAddress);
size_t length = static_cast<size_t>(*NumberOfBytesToProtect);
wibo::heap::VmStatus vmStatus =
wibo::heap::virtualProtect(base, length, static_cast<DWORD>(NewAccessProtection), OldAccessProtection);
if (vmStatus != wibo::heap::VmStatus::Success) {
@@ -351,7 +355,7 @@ NTSTATUS WINAPI NtQueryInformationProcess(HANDLE ProcessHandle, PROCESSINFOCLASS
PVOID ProcessInformation, ULONG ProcessInformationLength,
PULONG ReturnLength) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("NtQueryInformationProcess(%p, %u, %p, %u, %p) ", ProcessHandle, ProcessInformationClass,
DEBUG_LOG("NtQueryInformationProcess(%d, %u, %p, %u, %p) ", ProcessHandle, ProcessInformationClass,
ProcessInformation, ProcessInformationLength, ReturnLength);
if (!ProcessInformation) {
DEBUG_LOG("-> 0x%x\n", STATUS_INVALID_PARAMETER);
@@ -378,7 +382,7 @@ NTSTATUS WINAPI NtQueryInformationProcess(HANDLE ProcessHandle, PROCESSINFOCLASS
auto *info = reinterpret_cast<PROCESS_BASIC_INFORMATION *>(ProcessInformation);
std::memset(info, 0, sizeof(*info));
info->ExitStatus = static_cast<NTSTATUS>(details.exitCode);
info->PebBaseAddress = details.peb;
info->PebBaseAddress = toGuestPtr(details.peb);
DWORD_PTR processMask = 0;
DWORD_PTR systemMask = 0;
if (kernel32::GetProcessAffinityMask(ProcessHandle, &processMask, &systemMask)) {
@@ -440,7 +444,7 @@ NTSTATUS WINAPI NtQueryInformationProcess(HANDLE ProcessHandle, PROCESSINFOCLASS
size_t characterCount = widePath.empty() ? 0 : widePath.size() - 1;
unicode->Length = static_cast<unsigned short>(characterCount * sizeof(uint16_t));
unicode->MaximumLength = static_cast<unsigned short>(widePath.size() * sizeof(uint16_t));
unicode->Buffer = buffer;
unicode->Buffer = toGuestPtr(buffer);
DEBUG_LOG("-> 0x%x\n", STATUS_SUCCESS);
return STATUS_SUCCESS;
}

View File

@@ -7,7 +7,7 @@ using PIO_APC_ROUTINE = PVOID;
typedef struct _IO_STATUS_BLOCK {
union {
NTSTATUS Status;
PVOID Pointer;
GUEST_PTR Pointer;
};
ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
@@ -38,12 +38,13 @@ NTSTATUS WINAPI NtReadFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcR
NTSTATUS WINAPI NtWriteFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext,
PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length, PLARGE_INTEGER ByteOffset,
PULONG Key);
NTSTATUS WINAPI NtAllocateVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress, ULONG_PTR ZeroBits, PSIZE_T RegionSize,
ULONG AllocationType, ULONG Protect);
NTSTATUS WINAPI NtProtectVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress, PSIZE_T NumberOfBytesToProtect,
NTSTATUS WINAPI NtAllocateVirtualMemory(HANDLE ProcessHandle, GUEST_PTR *BaseAddress, ULONG_PTR ZeroBits,
PSIZE_T RegionSize, ULONG AllocationType, ULONG Protect);
NTSTATUS WINAPI NtProtectVirtualMemory(HANDLE ProcessHandle, GUEST_PTR *BaseAddress, PSIZE_T NumberOfBytesToProtect,
ULONG NewAccessProtection, PULONG OldAccessProtection);
NTSTATUS WINAPI RtlGetVersion(PRTL_OSVERSIONINFOW lpVersionInformation);
NTSTATUS WINAPI NtQueryInformationProcess(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass,
PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength);
PVOID ProcessInformation, ULONG ProcessInformationLength,
PULONG ReturnLength);
} // namespace ntdll

View File

@@ -119,7 +119,7 @@ HRESULT WINAPI CoInitialize(LPVOID pvReserved) {
}
HRESULT WINAPI CoCreateInstance(const GUID *rclsid, LPVOID pUnkOuter, DWORD dwClsContext, const GUID *riid,
LPVOID *ppv) {
GUEST_PTR *ppv) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("STUB: CoCreateInstance(0x%x, %p, %d, 0x%x, %p)\n", rclsid->Data1, pUnkOuter, dwClsContext, riid->Data1,
*ppv);

View File

@@ -5,7 +5,7 @@
namespace ole32 {
HRESULT WINAPI CoInitialize(LPVOID pvReserved);
HRESULT WINAPI CoCreateInstance(const GUID *rclsid, LPVOID pUnkOuter, DWORD dwClsContext, const GUID *riid, LPVOID *ppv);
HRESULT WINAPI CoCreateInstance(const GUID *rclsid, LPVOID pUnkOuter, DWORD dwClsContext, const GUID *riid, GUEST_PTR *ppv);
HRESULT WINAPI CLSIDFromString(LPCWSTR lpsz, GUID *pclsid);
} // namespace ole32

View File

@@ -4,8 +4,8 @@
#include "context.h"
#include "heap.h"
#include "modules.h"
#include "types.h"
#include <cstdarg>
#include <cstdlib>
#include <cstring>
#include <memory>
@@ -44,7 +44,7 @@ struct BindingHandleData {
};
std::unordered_map<RPC_WSTR, BindingComponents> g_stringBindings;
std::unordered_map<RPC_BINDING_HANDLE, std::unique_ptr<BindingHandleData>> g_bindingHandles;
std::unordered_map<RPC_BINDING_HANDLE, wibo::heap::guest_ptr<BindingHandleData>> g_bindingHandles;
std::u16string toU16(RPC_WSTR str) {
if (!str) {
@@ -112,7 +112,7 @@ BindingHandleData *getBinding(RPC_BINDING_HANDLE handle) {
namespace rpcrt4 {
RPC_STATUS WINAPI RpcStringBindingComposeW(RPC_WSTR objUuid, RPC_WSTR protSeq, RPC_WSTR networkAddr, RPC_WSTR endpoint,
RPC_WSTR options, RPC_WSTR *stringBinding) {
RPC_WSTR options, GUEST_PTR *stringBinding) {
HOST_CONTEXT_GUARD();
BindingComponents components;
components.objectUuid = toU16(objUuid);
@@ -136,18 +136,18 @@ RPC_STATUS WINAPI RpcStringBindingComposeW(RPC_WSTR objUuid, RPC_WSTR protSeq, R
buffer[length] = 0;
RPC_WSTR result = reinterpret_cast<RPC_WSTR>(buffer);
g_stringBindings[result] = components;
*stringBinding = result;
*stringBinding = toGuestPtr(result);
}
return RPC_S_OK;
}
RPC_STATUS WINAPI RpcBindingFromStringBindingW(RPC_WSTR stringBinding, RPC_BINDING_HANDLE *binding) {
RPC_STATUS WINAPI RpcBindingFromStringBindingW(RPC_WSTR stringBinding, GUEST_PTR *binding) {
HOST_CONTEXT_GUARD();
if (!binding) {
return RPC_S_INVALID_ARG;
}
*binding = nullptr;
*binding = GUEST_NULL;
if (!stringBinding) {
return RPC_S_INVALID_STRING_BINDING;
}
@@ -155,13 +155,13 @@ RPC_STATUS WINAPI RpcBindingFromStringBindingW(RPC_WSTR stringBinding, RPC_BINDI
if (it == g_stringBindings.end()) {
return RPC_S_INVALID_STRING_BINDING;
}
auto handleData = std::make_unique<BindingHandleData>();
auto handleData = wibo::heap::make_guest_unique<BindingHandleData>();
handleData->components = it->second;
handleData->bindingString = composeString(handleData->components);
handleData->serverReachable = false;
RPC_BINDING_HANDLE handle = reinterpret_cast<RPC_BINDING_HANDLE>(handleData.get());
g_bindingHandles.emplace(handle, std::move(handleData));
*binding = handle;
*binding = toGuestPtr(handle);
DEBUG_LOG("RpcBindingFromStringBindingW(handle=%p)\n", handle);
return RPC_S_OK;
}
@@ -190,12 +190,12 @@ RPC_STATUS WINAPI RpcBindingSetAuthInfoExW(RPC_BINDING_HANDLE binding, RPC_WSTR
return RPC_S_OK;
}
RPC_STATUS WINAPI RpcBindingFree(RPC_BINDING_HANDLE *binding) {
RPC_STATUS WINAPI RpcBindingFree(GUEST_PTR *binding) {
HOST_CONTEXT_GUARD();
if (!binding) {
return RPC_S_INVALID_ARG;
}
RPC_BINDING_HANDLE handle = *binding;
RPC_BINDING_HANDLE handle = reinterpret_cast<RPC_BINDING_HANDLE>(fromGuestPtr(*binding));
if (!handle) {
return RPC_S_INVALID_BINDING;
}
@@ -204,17 +204,17 @@ RPC_STATUS WINAPI RpcBindingFree(RPC_BINDING_HANDLE *binding) {
return RPC_S_INVALID_BINDING;
}
g_bindingHandles.erase(it);
*binding = nullptr;
*binding = GUEST_NULL;
DEBUG_LOG("RpcBindingFree\n");
return RPC_S_OK;
}
RPC_STATUS WINAPI RpcStringFreeW(RPC_WSTR *string) {
RPC_STATUS WINAPI RpcStringFreeW(GUEST_PTR *string) {
HOST_CONTEXT_GUARD();
if (!string) {
return RPC_S_INVALID_ARG;
}
RPC_WSTR value = *string;
RPC_WSTR value = reinterpret_cast<RPC_WSTR>(fromGuestPtr(*string));
if (!value) {
return RPC_S_OK;
}
@@ -223,7 +223,7 @@ RPC_STATUS WINAPI RpcStringFreeW(RPC_WSTR *string) {
g_stringBindings.erase(it);
}
std::free(reinterpret_cast<void *>(value));
*string = nullptr;
*string = GUEST_NULL;
return RPC_S_OK;
}

View File

@@ -15,25 +15,27 @@ struct RPC_SECURITY_QOS {
ULONG Capabilities;
ULONG IdentityTracking;
ULONG ImpersonationType;
PVOID AdditionalSecurityInfo;
GUEST_PTR AdditionalSecurityInfo;
};
union CLIENT_CALL_RETURN {
PVOID Pointer;
GUEST_PTR Pointer;
LONG_PTR Simple;
};
namespace rpcrt4 {
RPC_STATUS WINAPI RpcStringBindingComposeW(RPC_WSTR objUuid, RPC_WSTR protSeq, RPC_WSTR networkAddr, RPC_WSTR endpoint,
RPC_WSTR options, RPC_WSTR *stringBinding);
RPC_STATUS WINAPI RpcBindingFromStringBindingW(RPC_WSTR stringBinding, RPC_BINDING_HANDLE *binding);
RPC_WSTR options, GUEST_PTR *stringBinding);
RPC_STATUS WINAPI RpcBindingFromStringBindingW(RPC_WSTR stringBinding, GUEST_PTR *binding);
RPC_STATUS WINAPI RpcBindingSetAuthInfoExW(RPC_BINDING_HANDLE binding, RPC_WSTR serverPrincName, ULONG authnLevel,
ULONG authnSvc, RPC_AUTH_IDENTITY_HANDLE authIdentity, ULONG authzSvc,
RPC_SECURITY_QOS *securityQos);
RPC_STATUS WINAPI RpcBindingFree(RPC_BINDING_HANDLE *binding);
RPC_STATUS WINAPI RpcStringFreeW(RPC_WSTR *string);
RPC_STATUS WINAPI RpcBindingFree(GUEST_PTR *binding);
RPC_STATUS WINAPI RpcStringFreeW(GUEST_PTR *string);
#ifndef __x86_64__ // TODO
CLIENT_CALL_RETURN CDECL_NO_CONV NdrClientCall2(PMIDL_STUB_DESC stubDescriptor, PFORMAT_STRING format, ...);
#endif
VOID WINAPI NdrServerCall2(PRPC_MESSAGE message);
} // namespace rpcrt4

View File

@@ -12,7 +12,7 @@
namespace user32 {
constexpr uint32_t RT_STRING_ID = 6;
constexpr uintptr_t kDefaultKeyboardLayout = 0x04090409;
constexpr HKL kDefaultKeyboardLayout = 0x04090409;
constexpr int UOI_FLAGS = 1;
constexpr DWORD WSF_VISIBLE = 0x0001;
@@ -135,15 +135,14 @@ int WINAPI MessageBoxA(HWND hwnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) {
HKL WINAPI GetKeyboardLayout(DWORD idThread) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("GetKeyboardLayout(%u)\n", idThread);
DEBUG_LOG("STUB: GetKeyboardLayout(%u)\n", idThread);
(void)idThread;
return reinterpret_cast<HKL>(kDefaultKeyboardLayout);
return kDefaultKeyboardLayout;
}
HWINSTA WINAPI GetProcessWindowStation() {
DEBUG_LOG("GetProcessWindowStation()\n");
static int kWindowStationStub;
return reinterpret_cast<HWINSTA>(&kWindowStationStub);
DEBUG_LOG("STUB: GetProcessWindowStation()\n");
return NO_HANDLE;
}
BOOL WINAPI GetUserObjectInformationA(HANDLE hObj, int nIndex, PVOID pvInfo, DWORD nLength, LPDWORD lpnLengthNeeded) {
@@ -173,7 +172,7 @@ BOOL WINAPI GetUserObjectInformationA(HANDLE hObj, int nIndex, PVOID pvInfo, DWO
HWND WINAPI GetActiveWindow() {
DEBUG_LOG("GetActiveWindow()\n");
return nullptr;
return NO_HANDLE;
}
} // namespace user32

View File

@@ -8,6 +8,7 @@
#include "modules.h"
#include "resources.h"
#include "strutil.h"
#include "types.h"
#include <cstdio>
#include <cstring>
@@ -239,7 +240,7 @@ UINT WINAPI GetFileVersionInfoA(LPCSTR lptstrFilename, DWORD dwHandle, DWORD dwL
return 1;
}
static unsigned int VerQueryValueImpl(const void *pBlock, const std::string &subBlock, void **lplpBuffer,
static unsigned int VerQueryValueImpl(const void *pBlock, const std::string &subBlock, GUEST_PTR *lplpBuffer,
unsigned int *puLen) {
if (!pBlock)
return 0;
@@ -264,20 +265,20 @@ static unsigned int VerQueryValueImpl(const void *pBlock, const std::string &sub
std::string narrow = wideStringToString(reinterpret_cast<const uint16_t *>(outPtr), static_cast<int>(outLen));
std::memcpy(dest, narrow.c_str(), narrow.size() + 1);
if (lplpBuffer)
*lplpBuffer = dest;
*lplpBuffer = toGuestPtr(dest);
if (puLen)
*puLen = static_cast<unsigned int>(narrow.size());
return 1;
}
if (lplpBuffer)
*lplpBuffer = const_cast<uint8_t *>(outPtr);
*lplpBuffer = toGuestPtr(outPtr);
if (puLen)
*puLen = outLen;
return 1;
}
UINT WINAPI VerQueryValueA(LPCVOID pBlock, LPCSTR lpSubBlock, LPVOID *lplpBuffer, PUINT puLen) {
UINT WINAPI VerQueryValueA(LPCVOID pBlock, LPCSTR lpSubBlock, GUEST_PTR *lplpBuffer, PUINT puLen) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("VerQueryValueA(%p, %s, %p, %p)\n", pBlock, lpSubBlock ? lpSubBlock : "(null)", lplpBuffer, puLen);
if (!lpSubBlock)
@@ -299,7 +300,7 @@ UINT WINAPI GetFileVersionInfoW(LPCWSTR lptstrFilename, DWORD dwHandle, DWORD dw
return GetFileVersionInfoA(narrow.c_str(), dwHandle, dwLen, lpData);
}
UINT WINAPI VerQueryValueW(LPCVOID pBlock, LPCWSTR lpSubBlock, LPVOID *lplpBuffer, PUINT puLen) {
UINT WINAPI VerQueryValueW(LPCVOID pBlock, LPCWSTR lpSubBlock, GUEST_PTR *lplpBuffer, PUINT puLen) {
HOST_CONTEXT_GUARD();
if (!lpSubBlock)
return 0;

View File

@@ -6,9 +6,9 @@ namespace version {
UINT WINAPI GetFileVersionInfoSizeA(LPCSTR lptstrFilename, LPDWORD lpdwHandle);
UINT WINAPI GetFileVersionInfoA(LPCSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData);
UINT WINAPI VerQueryValueA(LPCVOID pBlock, LPCSTR lpSubBlock, LPVOID *lplpBuffer, PUINT puLen);
UINT WINAPI VerQueryValueA(LPCVOID pBlock, LPCSTR lpSubBlock, GUEST_PTR *lplpBuffer, PUINT puLen);
UINT WINAPI GetFileVersionInfoSizeW(LPCWSTR lptstrFilename, LPDWORD lpdwHandle);
UINT WINAPI GetFileVersionInfoW(LPCWSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData);
UINT WINAPI VerQueryValueW(LPCVOID pBlock, LPCWSTR lpSubBlock, LPVOID *lplpBuffer, PUINT puLen);
UINT WINAPI VerQueryValueW(LPCVOID pBlock, LPCWSTR lpSubBlock, GUEST_PTR *lplpBuffer, PUINT puLen);
} // namespace version

View File

@@ -1,11 +1,11 @@
#include "files.h"
#include "common.h"
#include "errors.h"
#include "handles.h"
#include "strutil.h"
#include <algorithm>
#include <cerrno>
#include <climits>
#include <cstddef>
#include <cstdio>
#include <mutex>
@@ -312,7 +312,7 @@ HANDLE getStdHandle(DWORD nStdHandle) {
case STD_ERROR_HANDLE:
return stderrHandle;
default:
return (void *)0xFFFFFFFF;
return INVALID_HANDLE_VALUE;
}
}

View File

@@ -1,4 +1,5 @@
#include "handles.h"
#include "types.h"
#include <atomic>
#include <cassert>
#include <cstdint>
@@ -12,7 +13,7 @@ constexpr uint32_t kCompatMaxIndex = (0xFFFFu >> kHandleAlignShift) - 1;
constexpr uint32_t kQuarantineLen = 64;
inline uint32_t indexOf(HANDLE h) noexcept {
uint32_t v = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(h));
uint32_t v = static_cast<uint32_t>(h);
if (v == 0 || (v & ((1U << kHandleAlignShift) - 1)) != 0) {
return UINT32_MAX;
}
@@ -21,7 +22,7 @@ inline uint32_t indexOf(HANDLE h) noexcept {
inline HANDLE makeHandle(uint32_t index) noexcept {
uint32_t v = (index + 1) << kHandleAlignShift;
return reinterpret_cast<HANDLE>(static_cast<uintptr_t>(v));
return static_cast<HANDLE>(v);
}
inline bool isPseudo(HANDLE h) noexcept { return reinterpret_cast<int32_t>(h) < 0; }
@@ -83,7 +84,7 @@ HANDLE Handles::alloc(Pin<> obj, uint32_t grantedAccess, uint32_t flags) {
}
Pin<> Handles::get(HANDLE h, HandleMeta *metaOut) {
if (h == nullptr || isPseudo(h)) {
if (h == NO_HANDLE || isPseudo(h)) {
return {}; // pseudo-handles have no entries
}

View File

@@ -35,6 +35,7 @@
namespace {
constexpr uintptr_t kLowMemoryStart = 0x00110000UL; // 1 MiB + 64 KiB
constexpr uintptr_t kHeapMax = 0x60000000UL; // 1 GiB
constexpr uintptr_t kTopDownStart = 0x7F000000UL; // Just below 2GB
constexpr uintptr_t kTwoGB = 0x80000000UL;
constexpr std::size_t kGuestArenaSize = 512ULL * 1024ULL * 1024ULL; // 512 MiB
@@ -195,7 +196,7 @@ bool overlapsExistingMapping(uintptr_t base, std::size_t length) {
if (info.RegionSize == 0) {
continue;
}
uintptr_t mapStart = reinterpret_cast<uintptr_t>(info.BaseAddress);
uintptr_t mapStart = reinterpret_cast<uintptr_t>(fromGuestPtr(info.BaseAddress));
uintptr_t mapEnd = mapStart + static_cast<uintptr_t>(info.RegionSize);
if (mapEnd <= base) {
continue;
@@ -214,8 +215,8 @@ void recordGuestMapping(uintptr_t base, std::size_t size, DWORD allocationProtec
return;
}
MEMORY_BASIC_INFORMATION info{};
info.BaseAddress = reinterpret_cast<void *>(base);
info.AllocationBase = reinterpret_cast<void *>(base);
info.BaseAddress = toGuestPtr(reinterpret_cast<void *>(base));
info.AllocationBase = toGuestPtr(reinterpret_cast<void *>(base));
info.AllocationProtect = allocationProtect;
info.RegionSize = size;
info.State = state;
@@ -435,7 +436,7 @@ void initializeImpl() {
// Map and register guest arena (below 2GB, exclusive)
ArenaRange guest;
if (mapArena(kGuestArenaSize, kLowMemoryStart, kTopDownStart, true, "wibo guest arena", guest)) {
if (mapArena(kGuestArenaSize, kLowMemoryStart, kHeapMax, true, "wibo guest arena", guest)) {
bool ok = mi_manage_os_memory_ex(guest.start, guest.size,
/*is_committed*/ false,
/*is_pinned*/ false,
@@ -910,8 +911,8 @@ VmStatus virtualQuery(const void *address, MEMORY_BASIC_INFORMATION *outInfo) {
regionEnd = regionStart + pageSize;
}
allocLock.unlock();
outInfo->BaseAddress = reinterpret_cast<void *>(regionStart);
outInfo->AllocationBase = nullptr;
outInfo->BaseAddress = toGuestPtr(reinterpret_cast<void *>(regionStart));
outInfo->AllocationBase = GUEST_NULL;
outInfo->AllocationProtect = 0;
outInfo->RegionSize = regionEnd - regionStart;
outInfo->State = MEM_FREE;
@@ -961,8 +962,8 @@ VmStatus virtualQuery(const void *address, MEMORY_BASIC_INFORMATION *outInfo) {
DWORD finalProtect = committed ? pageProtect : PAGE_NOACCESS;
allocLock.unlock();
outInfo->BaseAddress = reinterpret_cast<void *>(blockStart);
outInfo->AllocationBase = reinterpret_cast<void *>(region->base);
outInfo->BaseAddress = toGuestPtr(reinterpret_cast<void *>(blockStart));
outInfo->AllocationBase = toGuestPtr(reinterpret_cast<void *>(region->base));
outInfo->AllocationProtect = allocationProtect;
outInfo->RegionSize = blockEnd - blockStart;
outInfo->State = committed ? MEM_COMMIT : MEM_RESERVE;
@@ -1153,7 +1154,7 @@ static size_t blockLower2GB(MEMORY_BASIC_INFORMATION mappings[MAX_NUM_MAPPINGS])
if (numMappings < MAX_NUM_MAPPINGS) {
if (numMappings > 0) {
auto &prevMapping = mappings[numMappings - 1];
uintptr_t prevMapStart = reinterpret_cast<uintptr_t>(prevMapping.BaseAddress);
uintptr_t prevMapStart = reinterpret_cast<uintptr_t>(fromGuestPtr(prevMapping.BaseAddress));
uintptr_t prevMapEnd = prevMapStart + prevMapping.RegionSize;
if (mapStart <= prevMapEnd) {
// Extend the previous mapping
@@ -1164,10 +1165,10 @@ static size_t blockLower2GB(MEMORY_BASIC_INFORMATION mappings[MAX_NUM_MAPPINGS])
}
}
mappings[numMappings++] = (MEMORY_BASIC_INFORMATION){
.BaseAddress = reinterpret_cast<void *>(mapStart),
.AllocationBase = reinterpret_cast<void *>(mapStart),
.BaseAddress = toGuestPtr(reinterpret_cast<void *>(mapStart)),
.AllocationBase = toGuestPtr(reinterpret_cast<void *>(mapStart)),
.AllocationProtect = PAGE_NOACCESS,
.RegionSize = mapEnd - mapStart,
.RegionSize = static_cast<SIZE_T>(mapEnd - mapStart),
.State = MEM_RESERVE,
.Protect = PAGE_NOACCESS,
.Type = 0, // external
@@ -1225,9 +1226,9 @@ __attribute__((used)) static void wibo_heap_constructor() {
g_mappings = new std::map<uintptr_t, MEMORY_BASIC_INFORMATION>;
for (size_t i = 0; i < numMappings; ++i) {
if (debug) {
fprintf(stderr, "Existing %zu: BaseAddress=%p, RegionSize=%lu\n", i, mappings[i].BaseAddress,
fprintf(stderr, "Existing %zu: BaseAddress=%x, RegionSize=%u\n", i, mappings[i].BaseAddress,
mappings[i].RegionSize);
}
g_mappings->emplace(reinterpret_cast<uintptr_t>(mappings[i].BaseAddress), mappings[i]);
g_mappings->emplace(reinterpret_cast<uintptr_t>(fromGuestPtr(mappings[i].BaseAddress)), mappings[i]);
}
}

View File

@@ -5,6 +5,8 @@
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <limits>
#include <memory>
struct mi_heap_s;
typedef struct mi_heap_s mi_heap_t;
@@ -50,4 +52,100 @@ NTSTATUS ntStatusFromVmStatus(VmStatus status);
bool reserveGuestStack(std::size_t stackSizeBytes, void **outStackLimit, void **outStackBase);
//-------------------- deleters --------------------
template <class U> struct single_deleter {
void operator()(U *p) const noexcept {
if (!p)
return;
p->~U();
wibo::heap::guestFree(static_cast<void *>(p));
}
};
template <class U> struct array_deleter {
std::size_t n{}; // number of elements
void operator()(U *p) const noexcept {
if (!p)
return;
for (std::size_t i = n; i > 0; --i)
(p + (i - 1))->~U();
wibo::heap::guestFree(static_cast<void *>(p));
}
};
//-------------------- pointer alias picking T or T[] --------------------
template <class T> struct unique_type {
using type = std::unique_ptr<T, single_deleter<T>>;
};
template <class T> struct unique_type<T[]> {
using type = std::unique_ptr<T[], array_deleter<T>>;
};
// template <class T, std::size_t> struct unique_type<T[]>; // no bounded arrays (int[N])
template <class T> using guest_ptr = typename unique_type<T>::type;
//-------------------- helpers --------------------
inline bool mul_overflows(std::size_t a, std::size_t b) {
return b != 0 && a > (std::numeric_limits<std::size_t>::max)() / b;
}
//-------------------- single object --------------------
template <class T, class... Args>
requires(!std::is_array_v<T>)
guest_ptr<T> make_guest_unique(Args &&...args) noexcept {
// Optional: insist on nothrow construction in a no-exception build
static_assert(std::is_nothrow_constructible_v<T, Args...>,
"T must be nothrow-constructible when exceptions are disabled");
void *raw = wibo::heap::guestMalloc(sizeof(T));
if (!raw)
return {};
// placement-new without exceptions
T *p = ::new (raw) T(std::forward<Args>(args)...);
return guest_ptr<T>(p, single_deleter<T>{});
}
//-------------------- unbounded array: default-construct --------------------
template <class T>
requires std::is_unbounded_array_v<T>
guest_ptr<T> make_guest_unique(std::size_t n) noexcept {
using U = std::remove_extent_t<T>;
static_assert(std::is_nothrow_default_constructible_v<U>,
"U must be nothrow default-constructible when exceptions are disabled");
if (mul_overflows(n, sizeof(U)))
return {};
void *raw = wibo::heap::guestMalloc(n * sizeof(U));
if (!raw)
return {};
U *p = static_cast<U *>(raw);
for (std::size_t i = 0; i < n; ++i)
::new (p + i) U();
return guest_ptr<T>(p, array_deleter<U>{n});
}
//-------------------- unbounded array: per-element args --------------------
template <class T, class... Args>
requires std::is_unbounded_array_v<T>
guest_ptr<T> make_guest_unique(std::size_t n, Args &&...args) noexcept {
using U = std::remove_extent_t<T>;
static_assert(std::is_nothrow_constructible_v<U, Args...>,
"U(args...) must be nothrow-constructible when exceptions are disabled");
if (mul_overflows(n, sizeof(U)))
return {};
void *raw = wibo::heap::guestMalloc(n * sizeof(U));
if (!raw)
return {};
U *p = static_cast<U *>(raw);
for (std::size_t i = 0; i < n; ++i)
::new (p + i) U(std::forward<Args>(args)...);
return guest_ptr<T>(p, array_deleter<U>{n});
}
} // namespace wibo::heap

View File

@@ -86,11 +86,11 @@ struct PESectionHeader {
uint32_t characteristics;
};
struct PEImportDirectoryEntry {
uint32_t *importLookupTable;
uint32_t importLookupTable;
uint32_t timeDateStamp;
uint32_t forwarderChain;
char *name;
uint32_t *importAddressTable;
uint32_t name;
uint32_t importAddressTable;
};
struct PEHintNameTableEntry {
uint16_t hint;
@@ -254,7 +254,9 @@ bool wibo::Executable::loadPE(FILE *file, bool exec) {
allocStatus = wibo::heap::virtualAlloc(
&allocatedBase, &allocationSize, MEM_RESERVE | MEM_COMMIT, initialProtect, MEM_IMAGE);
}
if (allocStatus != wibo::heap::VmStatus::Success) {
if (allocStatus == wibo::heap::VmStatus::Success) {
DEBUG_LOG("loadPE: mapped image at %p\n", allocatedBase);
} else {
DEBUG_LOG("Image mapping failed (status=%u)\n", static_cast<unsigned>(allocStatus));
imageBase = nullptr;
return false;
@@ -425,10 +427,10 @@ bool wibo::Executable::resolveImports() {
}
while (dir->name) {
char *dllName = fromRVA(dir->name);
char *dllName = fromRVA<char>(dir->name);
DEBUG_LOG("DLL Name: %s\n", dllName);
uint32_t *lookupTable = fromRVA(dir->importLookupTable);
uint32_t *addressTable = fromRVA(dir->importAddressTable);
uint32_t *lookupTable = fromRVA<uint32_t>(dir->importLookupTable);
uint32_t *addressTable = fromRVA<uint32_t>(dir->importAddressTable);
ModuleInfo *module = loadModule(dllName);
if (!module && kernel32::getLastError() != ERROR_MOD_NOT_FOUND) {

40
src/macros.S Normal file
View File

@@ -0,0 +1,40 @@
.intel_syntax noprefix
.equ TEB_SELF, 0x18 # Self
.equ TEB_FS_SEL, 0xf98 # CurrentFsSelector
.equ TEB_GS_SEL, 0xf9a # CurrentGsSelector
#ifdef __i386__
.equ TEB_SP, 0xf9c # CurrentStackPointer
#endif // __i386__
#ifdef __x86_64__
.equ TEB_SP, 0xfa0 # CurrentStackPointer
.equ TEB_FSBASE, 0xfa8 # CurrentFsBase
.equ CS_32, 0x23 # 32-bit code segment (Linux)
.equ CS_64, 0x33 # 64-bit code segment (Linux)
.equ DS_32, 0x2b # 32-bit data segment (Linux)
.macro LJMP32
jmp fword ptr [rip] # far jump into 32-bit code
.long 1f # 32-bit code offset
.word CS_32 # 32-bit code segment (Linux)
.code32
1:
endbr32
.endm
.macro LJMP64
push CS_64 # 64-bit code segment (Linux)
push offset 1f # 64-bit code offset
retf # far jump into 64-bit code
.code64
1:
endbr64
.endm
#endif // __x86_64__

View File

@@ -1,5 +1,4 @@
#include "common.h"
#include "context.h"
#include "entry.h"
#include "entry_trampolines.h"
#include "files.h"
@@ -8,9 +7,15 @@
#include "processes.h"
#include "strutil.h"
#include "tls.h"
#include "types.h"
#include "version_info.h"
#ifdef __x86_64__
#include "setup.h"
#endif
#include <asm/ldt.h>
#include <asm/prctl.h>
#include <cstdarg>
#include <cstdio>
#include <cstdlib>
@@ -53,13 +58,13 @@ void wibo::debug_log(const char *fmt, ...) {
}
TEB *wibo::allocateTib() {
auto *newTib = static_cast<TEB *>(std::calloc(1, sizeof(TEB)));
auto *newTib = static_cast<TEB *>(wibo::heap::guestCalloc(1, sizeof(TEB)));
if (!newTib) {
return nullptr;
}
tls::initializeTib(newTib);
newTib->Tib.Self = &newTib->Tib;
newTib->Peb = processPeb;
newTib->Tib.Self = toGuestPtr(newTib);
newTib->Peb = toGuestPtr(processPeb);
return newTib;
}
@@ -82,8 +87,8 @@ void wibo::initializeTibStackInfo(TEB *tibPtr) {
fprintf(stderr, "Failed to reserve guest stack\n");
std::abort();
}
tibPtr->Tib.StackLimit = guestLimit;
tibPtr->Tib.StackBase = guestBase;
tibPtr->Tib.StackLimit = toGuestPtr(guestLimit);
tibPtr->Tib.StackBase = toGuestPtr(guestBase);
tibPtr->CurrentStackPointer = guestBase;
DEBUG_LOG("initializeTibStackInfo: using guest stack base=%p limit=%p\n", tibPtr->Tib.StackBase,
tibPtr->Tib.StackLimit);
@@ -94,10 +99,18 @@ bool wibo::installTibForCurrentThread(TEB *tibPtr) {
return false;
}
currentThreadTeb = tibPtr;
#ifdef __x86_64__
tibEntryNumber = x86_64_thread_setup(tibEntryNumber, tibPtr);
if (tibEntryNumber == -1 || tibPtr->CurrentFsSelector == 0) {
perror("x86_64_thread_setup failed");
return false;
}
#else
struct user_desc desc;
std::memset(&desc, 0, sizeof(desc));
desc.entry_number = tibEntryNumber;
desc.base_addr = reinterpret_cast<unsigned int>(tibPtr);
desc.base_addr = reinterpret_cast<uintptr_t>(tibPtr);
desc.limit = static_cast<unsigned int>(sizeof(TEB) - 1);
desc.seg_32bit = 1;
desc.contents = 0;
@@ -118,13 +131,10 @@ bool wibo::installTibForCurrentThread(TEB *tibPtr) {
tibPtr->CurrentFsSelector = static_cast<uint16_t>((desc.entry_number << 3) | 3);
tibPtr->CurrentGsSelector = 0;
currentThreadTeb = tibPtr;
#endif
return true;
}
// Make this global to ease debugging
TEB tib;
static std::string getExeName(const char *argv0) {
std::filesystem::path exePath(argv0 ? argv0 : "wibo");
return exePath.filename().string();
@@ -347,16 +357,18 @@ int main(int argc, char **argv) {
files::init();
// Create PEB
PEB *peb = reinterpret_cast<PEB *>(wibo::heap::guestCalloc(1, sizeof(PEB)));
peb->ProcessParameters = toGuestPtr(wibo::heap::guestCalloc(1, sizeof(RTL_USER_PROCESS_PARAMETERS)));
// Create TIB
memset(&tib, 0, sizeof(tib));
wibo::tls::initializeTib(&tib);
tib.Tib.Self = &tib.Tib;
tib.Peb = static_cast<PEB *>(calloc(1, sizeof(PEB)));
tib.Peb->ProcessParameters =
static_cast<RTL_USER_PROCESS_PARAMETERS *>(calloc(1, sizeof(RTL_USER_PROCESS_PARAMETERS)));
wibo::processPeb = tib.Peb;
wibo::initializeTibStackInfo(&tib);
if (!wibo::installTibForCurrentThread(&tib)) {
TEB *tib = reinterpret_cast<TEB *>(wibo::heap::guestCalloc(1, sizeof(TEB)));
wibo::tls::initializeTib(tib);
tib->Tib.Self = toGuestPtr(tib);
tib->Peb = toGuestPtr(peb);
wibo::processPeb = peb;
wibo::initializeTibStackInfo(tib);
if (!wibo::installTibForCurrentThread(tib)) {
fprintf(stderr, "Failed to install TIB for main thread\n");
return 1;
}
@@ -506,7 +518,7 @@ int main(int argc, char **argv) {
call_EntryProc(entryPoint);
DEBUG_LOG("We came back\n");
wibo::shutdownModuleRegistry();
wibo::tls::cleanupTib(&tib);
wibo::tls::cleanupTib(tib);
return 1;
}

View File

@@ -6,9 +6,11 @@
#include "errors.h"
#include "files.h"
#include "heap.h"
#include "kernel32/errhandlingapi.h"
#include "kernel32/internal.h"
#include "strutil.h"
#include "tls.h"
#include "types.h"
#include <algorithm>
#include <array>
@@ -38,8 +40,65 @@ extern const wibo::ModuleStub lib_user32;
extern const wibo::ModuleStub lib_vcruntime;
extern const wibo::ModuleStub lib_version;
// setup.S
template <size_t Index> void stubThunk();
/*
apiset api-ms-win-core-crt-l1-1-0 = msvcrt.dll
apiset api-ms-win-core-crt-l2-1-0 = msvcrt.dll
apiset api-ms-win-crt-conio-l1-1-0 = msvcrt.dll
apiset api-ms-win-crt-convert-l1-1-0 = msvcrt.dll
apiset api-ms-win-crt-environment-l1-1-0 = ucrtbase.dll
apiset api-ms-win-crt-filesystem-l1-1-0 = ucrtbase.dll
apiset api-ms-win-crt-heap-l1-1-0 = ucrtbase.dll
apiset api-ms-win-crt-locale-l1-1-0 = ucrtbase.dll
apiset api-ms-win-crt-math-l1-1-0 = ucrtbase.dll
apiset api-ms-win-crt-multibyte-l1-1-0 = ucrtbase.dll
apiset api-ms-win-crt-private-l1-1-0 = ucrtbase.dll
apiset api-ms-win-crt-process-l1-1-0 = ucrtbase.dll
apiset api-ms-win-crt-runtime-l1-1-0 = ucrtbase.dll
apiset api-ms-win-crt-stdio-l1-1-0 = ucrtbase.dll
apiset api-ms-win-crt-string-l1-1-0 = ucrtbase.dll
apiset api-ms-win-crt-time-l1-1-0 = ucrtbase.dll
apiset api-ms-win-crt-utility-l1-1-0 = ucrtbase.dll
*/
namespace {
const std::array<std::pair<std::string_view, std::string_view>, 17> kApiSet = {
std::pair{"api-ms-win-core-crt-l1-1-0.dll", "msvcrt.dll"},
std::pair{"api-ms-win-core-crt-l2-1-0.dll", "msvcrt.dll"},
std::pair{"api-ms-win-crt-conio-l1-1-0.dll", "msvcrt.dll"},
std::pair{"api-ms-win-crt-convert-l1-1-0.dll", "msvcrt.dll"},
std::pair{"api-ms-win-crt-environment-l1-1-0.dll", "ucrtbase.dll"},
std::pair{"api-ms-win-crt-filesystem-l1-1-0.dll", "ucrtbase.dll"},
std::pair{"api-ms-win-crt-heap-l1-1-0.dll", "ucrtbase.dll"},
std::pair{"api-ms-win-crt-locale-l1-1-0.dll", "ucrtbase.dll"},
std::pair{"api-ms-win-crt-math-l1-1-0.dll", "ucrtbase.dll"},
std::pair{"api-ms-win-crt-multibyte-l1-1-0.dll", "ucrtbase.dll"},
std::pair{"api-ms-win-crt-private-l1-1-0.dll", "ucrtbase.dll"},
std::pair{"api-ms-win-crt-process-l1-1-0.dll", "ucrtbase.dll"},
std::pair{"api-ms-win-crt-runtime-l1-1-0.dll", "ucrtbase.dll"},
std::pair{"api-ms-win-crt-stdio-l1-1-0.dll", "ucrtbase.dll"},
std::pair{"api-ms-win-crt-string-l1-1-0.dll", "ucrtbase.dll"},
std::pair{"api-ms-win-crt-time-l1-1-0.dll", "ucrtbase.dll"},
std::pair{"api-ms-win-crt-utility-l1-1-0.dll", "ucrtbase.dll"},
};
const std::array<std::pair<std::string_view, std::string_view>, 11> kFallbacks = {
std::pair{"ucrtbase.dll", "msvcrt.dll"},
std::pair{"msvcrt40.dll", "msvcrt.dll"},
std::pair{"msvcr70.dll", "msvcrt.dll"},
std::pair{"msvcr71.dll", "msvcrt.dll"},
std::pair{"msvcr80.dll", "msvcrt.dll"},
std::pair{"msvcr90.dll", "msvcrt.dll"},
std::pair{"msvcr100.dll", "msvcrt.dll"},
std::pair{"msvcr110.dll", "msvcrt.dll"},
std::pair{"msvcr120.dll", "msvcrt.dll"},
std::pair{"msvcr130.dll", "msvcrt.dll"},
std::pair{"msvcr140.dll", "msvcrt.dll"},
};
constexpr DWORD DLL_PROCESS_DETACH = 0;
constexpr DWORD DLL_PROCESS_ATTACH = 1;
constexpr DWORD DLL_THREAD_ATTACH = 2;
@@ -69,6 +128,8 @@ size_t stubIndex = 0;
std::array<std::string, MAX_STUBS> stubDlls;
std::array<std::string, MAX_STUBS> stubFuncNames;
std::unordered_map<std::string, StubFuncType> stubCache;
std::unordered_map<HANDLE, std::shared_ptr<wibo::ModuleInfo>> g_modules;
HANDLE g_nextStubHandle = 1;
std::string makeStubKey(const char *dllName, const char *funcName) {
std::string key;
@@ -85,11 +146,6 @@ std::string makeStubKey(const char *dllName, const char *funcName) {
return key;
}
template <size_t Index> void stubThunk() {
// Call the appropriate entry trampoline
thunk_entry_stubBase(Index);
}
template <size_t... Indices>
constexpr std::array<void (*)(void), sizeof...(Indices)> makeStubTable(std::index_sequence<Indices...>) {
return {{stubThunk<Indices>...}};
@@ -162,8 +218,11 @@ LockedRegistry registry() {
if (!reg.initialized) {
reg.initialized = true;
const wibo::ModuleStub *builtins[] = {
&lib_advapi32, &lib_bcrypt, &lib_crt, &lib_kernel32, &lib_lmgr, &lib_mscoree, &lib_msvcrt,
&lib_ntdll, &lib_ole32, &lib_rpcrt4, &lib_user32, &lib_vcruntime, &lib_version, nullptr,
&lib_advapi32, &lib_bcrypt, /*&lib_crt,*/ &lib_kernel32,
&lib_lmgr, &lib_mscoree, /*&lib_msvcrt,*/
&lib_ntdll, &lib_ole32, &lib_rpcrt4,
&lib_user32, &lib_vcruntime, &lib_version,
nullptr,
};
for (const wibo::ModuleStub **module = builtins; *module; ++module) {
registerBuiltinModule(reg, *module);
@@ -204,11 +263,11 @@ struct ParsedModuleName {
bool endsWithDot = false;
};
ParsedModuleName parseModuleName(const std::string &name) {
ParsedModuleName parseModuleName(std::string_view name) {
ParsedModuleName parsed;
parsed.original = name;
parsed.base = name;
std::string sanitized = name;
std::string sanitized{name};
std::replace(sanitized.begin(), sanitized.end(), '/', '\\');
auto sep = sanitized.find_last_of('\\');
if (sep != std::string::npos) {
@@ -282,19 +341,20 @@ bool allocateModuleTlsForThread(wibo::ModuleInfo &module, TEB *tib) {
if (info.threadAllocations.find(tib) != info.threadAllocations.end()) {
return true;
}
void *block = nullptr;
GUEST_PTR block = GUEST_NULL;
const size_t allocationSize = info.allocationSize;
if (allocationSize > 0) {
block = wibo::heap::guestMalloc(allocationSize);
if (!block) {
void *ptr = wibo::heap::guestMalloc(allocationSize);
if (!ptr) {
DEBUG_LOG(" allocateModuleTlsForThread: failed to allocate %zu bytes for %s\n", allocationSize,
module.originalName.c_str());
return false;
}
std::memset(block, 0, allocationSize);
std::memset(ptr, 0, allocationSize);
if (info.templateData && info.templateSize > 0) {
std::memcpy(block, info.templateData, info.templateSize);
std::memcpy(ptr, info.templateData, info.templateSize);
}
block = toGuestPtr(ptr);
}
info.threadAllocations.emplace(tib, block);
if (!wibo::tls::setValue(tib, info.index, block)) {
@@ -322,10 +382,10 @@ void freeModuleTlsForThread(wibo::ModuleInfo &module, TEB *tib) {
if (it == info.threadAllocations.end()) {
return;
}
void *block = it->second;
GUEST_PTR block = it->second;
info.threadAllocations.erase(it);
if (wibo::tls::getValue(tib, info.index) == block) {
if (!wibo::tls::setValue(tib, info.index, nullptr)) {
if (!wibo::tls::setValue(tib, info.index, GUEST_NULL)) {
DEBUG_LOG(" freeModuleTlsForThread: failed to clear TLS pointer for %s (index %u)\n",
module.originalName.c_str(), info.index);
}
@@ -334,7 +394,7 @@ void freeModuleTlsForThread(wibo::ModuleInfo &module, TEB *tib) {
wibo::tls::clearModulePointer(tib, info.loaderIndex);
}
if (block) {
std::free(block);
wibo::heap::guestFree(fromGuestPtr(block));
}
}
@@ -346,7 +406,7 @@ void runModuleTlsCallbacks(wibo::ModuleInfo &module, DWORD reason) {
if (!callback) {
continue;
}
call_PIMAGE_TLS_CALLBACK(callback, module.handle, reason, nullptr);
call_PIMAGE_TLS_CALLBACK(callback, reinterpret_cast<PVOID>(module.handle), reason, nullptr);
}
}
@@ -502,7 +562,9 @@ void registerBuiltinModule(ModuleRegistry &reg, const wibo::ModuleStub *module)
return;
}
wibo::ModulePtr entry = std::make_shared<wibo::ModuleInfo>();
entry->handle = entry.get();
HANDLE handle = g_nextStubHandle++;
g_modules[handle] = entry;
entry->handle = handle;
entry->moduleStub = module;
entry->refCount = UINT_MAX;
entry->originalName = module->names[0] ? module->names[0] : "";
@@ -570,12 +632,10 @@ BOOL callDllMain(wibo::ModuleInfo &info, DWORD reason, LPVOID reserved) {
}
}
DEBUG_LOG(" callDllMain: invoking DllMain(%p, %u, %p) for %s\n",
reinterpret_cast<HMODULE>(info.executable->imageBase), callReason, callReserved,
info.normalizedName.c_str());
DEBUG_LOG(" callDllMain: invoking DllMain(%p, %u, %p) for %s\n", toGuestPtr(info.executable->imageBase),
callReason, callReserved, info.normalizedName.c_str());
BOOL result =
call_DllEntryProc(dllMain, reinterpret_cast<HMODULE>(info.executable->imageBase), callReason, callReserved);
BOOL result = call_DllEntryProc(dllMain, toGuestPtr(info.executable->imageBase), callReason, callReserved);
DEBUG_LOG(" callDllMain: %s DllMain returned %d\n", info.normalizedName.c_str(), result);
return result;
};
@@ -739,7 +799,7 @@ ModuleInfo *registerProcessModule(std::unique_ptr<Executable> executable, std::f
std::string normalizedName = normalizedBaseKey(parsed);
ModulePtr info = std::make_unique<ModuleInfo>();
info->handle = executable->imageBase; // Use image base as handle for main module
info->handle = toGuestPtr(executable->imageBase); // Use image base as handle for main module
info->moduleStub = nullptr;
info->originalName = std::move(originalName);
info->normalizedName = std::move(normalizedName);
@@ -825,7 +885,7 @@ ModuleInfo *moduleInfoFromHandle(HMODULE module) {
if (info->handle == module) {
return info;
}
if (info->executable && info->executable->imageBase == module) {
if (info->executable && info->executable->imageBase == reinterpret_cast<void *>(module)) {
return info;
}
}
@@ -883,7 +943,7 @@ bool initializeModuleTls(ModuleInfo &module) {
info.callbacks.clear();
uintptr_t callbacksArray = resolveModuleAddress(exec, tlsDirectory->AddressOfCallBacks);
if (callbacksArray) {
auto callbackPtr = reinterpret_cast<uintptr_t *>(callbacksArray);
auto callbackPtr = reinterpret_cast<GUEST_PTR *>(callbacksArray);
while (callbackPtr && *callbackPtr) {
info.callbacks.push_back(reinterpret_cast<PIMAGE_TLS_CALLBACK>(resolveModuleAddress(exec, *callbackPtr)));
++callbackPtr;
@@ -937,13 +997,13 @@ bool initializeModuleTls(ModuleInfo &module) {
if (!ctx.success) {
for (auto &[thread, block] : info.threadAllocations) {
if (block) {
std::free(block);
wibo::heap::guestFree(fromGuestPtr(block));
}
if (info.loaderIndex != tls::kInvalidTlsIndex) {
wibo::tls::clearModulePointer(thread, info.loaderIndex);
}
if (wibo::tls::getValue(thread, info.index) == block) {
wibo::tls::setValue(thread, info.index, nullptr);
wibo::tls::setValue(thread, info.index, GUEST_NULL);
}
}
info.threadAllocations.clear();
@@ -971,14 +1031,14 @@ void releaseModuleTls(ModuleInfo &module) {
for (auto &[tib, block] : info.threadAllocations) {
if (tib) {
if (wibo::tls::getValue(tib, info.index) == block) {
wibo::tls::setValue(tib, info.index, nullptr);
wibo::tls::setValue(tib, info.index, GUEST_NULL);
}
if (info.loaderIndex != tls::kInvalidTlsIndex) {
wibo::tls::clearModulePointer(tib, info.loaderIndex);
}
}
if (block) {
std::free(block);
wibo::heap::guestFree(fromGuestPtr(block));
}
}
info.threadAllocations.clear();
@@ -1068,18 +1128,9 @@ ModuleInfo *findLoadedModule(const char *name) {
return info;
}
ModuleInfo *loadModule(const char *dllName) {
if (!dllName || *dllName == '\0') {
kernel32::setLastError(ERROR_INVALID_PARAMETER);
return nullptr;
}
std::string requested(dllName);
DEBUG_LOG("loadModule(%s)\n", requested.c_str());
static ModuleInfo *loadModuleInternal(const std::string &dllName) {
auto reg = registry();
ParsedModuleName parsed = parseModuleName(requested);
ParsedModuleName parsed = parseModuleName(dllName);
DWORD diskError = ERROR_SUCCESS;
auto tryLoadExternal = [&](const std::filesystem::path &path) -> ModuleInfo * {
@@ -1090,7 +1141,7 @@ ModuleInfo *loadModule(const char *dllName) {
if (info->refCount != UINT_MAX) {
info->refCount++;
}
registerExternalModuleAliases(*reg, requested, files::canonicalPath(path), info);
registerExternalModuleAliases(*reg, dllName, files::canonicalPath(path), info);
return info;
}
reg.lock.unlock();
@@ -1115,9 +1166,11 @@ ModuleInfo *loadModule(const char *dllName) {
fclose(file);
ModulePtr info = std::make_unique<ModuleInfo>();
info->handle = info.get();
HANDLE handle = g_nextStubHandle++;
g_modules[handle] = info;
info->handle = handle;
info->moduleStub = nullptr;
info->originalName = requested;
info->originalName = dllName;
info->normalizedName = normalizedBaseKey(parsed);
info->resolvedPath = files::canonicalPath(path);
info->executable = std::move(executable);
@@ -1126,7 +1179,7 @@ ModuleInfo *loadModule(const char *dllName) {
reg.lock.lock();
ModuleInfo *raw = info.get();
reg->modulesByKey[key] = std::move(info);
registerExternalModuleAliases(*reg, requested, raw->resolvedPath, raw);
registerExternalModuleAliases(*reg, dllName, raw->resolvedPath, raw);
reg.lock.unlock();
ensureExportsInitialized(*raw);
if (!raw->executable->resolveImports()) {
@@ -1165,7 +1218,7 @@ ModuleInfo *loadModule(const char *dllName) {
};
auto resolveAndLoadExternal = [&]() -> ModuleInfo * {
auto resolvedPath = resolveModuleOnDisk(*reg, requested, false);
auto resolvedPath = resolveModuleOnDisk(*reg, dllName, false);
if (!resolvedPath) {
DEBUG_LOG(" module not found on disk\n");
diskError = ERROR_MOD_NOT_FOUND;
@@ -1177,7 +1230,7 @@ ModuleInfo *loadModule(const char *dllName) {
std::string alias = normalizedBaseKey(parsed);
ModuleInfo *existing = findByAlias(*reg, alias);
if (!existing) {
existing = findByAlias(*reg, normalizeAlias(requested));
existing = findByAlias(*reg, normalizeAlias(dllName));
}
if (existing) {
DEBUG_LOG(" found existing module alias %s (builtin=%d)\n", alias.c_str(), existing->moduleStub != nullptr);
@@ -1188,10 +1241,10 @@ ModuleInfo *loadModule(const char *dllName) {
DEBUG_LOG(" returning existing external module %s\n", existing->originalName.c_str());
return existing;
}
bool pinned = reg->pinnedModules.count(existing) != 0;
bool pinned = reg->pinnedModules.contains(existing);
if (!pinned) {
if (ModuleInfo *external = resolveAndLoadExternal()) {
DEBUG_LOG(" replaced builtin module %s with external copy\n", requested.c_str());
DEBUG_LOG(" replaced builtin module %s with external copy\n", dllName.c_str());
return external;
} else if (diskError != ERROR_MOD_NOT_FOUND) {
kernel32::setLastError(diskError);
@@ -1203,7 +1256,7 @@ ModuleInfo *loadModule(const char *dllName) {
}
if (ModuleInfo *external = resolveAndLoadExternal()) {
DEBUG_LOG(" loaded external module %s\n", requested.c_str());
DEBUG_LOG(" loaded external module %s\n", dllName.c_str());
return external;
} else if (diskError != ERROR_MOD_NOT_FOUND) {
kernel32::setLastError(diskError);
@@ -1217,7 +1270,7 @@ ModuleInfo *loadModule(const char *dllName) {
builtin = builtinIt->second;
}
if (!builtin) {
builtinIt = reg->builtinAliasMap.find(normalizeAlias(requested));
builtinIt = reg->builtinAliasMap.find(normalizeAlias(dllName));
if (builtinIt != reg->builtinAliasMap.end()) {
builtin = builtinIt->second;
}
@@ -1231,6 +1284,46 @@ ModuleInfo *loadModule(const char *dllName) {
return nullptr;
}
ModuleInfo *loadModule(const char* dllName) {
if (!dllName || *dllName == '\0') {
kernel32::setLastError(ERROR_INVALID_PARAMETER);
return nullptr;
}
DEBUG_LOG("loadModule(%s)\n", dllName);
std::string_view requested{dllName};
const auto parsed = parseModuleName(requested);
std::string normalized = normalizedBaseKey(parsed);
for (auto& [alias, module] : kApiSet) {
if (alias == normalized) {
DEBUG_LOG(" resolved api set %s -> %s\n", alias.data(), module.data());
requested = module;
normalized = module;
break;
}
}
DWORD lastError = kernel32::getLastError();
if (auto* info = loadModuleInternal(std::string{requested})) {
return info;
}
if (kernel32::getLastError() != ERROR_MOD_NOT_FOUND) {
return nullptr;
}
kernel32::setLastError(lastError);
for (auto& [module, fallback] : kFallbacks) {
if (module == normalized) {
DEBUG_LOG(" trying fallback %s -> %s\n", module.data(), fallback.data());
return loadModuleInternal(std::string{fallback});
}
}
kernel32::setLastError(ERROR_MOD_NOT_FOUND);
return nullptr;
}
void freeModule(ModuleInfo *info) {
auto reg = registry();
if (!info || info->refCount == UINT_MAX) {

View File

@@ -4,6 +4,7 @@
#include "entry.h"
#include "msvcrt.h"
#include "tls.h"
#include "types.h"
#include <optional>
#include <unordered_map>
@@ -39,8 +40,7 @@ class Executable {
bool findResource(const ResourceIdentifier &type, const ResourceIdentifier &name, std::optional<uint16_t> language,
ResourceLocation &out) const;
template <typename T> T *fromRVA(uintptr_t rva) const { return (T *)(rva + (uint8_t *)imageBase); }
template <typename T> T *fromRVA(T *rva) const { return fromRVA<T>((uintptr_t)rva); }
template <typename T> T *fromRVA(uint32_t rva) const { return (T *)(rva + (uint8_t *)imageBase); }
void *imageBase = nullptr;
size_t imageSize = 0;
@@ -77,7 +77,7 @@ struct ModuleTlsInfo {
uint32_t characteristics = 0;
size_t allocationSize = 0;
std::vector<PIMAGE_TLS_CALLBACK> callbacks;
std::unordered_map<TEB *, void *> threadAllocations;
std::unordered_map<TEB *, GUEST_PTR> threadAllocations;
};
struct ModuleInfo {
@@ -140,8 +140,8 @@ ModuleInfo *moduleInfoFromAddress(void *addr);
* otherwise it will be a pointer to a `wibo::ModuleInfo`.
*/
inline bool isMainModule(HMODULE hModule) {
return hModule == nullptr || hModule == reinterpret_cast<HMODULE>(mainModule) ||
(mainModule && mainModule->executable && hModule == mainModule->executable->imageBase);
return hModule == NO_HANDLE || (mainModule && mainModule->executable &&
reinterpret_cast<void *>(hModule) == mainModule->executable->imageBase);
}
} // namespace wibo

74
src/setup.S Normal file
View File

@@ -0,0 +1,74 @@
#include "macros.S"
.section .note.GNU-stack, "", @progbits
.text
#ifdef __x86_64__
# int x86_64_thread_setup(int entry_number, void *teb)
.globl x86_64_thread_setup
.type x86_64_thread_setup, @function
x86_64_thread_setup:
push rbx # save rbx
mov r8, rsp # save host stack
rdfsbase r9 # read host FS base
mov rdx, qword ptr [rsi+TEB_SP] # fetch guest stack
LJMP32 # far jump into 32-bit code
mov ax, 0x2b # user data segment (Linux)
mov ds, ax # setup data segment
mov es, ax # setup extra segment
mov esp, edx # switch to guest stack
sub esp, 0x10 # sizeof(user_desc)
mov dword ptr [esp], edi # entry_number (arg 0)
mov dword ptr [esp+4], esi # base_addr (arg 1)
mov dword ptr [esp+8], 0xffff # limit
mov dword ptr [esp+12], 0x41 # seg_32bit | usable
mov ebx, esp # &user_desc
mov eax, 0xf3 # SYS_set_thread_area
int 0x80 # syscall
test eax, eax # check for error
jnz 1f # skip selector setup
mov eax, dword ptr [esp] # entry_number
cmp eax, -1 # check for invalid entry_number
jz 2f # skip selector setup
lea ebx, [eax*8+3] # create selector
mov fs, bx # setup fs segment
mov word ptr [esi+TEB_FS_SEL], bx # save selector
jmp 2f # skip error handling
1:
mov eax, -1 # return -1
2:
add esp, 0x10 # cleanup stack
LJMP64 # far jump into 64-bit code
cdqe # sign-extend eax to rax
mov rsp, r8 # switch to host stack
wrfsbase r9 # restore host FS base
pop rbx # restore rbx
ret
.size x86_64_thread_setup, .-x86_64_thread_setup
#endif // __x86_64__
.altmacro
.code32
.macro stubThunkX number
#ifdef __x86_64__
.globl _Z9stubThunkILm\()\number\()EEvv
.type _Z9stubThunkILm\()\number\()EEvv, @function
_Z9stubThunkILm\()\number\()EEvv:
#else
.globl _Z9stubThunkILj\()\number\()EEvv
.type _Z9stubThunkILj\()\number\()EEvv, @function
_Z9stubThunkILj\()\number\()EEvv:
#endif
pop eax
push \number
push eax
jmp thunk_entry_stubBase
.endm
.set i, 0
.rept 256
stubThunkX %i
.set i, i+1
.endr

13
src/setup.h Normal file
View File

@@ -0,0 +1,13 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __x86_64__
int x86_64_thread_setup(int entry_number, void *teb);
#endif
#ifdef __cplusplus
}
#endif

View File

@@ -1,5 +1,7 @@
#include "tls.h"
#include "common.h"
#include "heap.h"
#include "types.h"
#include <algorithm>
#include <array>
@@ -20,7 +22,7 @@ size_t g_expansionCapacity = 0;
struct TlsArray {
size_t capacity;
void *slots[];
GUEST_PTR slots[];
};
std::unordered_map<TEB *, TlsArray *> g_moduleArrays;
@@ -31,8 +33,8 @@ TlsArray *allocateTlsArray(size_t capacity) {
if (capacity == 0 || capacity > kMaxExpansionSlots) {
return nullptr;
}
const size_t bytes = sizeof(TlsArray) + capacity * sizeof(void *);
auto *arr = static_cast<TlsArray *>(std::calloc(1, bytes));
const size_t bytes = sizeof(TlsArray) + capacity * sizeof(GUEST_PTR);
auto *arr = static_cast<TlsArray *>(wibo::heap::guestCalloc(1, bytes));
if (!arr) {
return nullptr;
}
@@ -40,7 +42,7 @@ TlsArray *allocateTlsArray(size_t capacity) {
return arr;
}
inline TlsArray *arrayFromSlots(void *slots) {
inline TlsArray *arrayFromSlots(GUEST_PTR slots) {
return slots ? reinterpret_cast<TlsArray *>(reinterpret_cast<uint8_t *>(slots) - offsetof(TlsArray, slots))
: nullptr;
}
@@ -56,7 +58,7 @@ void setExpansionArray(TEB *tib, TlsArray *arr) {
if (!tib) {
return;
}
tib->TlsExpansionSlots = arr ? arr->slots : nullptr;
tib->TlsExpansionSlots = arr ? toGuestPtr(arr->slots) : GUEST_NULL;
}
size_t chooseCapacity(size_t current, size_t required) {
@@ -202,7 +204,7 @@ bool ensureModuleArrayCapacityLocked(size_t required) {
}
for (auto &entry : pending) {
g_moduleArrays[entry.tib] = entry.newArray;
entry.tib->ThreadLocalStoragePointer = entry.newArray->slots;
entry.tib->ThreadLocalStoragePointer = toGuestPtr(entry.newArray->slots);
if (entry.oldArray) {
queueOldModuleArray(entry.tib, entry.oldArray);
}
@@ -214,7 +216,7 @@ bool ensureModuleArrayCapacityLocked(size_t required) {
void zeroSlotForAllTibs(size_t index) {
if (index < kTlsSlotCount) {
for (TEB *tib : g_activeTibs) {
tib->TlsSlots[index] = nullptr;
tib->TlsSlots[index] = GUEST_NULL;
}
return;
}
@@ -224,7 +226,7 @@ void zeroSlotForAllTibs(size_t index) {
if (!arr || expansionIndex >= arr->capacity) {
continue;
}
arr->slots[expansionIndex] = nullptr;
arr->slots[expansionIndex] = GUEST_NULL;
}
}
@@ -272,7 +274,7 @@ void cleanupTib(TEB *tib) {
}
g_moduleGarbage.erase(garbageIt);
}
tib->ThreadLocalStoragePointer = nullptr;
tib->ThreadLocalStoragePointer = GUEST_NULL;
auto it = std::find(g_activeTibs.begin(), g_activeTibs.end(), tib);
if (it != g_activeTibs.end()) {
g_activeTibs.erase(it);
@@ -316,9 +318,9 @@ bool isSlotAllocated(DWORD index) {
return index < wibo::tls::kTlsMaxSlotCount && g_slotUsed[index];
}
void *getValue(TEB *tib, DWORD index) {
GUEST_PTR getValue(TEB *tib, DWORD index) {
if (!tib || index >= static_cast<DWORD>(wibo::tls::kTlsMaxSlotCount)) {
return nullptr;
return GUEST_NULL;
}
if (index < static_cast<DWORD>(kTlsSlotCount)) {
return tib->TlsSlots[index];
@@ -326,16 +328,16 @@ void *getValue(TEB *tib, DWORD index) {
std::lock_guard lock(g_tlsMutex);
auto *arr = getExpansionArray(tib);
if (!arr) {
return nullptr;
return GUEST_NULL;
}
size_t expansionIndex = static_cast<size_t>(index) - kTlsSlotCount;
if (expansionIndex >= arr->capacity) {
return nullptr;
return GUEST_NULL;
}
return arr->slots[expansionIndex];
}
bool setValue(TEB *tib, DWORD index, void *value) {
bool setValue(TEB *tib, DWORD index, GUEST_PTR value) {
if (!tib || index >= static_cast<DWORD>(wibo::tls::kTlsMaxSlotCount)) {
return false;
}
@@ -357,9 +359,9 @@ bool setValue(TEB *tib, DWORD index, void *value) {
return true;
}
void *getValue(DWORD index) { return getValue(currentThreadTeb, index); }
GUEST_PTR getValue(DWORD index) { return getValue(currentThreadTeb, index); }
bool setValue(DWORD index, void *value) { return setValue(currentThreadTeb, index, value); }
bool setValue(DWORD index, GUEST_PTR value) { return setValue(currentThreadTeb, index, value); }
void forEachTib(void (*callback)(TEB *, void *), void *context) {
if (!callback) {
@@ -380,7 +382,7 @@ bool ensureModulePointerCapacity(size_t capacity) {
return ensureModuleArrayCapacityLocked(capacity);
}
bool setModulePointer(TEB *tib, size_t index, void *value) {
bool setModulePointer(TEB *tib, size_t index, GUEST_PTR value) {
if (!tib) {
return false;
}
@@ -393,7 +395,7 @@ bool setModulePointer(TEB *tib, size_t index, void *value) {
return false;
}
array->slots[index] = value;
tib->ThreadLocalStoragePointer = array->slots;
tib->ThreadLocalStoragePointer = toGuestPtr(array->slots);
return true;
}
@@ -406,7 +408,7 @@ void clearModulePointer(TEB *tib, size_t index) {
if (!array || index >= array->capacity) {
return;
}
array->slots[index] = nullptr;
array->slots[index] = GUEST_NULL;
}
} // namespace wibo::tls

View File

@@ -13,17 +13,17 @@ void cleanupTib(TEB *tib);
void forEachTib(void (*callback)(TEB *, void *), void *context);
bool ensureModulePointerCapacity(size_t capacity);
bool setModulePointer(TEB *tib, size_t index, void *value);
bool setModulePointer(TEB *tib, size_t index, GUEST_PTR value);
void clearModulePointer(TEB *tib, size_t index);
DWORD reserveSlot();
bool releaseSlot(DWORD index);
bool isSlotAllocated(DWORD index);
void *getValue(TEB *tib, DWORD index);
bool setValue(TEB *tib, DWORD index, void *value);
GUEST_PTR getValue(TEB *tib, DWORD index);
bool setValue(TEB *tib, DWORD index, GUEST_PTR value);
void *getValue(DWORD index);
bool setValue(DWORD index, void *value);
GUEST_PTR getValue(DWORD index);
bool setValue(DWORD index, GUEST_PTR value);
} // namespace wibo::tls

View File

@@ -4,11 +4,6 @@
#define va_list __builtin_va_list
#endif
// On Windows, the incoming stack is aligned to a 4 byte boundary.
// force_align_arg_pointer will realign the stack to match GCC's 16 byte alignment.
#define WIN_ENTRY __attribute__((cdecl, force_align_arg_pointer))
#define WIN_FUNC __attribute__((stdcall, force_align_arg_pointer))
// Annotation macros for code generation
#ifdef WIBO_CODEGEN
#define WIBO_ANNOTATE(x) __attribute__((annotate(x)))
@@ -32,19 +27,41 @@
#define _CC_STDCALL WIBO_ANNOTATE("CC:stdcall")
// Instructs codegen to convert between calling conventions
#ifdef __x86_64__
#define WINAPI _CC_STDCALL
#define CDECL _CC_CDECL
#define CDECL_NO_CONV _CC_CDECL __attribute__((force_align_arg_pointer))
#else
#define WINAPI _CC_STDCALL __attribute__((fastcall))
#define CDECL _CC_CDECL __attribute__((fastcall))
#define CDECL_NO_CONV _CC_CDECL __attribute__((cdecl, force_align_arg_pointer))
#endif
// Used for host-to-guest calls
#define GUEST_STDCALL __attribute__((stdcall))
typedef unsigned int GUEST_PTR;
constexpr GUEST_PTR GUEST_NULL = 0;
#ifdef __x86_64__
inline GUEST_PTR toGuestPtr(const void *addr) {
unsigned long long addr64 = reinterpret_cast<unsigned long long>(addr);
if (addr64 > 0xFFFFFFFF)
__builtin_unreachable();
return static_cast<GUEST_PTR>(addr64);
}
inline void *fromGuestPtr(GUEST_PTR addr) { return reinterpret_cast<void *>(addr); }
#else
inline GUEST_PTR toGuestPtr(const void *addr) { return static_cast<GUEST_PTR>(reinterpret_cast<unsigned long>(addr)); }
inline void *fromGuestPtr(GUEST_PTR addr) { return reinterpret_cast<void *>(addr); }
#endif
using VOID = void;
using HANDLE = VOID *;
using HMODULE = VOID *;
using HGLOBAL = HANDLE;
using HLOCAL = HANDLE;
using HRSRC = HANDLE;
using HANDLE = int;
using HMODULE = HANDLE;
using HGLOBAL = GUEST_PTR;
using HLOCAL = GUEST_PTR;
using HRSRC = GUEST_PTR;
using HINSTANCE = HANDLE;
using LPHANDLE = HANDLE *;
using PHANDLE = HANDLE *;
@@ -66,12 +83,9 @@ using ULONG = unsigned int;
using PULONG = ULONG *;
using LONGLONG = long long;
using ULONGLONG = unsigned long long;
using LONG_PTR = long;
static_assert(sizeof(LONG_PTR) == sizeof(void *), "LONG_PTR must be pointer-sized");
using ULONG_PTR = unsigned long;
static_assert(sizeof(ULONG_PTR) == sizeof(void *), "ULONG_PTR must be pointer-sized");
using UINT_PTR = unsigned long;
static_assert(sizeof(UINT_PTR) == sizeof(void *), "UINT_PTR must be pointer-sized");
using LONG_PTR = int;
using ULONG_PTR = unsigned int;
using UINT_PTR = unsigned int;
using DWORD_PTR = ULONG_PTR;
using PDWORD_PTR = DWORD_PTR *;
using SHORT = short;
@@ -97,7 +111,7 @@ using BYTE = unsigned char;
using BOOLEAN = unsigned char;
using UINT = unsigned int;
using PUINT = UINT *;
using HKEY = VOID *;
using HKEY = HANDLE;
using PHKEY = HKEY *;
using PSID = VOID *;
using REGSAM = DWORD;
@@ -110,6 +124,8 @@ using PBYTE = BYTE *;
using LPBYTE = BYTE *;
using PWSTR = WCHAR *;
constexpr HANDLE NO_HANDLE = 0;
using NTSTATUS = LONG;
using HRESULT = LONG;
@@ -271,20 +287,23 @@ constexpr SIZE_T kTlsSlotCount = 64;
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
GUEST_PTR Buffer;
} UNICODE_STRING;
typedef GUEST_PTR PUNICODE_STRING;
typedef struct _RTL_USER_PROCESS_PARAMETERS {
BYTE Reserved1[16];
PVOID Reserved2[10];
GUEST_PTR Reserved2[10];
UNICODE_STRING ImagePathName;
UNICODE_STRING CommandLine;
} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;
typedef struct _LIST_ENTRY {
struct _LIST_ENTRY *Flink;
struct _LIST_ENTRY *Blink;
} LIST_ENTRY, *PLIST_ENTRY, PRLIST_ENTRY;
GUEST_PTR Flink;
GUEST_PTR Blink;
} LIST_ENTRY;
typedef GUEST_PTR PLIST_ENTRY;
typedef GUEST_PTR PRLIST_ENTRY;
typedef struct _PEB_LDR_DATA {
BYTE Reserved1[8];
@@ -299,23 +318,24 @@ typedef struct _PEB {
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[1];
PVOID Reserved3[2];
PPEB_LDR_DATA Ldr;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
PVOID Reserved4[3];
PVOID AtlThunkSListPtr;
PVOID Reserved5;
GUEST_PTR Reserved3[2];
GUEST_PTR Ldr;
GUEST_PTR ProcessParameters;
GUEST_PTR Reserved4[3];
GUEST_PTR AtlThunkSListPtr;
GUEST_PTR Reserved5;
ULONG Reserved6;
PVOID Reserved7;
GUEST_PTR Reserved7;
ULONG Reserved8;
ULONG AtlThunkSListPtr32;
PVOID Reserved9[45];
GUEST_PTR Reserved9[45];
BYTE Reserved10[96];
PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
GUEST_PTR PostProcessInitRoutine;
BYTE Reserved11[128];
PVOID Reserved12[1];
GUEST_PTR Reserved12[1];
ULONG SessionId;
} PEB, *PPEB;
} PEB;
typedef GUEST_PTR PPEB;
struct CLIENT_ID {
HANDLE UniqueProcess;
@@ -325,7 +345,7 @@ struct CLIENT_ID {
struct _ACTIVATION_CONTEXT;
typedef struct _RTL_ACTIVATION_CONTEXT_STACK_FRAME {
struct _RTL_ACTIVATION_CONTEXT_STACK_FRAME *Previous;
GUEST_PTR Previous;
_ACTIVATION_CONTEXT *ActivationContext;
ULONG Flags;
} RTL_ACTIVATION_CONTEXT_STACK_FRAME, *PRTL_ACTIVATION_CONTEXT_STACK_FRAME;
@@ -339,6 +359,7 @@ typedef struct _ACTIVATION_CONTEXT_STACK {
} ACTIVATION_CONTEXT_STACK, *PACTIVATION_CONTEXT_STACK;
#define GDI_BATCH_BUFFER_SIZE 0x136
typedef struct _GDI_TEB_BATCH {
ULONG Offset;
HANDLE HDC;
@@ -346,83 +367,86 @@ typedef struct _GDI_TEB_BATCH {
} GDI_TEB_BATCH, *PGDI_TEB_BATCH;
typedef struct _NT_TIB {
struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList;
PVOID StackBase;
PVOID StackLimit;
PVOID SubSystemTib;
GUEST_PTR ExceptionList;
GUEST_PTR StackBase;
GUEST_PTR StackLimit;
GUEST_PTR SubSystemTib;
union {
PVOID FiberData;
GUEST_PTR FiberData;
DWORD Version;
} DUMMYUNIONNAME;
PVOID ArbitraryUserPointer;
struct _NT_TIB *Self;
GUEST_PTR ArbitraryUserPointer;
GUEST_PTR Self;
} NT_TIB, *PNT_TIB;
typedef struct _TEB {
NT_TIB Tib;
PVOID EnvironmentPointer;
GUEST_PTR EnvironmentPointer;
CLIENT_ID ClientId;
PVOID ActiveRpcHandle;
PVOID ThreadLocalStoragePointer;
GUEST_PTR ActiveRpcHandle;
GUEST_PTR ThreadLocalStoragePointer;
PPEB Peb;
ULONG LastErrorValue;
ULONG CountOfOwnedCriticalSections;
PVOID CsrClientThread;
PVOID Win32ThreadInfo;
GUEST_PTR CsrClientThread;
GUEST_PTR Win32ThreadInfo;
ULONG Win32ClientInfo[31]; /* used for user32 private data in Wine */
PVOID WOW32Reserved;
GUEST_PTR WOW32Reserved;
ULONG CurrentLocale;
ULONG FpSoftwareStatusRegister;
PVOID SystemReserved1[54]; /* used for kernel32 private data in Wine */
PVOID Spare1;
GUEST_PTR SystemReserved1[54]; /* used for kernel32 private data in Wine */
GUEST_PTR Spare1;
LONG ExceptionCode;
PVOID ActivationContextStackPointer;
GUEST_PTR ActivationContextStackPointer;
BYTE SpareBytes1[36];
PVOID SystemReserved2[10]; /* used for ntdll private data in Wine */
GUEST_PTR SystemReserved2[10]; /* used for ntdll private data in Wine */
GDI_TEB_BATCH GdiTebBatch;
ULONG gdiRgn;
ULONG gdiPen;
ULONG gdiBrush;
CLIENT_ID RealClientId;
HANDLE GdiCachedProcessHandle;
GUEST_PTR GdiCachedProcessHandle;
ULONG GdiClientPID;
ULONG GdiClientTID;
PVOID GdiThreadLocaleInfo;
PVOID UserReserved[5];
PVOID glDispatchTable[280];
GUEST_PTR GdiThreadLocaleInfo;
GUEST_PTR UserReserved[5];
GUEST_PTR glDispatchTable[280];
ULONG glReserved1[26];
PVOID glReserved2;
PVOID glSectionInfo;
PVOID glSection;
PVOID glTable;
PVOID glCurrentRC;
PVOID glContext;
GUEST_PTR glReserved2;
GUEST_PTR glSectionInfo;
GUEST_PTR glSection;
GUEST_PTR glTable;
GUEST_PTR glCurrentRC;
GUEST_PTR glContext;
ULONG LastStatusValue;
UNICODE_STRING StaticUnicodeString;
WCHAR StaticUnicodeBuffer[261];
PVOID DeallocationStack;
PVOID TlsSlots[64];
GUEST_PTR DeallocationStack;
GUEST_PTR TlsSlots[64];
LIST_ENTRY TlsLinks;
PVOID Vdm;
PVOID ReservedForNtRpc;
PVOID DbgSsReserved[2];
GUEST_PTR Vdm;
GUEST_PTR ReservedForNtRpc;
GUEST_PTR DbgSsReserved[2];
ULONG HardErrorDisabled;
PVOID Instrumentation[16];
PVOID WinSockData;
GUEST_PTR Instrumentation[16];
GUEST_PTR WinSockData;
ULONG GdiBatchCount;
ULONG Spare2;
ULONG Spare3;
ULONG Spare4;
PVOID ReservedForOle;
GUEST_PTR ReservedForOle;
ULONG WaitingOnLoaderLock;
PVOID Reserved5[3];
PVOID *TlsExpansionSlots;
GUEST_PTR Reserved5[3];
GUEST_PTR TlsExpansionSlots;
// wibo
WORD CurrentFsSelector;
WORD CurrentGsSelector;
PVOID CurrentStackPointer;
} TEB, *PTEB;
void *CurrentStackPointer;
#ifdef __x86_64__
void *CurrentFsBase;
#endif
} TEB;
typedef GUEST_PTR PTEB;
#ifndef offsetof
#define offsetof(type, member) __builtin_offsetof(type, member)
#endif
@@ -436,8 +460,8 @@ static_assert(offsetof(TEB, DeallocationStack) == 0xE0C, "DeallocationStack offs
static_assert(offsetof(TEB, TlsSlots) == 0xE10, "TLS slots offset mismatch");
typedef struct _MEMORY_BASIC_INFORMATION {
PVOID BaseAddress;
PVOID AllocationBase;
GUEST_PTR BaseAddress;
GUEST_PTR AllocationBase;
DWORD AllocationProtect;
SIZE_T RegionSize;
DWORD State;
@@ -451,12 +475,12 @@ typedef struct _iobuf {
_iobuf() : _file(-1) {}
explicit _iobuf(int file) : _file(file) {}
char *_ptr = nullptr;
GUEST_PTR _ptr = GUEST_NULL;
int _cnt = 0;
char *_base = nullptr;
GUEST_PTR _base = GUEST_NULL;
int _flag = 0;
int _file;
int _charbuf = 0;
int _bufsiz = 0;
char *_tmpfname = nullptr;
GUEST_PTR _tmpfname = GUEST_NULL;
} _FILE;

View File

@@ -20,7 +20,7 @@ import os
import sys
import tempfile
from dataclasses import dataclass, field
from enum import IntEnum
from enum import Enum, IntEnum
from pathlib import Path
from typing import Iterable, List, Optional
@@ -50,6 +50,11 @@ if "LIBCLANG_PATH" in os.environ:
)
class Arch(str, Enum):
X86 = "x86"
X86_64 = "x86_64"
class CallingConv(IntEnum):
"""CXCallingConv enum values from clang-c/Index.h"""
@@ -91,13 +96,30 @@ def _get_function_calling_conv(func_type: CXType) -> CallingConv:
return CallingConv(_get_calling_conv(func_type))
class ArgClass(str, Enum):
INT = "int"
MEMORY = "memory"
@dataclass
class ArgInfo:
type: Type
arg_class: ArgClass
sign_extended: bool
@dataclass
class ArgPlacement:
size: int
slot_size: int
primitive: bool
sign_extended: bool
type: Type
stack_offset: Optional[int] = None
register: Optional[str] = None
def __init__(self, arg: ArgInfo, arch: Arch):
self.size = arg.type.get_canonical().get_size()
self.slot_size = _slot_size_for_arch(arg, arch)
self.register = None
self.stack_offset = None
@dataclass
@@ -108,7 +130,7 @@ class FuncInfo:
source_cc: CallingConv
target_cc: CallingConv
variadic: bool
return_type: Type
return_type: ArgInfo
args: List[ArgInfo] = field(default_factory=list)
@@ -118,7 +140,7 @@ class TypedefInfo:
source_cc: CallingConv
target_cc: CallingConv
variadic: bool
return_type: Type
return_type: ArgInfo
args: List[ArgInfo] = field(default_factory=list)
@@ -210,43 +232,146 @@ SIGNED_KINDS = [
]
def _calculate_arg_info(t: Type) -> ArgInfo:
canonical = t.get_canonical()
# if canonical.kind == TypeKind.RECORD:
# arg_class = ArgClass.MEMORY
# else:
arg_class = ArgClass.INT
if canonical.kind == TypeKind.POINTER:
pointee = canonical.get_pointee()
if pointee.kind == TypeKind.POINTER:
print(f"Bugprone: Pointer to pointer ({_type_to_string(t)})")
# Sign-extend signed integers and HANDLE-like typedefs
is_sign_extended = canonical.kind in SIGNED_KINDS or _is_handle_typedef(t)
return ArgInfo(
arg_class=arg_class,
sign_extended=is_sign_extended,
type=t,
)
def _collect_args(func_type: CXType) -> List[ArgInfo]:
"""Collect argument information for a function."""
args: List[ArgInfo] = []
for t in func_type.argument_types():
size = t.get_size()
canonical = t.get_canonical()
# Determine if primitive (not struct/union)
is_primitive = canonical.kind != TypeKind.RECORD
# Determine if sign-extended
# Sign-extend signed integers and HANDLE-like typedefs
is_sign_extended = canonical in SIGNED_KINDS or _is_handle_typedef(t)
# Calculate stack slot size
if size <= 4:
slot_size = 4
elif size <= 8:
slot_size = 8
else:
raise NotImplementedError(
f"Argument size {size} not supported for function {func_type.spelling}"
)
args.append(
ArgInfo(
size=size,
slot_size=slot_size,
primitive=is_primitive,
sign_extended=is_sign_extended,
type=t,
)
)
args.append(_calculate_arg_info(t))
return args
def collect_functions(tu: TranslationUnit, ns_filter: Optional[str]) -> List[FuncInfo]:
def _slot_size_for_arch(arg: ArgInfo, arch: Arch) -> int:
"""Return the slot size (in bytes) used to pass an argument on the given architecture."""
canonical = arg.type.get_canonical()
if canonical.kind == TypeKind.POINTER:
return 8 if arch == Arch.X86_64 else 4
size = canonical.get_size()
if arch == Arch.X86:
if size <= 4:
return 4
if size <= 8:
return 8
elif arch == Arch.X86_64:
if size <= 8:
return 8
raise NotImplementedError(
f"Argument size {size} not supported for architecture {arch.value}"
)
@dataclass
class ArgLayout:
args: List[ArgPlacement]
stack_size: int
def compute_arg_layout(
args: List[ArgInfo],
cc: CallingConv,
arch: Arch,
stack_offset: int = 0,
skip_args: int = 0,
) -> ArgLayout:
"""Compute how each argument is passed for the given calling convention and arch."""
placements: List[ArgPlacement] = []
stack_size = 0
gpr_order: List[str] = []
gpr_index = skip_args
if arch == Arch.X86 and cc == CallingConv.X86_FASTCALL:
gpr_order = ["ecx", "edx"]
elif arch == Arch.X86_64 and cc == CallingConv.C:
gpr_order = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"]
# Offset our stack based on number of extra arguments
# We assume that every arg represented by skip_args fits in a register
register_size = 8 if arch == Arch.X86_64 else 4
consumed_stack = max(0, skip_args - len(gpr_order)) * register_size
stack_offset += consumed_stack
stack_size += consumed_stack
def _push_stack(arg: ArgInfo) -> None:
nonlocal stack_offset
nonlocal stack_size
placement = ArgPlacement(arg, arch)
placement.stack_offset = stack_offset
placements.append(placement)
stack_offset += placement.slot_size
stack_size += placement.slot_size
def _push_register(arg: ArgInfo) -> None:
nonlocal gpr_index
placement = ArgPlacement(arg, arch)
placement.register = gpr_order[gpr_index]
placements.append(placement)
gpr_index += 1
# Special case for x86 fastcall: stop using registers if any spill onto the stack
if arch == Arch.X86 and cc == CallingConv.X86_FASTCALL:
stack_args_start = 0
for i in range(min(len(gpr_order), len(args))):
if gpr_index >= len(gpr_order):
break
arg = args[i]
slot_size = _slot_size_for_arch(arg, arch)
if arg.arg_class == ArgClass.INT and slot_size == 4:
_push_register(arg)
stack_args_start += 1
else:
break
for i in range(stack_args_start, len(args)):
_push_stack(args[i])
else:
for arg in args:
slot_size = _slot_size_for_arch(arg, arch)
if (
arg.arg_class == ArgClass.INT
and slot_size <= register_size
and gpr_index < len(gpr_order)
):
_push_register(arg)
else:
_push_stack(arg)
return ArgLayout(args=placements, stack_size=stack_size)
def describe_arg_placement(placement: ArgPlacement) -> str:
if placement.register is not None:
return f"{placement.register}[{placement.slot_size}]"
if placement.stack_offset is not None:
return f"stack+{placement.stack_offset}[{placement.slot_size}]"
raise ValueError(f"Unassigned placement {placement}")
def collect_functions(
tu: TranslationUnit, ns_filter: Optional[str], arch: Arch
) -> List[FuncInfo]:
want_ns = ns_filter.split("::") if ns_filter else None
out: dict[str, FuncInfo] = {}
@@ -268,7 +393,7 @@ def collect_functions(tu: TranslationUnit, ns_filter: Optional[str]) -> List[Fun
source_cc=source_cc,
target_cc=_get_function_calling_conv(node.type),
variadic=node.type.is_function_variadic(),
return_type=node.type.get_result(),
return_type=_calculate_arg_info(node.type.get_result()),
args=_collect_args(node.type),
)
@@ -292,7 +417,7 @@ def _type_to_string(t: CXType) -> str:
return spelling
def collect_typedefs(tu: TranslationUnit) -> List[TypedefInfo]:
def collect_typedefs(tu: TranslationUnit, arch: Arch) -> List[TypedefInfo]:
"""Collect function pointer typedefs and type aliases from the translation unit."""
out: dict[str, TypedefInfo] = {}
@@ -309,17 +434,13 @@ def collect_typedefs(tu: TranslationUnit) -> List[TypedefInfo]:
if target_cc == CallingConv.DEFAULT:
return # No CC annotation; skip
variadic = func_type.is_function_variadic()
args = _collect_args(func_type)
return_type = func_type.get_result()
out[name] = TypedefInfo(
name=name,
source_cc=source_cc,
target_cc=target_cc,
variadic=variadic,
return_type=return_type,
args=args,
variadic=func_type.is_function_variadic(),
return_type=_calculate_arg_info(func_type.get_result()),
args=_collect_args(func_type),
)
def visit(node: Cursor) -> None:
@@ -372,17 +493,15 @@ def collect_variables(tu: TranslationUnit, ns_filter: Optional[str]) -> List[Var
return sorted(out.values(), key=lambda v: v.name)
def emit_cc_thunk(f: FuncInfo | TypedefInfo, lines: List[str]):
def emit_cc_thunk32(f: FuncInfo | TypedefInfo, lines: List[str]):
if isinstance(f, TypedefInfo):
# Host-to-guest
target = "[eax+4]"
arg_off = 8
call_target = "[eax+4]"
align = 0
host_to_guest = True
elif isinstance(f, FuncInfo):
# Guest-to-host
target = f.mangled
arg_off = 4
call_target = f.mangled
align = 16
host_to_guest = False
@@ -391,49 +510,32 @@ def emit_cc_thunk(f: FuncInfo | TypedefInfo, lines: List[str]):
assert f.source_cc == CallingConv.C and f.target_cc == CallingConv.C, (
"Variadic functions must be cdecl"
)
lines.append(f"\tjmp {target}")
lines.append(f"\tjmp {call_target}")
return
# Compute argument stack offsets
offsets: List[int] = []
for arg in f.args:
offsets.append(arg_off)
arg_off += arg.slot_size
reg_indices: List[int] = []
if f.target_cc == CallingConv.X86_FASTCALL:
# Store the first two non-record 4-byte args in ECX/EDX for GCC/Clang x86 fastcall
if len(f.args) >= 1 and f.args[0].primitive and f.args[0].slot_size == 4:
reg_indices.append(0) # ECX
if len(f.args) >= 2 and f.args[1].primitive and f.args[1].slot_size == 4:
reg_indices.append(1) # EDX
elif f.target_cc == CallingConv.C or f.target_cc == CallingConv.X86_STDCALL:
# No register args for cdecl or stdcall
pass
else:
raise NotImplementedError(
f"Unsupported target calling convention {f.target_cc.name} for function {f.name}"
source_layout = compute_arg_layout(
f.args,
f.source_cc,
Arch.X86,
stack_offset=4,
skip_args=1 if host_to_guest else 0,
)
target_layout = compute_arg_layout(f.args, f.target_cc, Arch.X86)
# Bytes we will push for the call (exclude args passed in registers)
stack_bytes = sum(
arg.slot_size for i, arg in enumerate(f.args) if i not in reg_indices
)
# Get current TIB
# Get current TEB
if host_to_guest:
lines.append("\tmov ecx, gs:[currentThreadTeb@ntpoff]")
else:
lines.append("\tmov ecx, fs:[0x18]")
lines.append("\tmov ecx, fs:[TEB_SELF]")
# Swap fs and gs
lines.append("\tmov ax, fs")
lines.append("\tmov dx, word ptr [ecx+0xf98]")
lines.append("\tmov word ptr [ecx+0xf98], ax")
lines.append("\tmov dx, word ptr [ecx+TEB_FS_SEL]")
lines.append("\tmov word ptr [ecx+TEB_FS_SEL], ax")
lines.append("\tmov fs, dx")
lines.append("\tmov ax, gs")
lines.append("\tmov dx, word ptr [ecx+0xf9a]")
lines.append("\tmov word ptr [ecx+0xf9a], ax")
lines.append("\tmov dx, word ptr [ecx+TEB_GS_SEL]")
lines.append("\tmov word ptr [ecx+TEB_GS_SEL], ax")
lines.append("\tmov gs, dx")
# Store guest stack pointer in eax for arg access
@@ -442,48 +544,60 @@ def emit_cc_thunk(f: FuncInfo | TypedefInfo, lines: List[str]):
# Swap stack pointer
lines.append("\tpush ebp")
lines.append("\tmov ebp, dword ptr [ecx+0xf9c]")
lines.append("\tmov dword ptr [ecx+0xf9c], esp")
lines.append("\tmov ebp, dword ptr [ecx+TEB_SP]")
lines.append("\tmov dword ptr [ecx+TEB_SP], esp")
lines.append("\tmov esp, ebp")
# Allocate stack space for arguments
if stack_bytes > 0:
lines.append(f"\tsub esp, {stack_bytes}")
if target_layout.stack_size > 0:
lines.append(f"\tsub esp, {target_layout.stack_size}")
# Align stack if needed (must be done after allocating args)
if align > 0:
lines.append(f"\tand esp, ~{align - 1}")
# Copy args onto stack
cur_off = 0
for i, arg in enumerate(f.args):
if i in reg_indices:
# Copy args onto stack for the callee
for idx, target in enumerate(target_layout.args):
if target.stack_offset is None:
continue
base = offsets[i]
for part_off in range(0, arg.slot_size, 4):
lines.append(f"\tmov ecx, [eax+{base + part_off}]")
lines.append(f"\tmov [esp+{cur_off + part_off}], ecx")
cur_off += arg.slot_size
source = source_layout.args[idx]
if source.stack_offset is None:
raise NotImplementedError(
f"Source calling convention {f.source_cc.name} requires register argument {idx}; not implemented"
)
if source.slot_size != target.slot_size:
raise NotImplementedError(
f"Argument {idx} requires size conversion {source.slot_size}->{target.slot_size}; not implemented"
)
for off in range(0, target.slot_size, 4):
lines.append(f"\tmov ecx, [eax+{source.stack_offset + off}]")
lines.append(f"\tmov [esp+{target.stack_offset + off}], ecx")
# Load args into registers as needed
if len(reg_indices) > 0:
i = reg_indices[0]
offset = offsets[i]
lines.append(f"\tmov ecx, [eax+{offset}]")
if len(reg_indices) > 1:
i = reg_indices[1]
offset = offsets[i]
lines.append(f"\tmov edx, [eax+{offset}]")
for idx, target in enumerate(target_layout.args):
if target.register is None:
continue
source = source_layout.args[idx]
if source.stack_offset is None:
raise NotImplementedError(
f"Source calling convention {f.source_cc.name} requires register argument {idx}; not implemented"
)
lines.append(f"\tmov {target.register}, [eax+{source.stack_offset}]")
# Call into target
lines.append(f"\tcall {target}")
lines.append(f"\tcall {call_target}")
# Determine if we can clobber eax/edx
if f.return_type.kind == TypeKind.RECORD:
if f.return_type.arg_class != ArgClass.INT:
raise NotImplementedError(
f"Struct return type not supported for function {f.name}"
f"Unsupported return type class {f.return_type.arg_class.value} for function {f.name}"
)
return_size = f.return_type.get_size()
return_size = f.return_type.type.get_size()
save_eax = return_size > 0
save_edx = return_size > 4
if return_size > 8:
@@ -497,16 +611,16 @@ def emit_cc_thunk(f: FuncInfo | TypedefInfo, lines: List[str]):
if save_edx:
lines.append("\tpush edx")
if host_to_guest:
lines.append("\tmov ecx, fs:[0x18]")
lines.append("\tmov ecx, fs:[TEB_SELF]")
else:
lines.append("\tmov ecx, gs:[currentThreadTeb@ntpoff]")
lines.append("\tmov ax, fs")
lines.append("\tmov dx, word ptr [ecx+0xf98]")
lines.append("\tmov word ptr [ecx+0xf98], ax")
lines.append("\tmov dx, word ptr [ecx+TEB_FS_SEL]")
lines.append("\tmov word ptr [ecx+TEB_FS_SEL], ax")
lines.append("\tmov fs, dx")
lines.append("\tmov ax, gs")
lines.append("\tmov dx, word ptr [ecx+0xf9a]")
lines.append("\tmov word ptr [ecx+0xf9a], ax")
lines.append("\tmov dx, word ptr [ecx+TEB_GS_SEL]")
lines.append("\tmov word ptr [ecx+TEB_GS_SEL], ax")
lines.append("\tmov gs, dx")
if save_edx:
lines.append("\tpop edx")
@@ -515,29 +629,293 @@ def emit_cc_thunk(f: FuncInfo | TypedefInfo, lines: List[str]):
# Swap stack pointer
lines.append("\tmov esp, ebp") # Clean up arg space
lines.append("\tmov ebp, dword ptr [ecx+0xf9c]")
lines.append("\tmov dword ptr [ecx+0xf9c], esp")
lines.append("\tmov ebp, dword ptr [ecx+TEB_SP]")
lines.append("\tmov dword ptr [ecx+TEB_SP], esp")
# Restore stack and frame pointer
lines.append("\tleave")
# Return to guest
if f.source_cc == CallingConv.X86_STDCALL:
ret_bytes = sum(arg.slot_size for arg in f.args)
elif f.source_cc == CallingConv.C:
ret_bytes = 0
else:
raise NotImplementedError(
f"Unsupported source calling convention {f.source_cc.name} for function {f.name}"
)
if ret_bytes > 0:
lines.append(f"\tret {ret_bytes}")
if f.source_cc == CallingConv.X86_STDCALL and source_layout.stack_size > 0:
lines.append(f"\tret {source_layout.stack_size}")
else:
lines.append("\tret")
def _x64_register_by_slot_size(reg: str, slot_size: int) -> str:
if slot_size == 8:
return reg
if reg in ["rax", "rbx", "rcx", "rdx", "rsi", "rdi", "rbp", "rsp"]:
if slot_size == 4:
return f"e{reg[1:]}"
elif slot_size == 2:
return reg[1:]
elif slot_size == 1:
if reg in ["rax", "rbx", "rcx", "rdx"]:
return f"{reg[1]}l"
elif reg in ["rsi", "rdi"]:
return f"{reg[1]}il"
else:
return f"{reg[1]}pl"
if slot_size == 4:
return f"{reg}d"
if slot_size == 2:
return f"{reg}w"
if slot_size == 1:
return f"{reg}b"
raise NotImplementedError(f"Unsupported register {reg} for slot size {slot_size}")
def _x64_ptr_type_by_slot_size(slot_size) -> str:
if slot_size == 4:
return "dword ptr"
elif slot_size == 8:
return "qword ptr"
else:
raise ValueError(f"Unsupported slot size {slot_size}")
def emit_cc_thunk64(f: FuncInfo | TypedefInfo, lines: List[str]):
if isinstance(f, TypedefInfo):
# Host-to-guest
call_target = "edi"
align = 0
host_to_guest = True
elif isinstance(f, FuncInfo):
# Guest-to-host
call_target = f.mangled
align = 16
host_to_guest = False
if f.variadic:
# Variadic functions are not yet supported for calling convention conversion.
assert f.source_cc == CallingConv.C and f.target_cc == CallingConv.C, (
"Variadic functions must be cdecl"
)
lines.append(f"\tjmp {call_target}")
return
source_layout = compute_arg_layout(
f.args,
f.source_cc,
Arch.X86_64 if host_to_guest else Arch.X86,
stack_offset=24 if host_to_guest else 16,
skip_args=1 if host_to_guest else 0,
)
target_layout = compute_arg_layout(
f.args, f.target_cc, Arch.X86 if host_to_guest else Arch.X86_64
)
if host_to_guest:
lines.append(".code64")
# Save rbx and rbp
lines.append("\tpush rbx")
lines.append("\tpush rbp")
# Stash host stack in r10
lines.append("\tmov r10, rsp")
# Get current TEB
lines.append("\tmov rcx, fs:[currentThreadTeb@tpoff]")
# Save FS base
lines.append("\trdfsbase r9")
lines.append("\tmov qword ptr [rcx+TEB_FSBASE], r9")
# Save RSP and load guest stack
lines.append("\tmov rbp, qword ptr [rcx+TEB_SP]")
lines.append("\tmov qword ptr [rcx+TEB_SP], rsp")
lines.append("\tmov rsp, rbp")
# Allocate stack space for arguments
if target_layout.stack_size > 0:
lines.append(f"\tsub rsp, {target_layout.stack_size}")
# Align stack if needed (must be done after allocating args)
if align > 0:
lines.append(f"\tand rsp, ~{align - 1}")
# Transfer arguments
for i, target in enumerate(target_layout.args):
if target.stack_offset is None:
raise NotImplementedError(f"Unexpected register argument {target}")
source = source_layout.args[i]
if source.stack_offset is not None:
ptr_type = _x64_ptr_type_by_slot_size(source.slot_size)
register = _x64_register_by_slot_size("rax", target.slot_size)
lines.append(
f"\tmov {register}, {ptr_type} [r10+{source.stack_offset}]"
)
ptr_type = _x64_ptr_type_by_slot_size(target.slot_size)
register = _x64_register_by_slot_size("rax", target.slot_size)
elif source.register is not None:
ptr_type = _x64_ptr_type_by_slot_size(target.slot_size)
register = _x64_register_by_slot_size(source.register, target.slot_size)
else:
raise ValueError(f"Argument {i} is not a register or stack offset")
lines.append(f"\tmov {ptr_type} [rsp+{target.stack_offset}], {register}")
# Jump to 32-bit mode
lines.append("\tLJMP32")
# Setup FS selector
lines.append("\tmov ax, word ptr [ecx+TEB_FS_SEL]")
lines.append("\tmov fs, ax")
# Call into target
lines.append(f"\tcall {call_target}")
# Get current TEB
lines.append("\tmov ecx, fs:[TEB_SELF]")
# Jump back to 64-bit
lines.append("\tLJMP64")
# Sign extend return value if necessary
if f.return_type.sign_extended:
lines.append("\tcdqe")
# Restore FS base
lines.append("\tmov r9, qword ptr [rcx+TEB_FSBASE]")
lines.append("\twrfsbase r9")
# Restore host stack
lines.append("\tmov rsp, qword ptr [rcx+TEB_SP]")
lines.append("\tmov qword ptr [rcx+TEB_SP], rbp")
# Restore rbp, rbx and return
lines.append("\tpop rbp")
lines.append("\tpop rbx")
lines.append("\tret")
else:
lines.append(".code32")
# Save registers
lines.append("\tpush ebp")
lines.append("\tpush esi")
lines.append("\tpush edi")
# Get current TEB
lines.append("\tmov ecx, fs:[TEB_SELF]")
# Save fs segment
lines.append("\tmov di, fs")
lines.append("\tmov word ptr [ecx+TEB_FS_SEL], di")
# Jump back to 64-bit
lines.append("\tLJMP64")
# Restore FS base
lines.append("\tmov r9, qword ptr [rcx+TEB_FSBASE]")
lines.append("\twrfsbase r9")
# Stash guest stack in r10
lines.append("\tmov r10, rsp")
# Restore host stack
lines.append("\tmov rbp, qword ptr [rcx+TEB_SP]")
lines.append("\tmov qword ptr [rcx+TEB_SP], rsp")
lines.append("\tmov rsp, rbp")
# Allocate stack space for arguments
if target_layout.stack_size > 0:
lines.append(f"\tsub rsp, {target_layout.stack_size}")
# Align stack if needed (must be done after allocating args)
if align > 0:
lines.append(f"\tand rsp, ~{align - 1}")
# Transfer args
for i, target in enumerate(target_layout.args):
arg = f.args[i]
source = source_layout.args[i]
if target.stack_offset is not None:
if source.stack_offset is not None:
ptr_type = _x64_ptr_type_by_slot_size(source.slot_size)
register = _x64_register_by_slot_size("rax", source.slot_size)
lines.append(
f"\tmov {register}, {ptr_type} [r10+{source.stack_offset}]"
)
ptr_type = _x64_ptr_type_by_slot_size(target.slot_size)
register = _x64_register_by_slot_size("rax", target.slot_size)
elif source.register is not None:
ptr_type = _x64_ptr_type_by_slot_size(target.slot_size)
register = _x64_register_by_slot_size(
source.register, target.slot_size
)
else:
raise ValueError(f"Argument {i} is not a register or stack offset")
lines.append(
f"\tmov {ptr_type} [rsp+{target.stack_offset}], {register}"
)
elif target.register is not None:
ptr_type = _x64_ptr_type_by_slot_size(source.slot_size)
if source.slot_size == 4 and target.slot_size == 8:
if arg.sign_extended:
register = _x64_register_by_slot_size(
target.register, source.slot_size
)
lines.append(
f"\tmov {register}, {ptr_type} [r10+{source.stack_offset}]"
)
lines.append(f"\tmovsxd {target.register}, {register}")
else:
register = _x64_register_by_slot_size(
target.register, source.slot_size
)
lines.append(
f"\tmov {register}, {ptr_type} [r10+{source.stack_offset}]"
)
elif source.slot_size == 8 and target.slot_size == 8:
lines.append(
f"\tmov {target.register}, {ptr_type} [r10+{source.stack_offset}]"
)
else:
raise NotImplementedError(
f"Unsupported conversion from {source.slot_size} to {target.slot_size}"
)
# Call into target
lines.append(f"\tcall {call_target}")
# Get current TEB
lines.append("\tmov rcx, fs:[currentThreadTeb@tpoff]")
# Restore host stack
lines.append("\tmov rsp, qword ptr [rcx+TEB_SP]")
lines.append("\tmov qword ptr [rcx+TEB_SP], rbp")
# Jump to 32-bit mode
lines.append("\tLJMP32")
# Setup FS selector
lines.append("\tmov di, word ptr [ecx+TEB_FS_SEL]")
lines.append("\tmov fs, di")
# Restore registers
lines.append("\tpop edi")
lines.append("\tpop esi")
lines.append("\tpop ebp")
# Return to guest
if f.source_cc == CallingConv.X86_STDCALL and source_layout.stack_size > 0:
lines.append(f"\tret {source_layout.stack_size}")
else:
lines.append("\tret")
def emit_cc_thunk(f: FuncInfo | TypedefInfo, lines: List[str], arch: Arch):
if arch == Arch.X86_64:
return emit_cc_thunk64(f, lines)
elif arch == Arch.X86:
return emit_cc_thunk32(f, lines)
def emit_guest_to_host_thunks(
lines: List[str], dll: str, funcs: Iterable[FuncInfo]
lines: List[str], dll: str, funcs: Iterable[FuncInfo], arch: Arch
) -> None:
for f in funcs:
thunk = f"thunk_{dll}_{f.name}"
@@ -545,19 +923,24 @@ def emit_guest_to_host_thunks(
lines.append(
f"# {f.qualified_ns}::{f.name} (source_cc={f.source_cc.name}, target_cc={f.target_cc.name}, variadic={f.variadic})"
)
source_layout = compute_arg_layout(f.args, f.source_cc, Arch.X86)
target_layout = compute_arg_layout(f.args, f.target_cc, arch)
for i, arg in enumerate(f.args):
lines.append(
f"\t# Arg {i} (slot_size={arg.slot_size}, primitive={arg.primitive}, sign_extended={arg.sign_extended})"
)
details: List[str] = []
details.append(f"src={describe_arg_placement(source_layout.args[i])}")
details.append(f"dst={describe_arg_placement(target_layout.args[i])}")
details.append(f"class={arg.arg_class.value}")
details.append(f"sign_extended={arg.sign_extended}")
lines.append(f"\t# Arg {i} ({', '.join(details)})")
lines.append(f".globl {thunk}")
lines.append(f".type {thunk}, @function")
lines.append(f"{thunk}:")
emit_cc_thunk(f, lines)
emit_cc_thunk(f, lines, arch)
lines.append(f".size {thunk}, .-{thunk}")
def emit_host_to_guest_thunks(
lines: List[str], typedefs: Iterable[TypedefInfo]
lines: List[str], typedefs: Iterable[TypedefInfo], arch: Arch
) -> None:
for f in typedefs:
thunk = f"call_{f.name}"
@@ -565,14 +948,23 @@ def emit_host_to_guest_thunks(
lines.append(
f"# {f.name} (target_cc={f.target_cc.name}, variadic={f.variadic})"
)
source_layout = compute_arg_layout(f.args, f.source_cc, arch, skip_args=1)
target_layout = compute_arg_layout(f.args, f.target_cc, Arch.X86)
for i, arg in enumerate(f.args):
lines.append(
f"\t# Arg {i} (slot_size={arg.slot_size}, primitive={arg.primitive}, sign_extended={arg.sign_extended})"
)
details: List[str] = []
details.append(f"src={describe_arg_placement(source_layout.args[i])}")
details.append(f"dst={describe_arg_placement(target_layout.args[i])}")
details.append(f"class={arg.arg_class.value}")
details.append(f"sign_extended={arg.sign_extended}")
lines.append(f"\t# Arg {i} ({', '.join(details)})")
# details = []
# details.append(f"class={f.return_type.arg_class.value}")
# details.append(f"sign_extended={f.return_type.sign_extended}")
# lines.append(f"\t# Ret ({', '.join(details)})")
lines.append(f".weak {thunk}")
lines.append(f".type {thunk}, @function")
lines.append(f"{thunk}:")
emit_cc_thunk(f, lines)
emit_cc_thunk(f, lines, arch)
lines.append(f".size {thunk}, .-{thunk}")
@@ -581,6 +973,7 @@ def emit_header_mapping(
funcs: Iterable[FuncInfo],
typedefs: Iterable[TypedefInfo],
variables: Iterable[VarInfo],
arch: Arch,
) -> str:
guard = f"WIBO_GEN_{dll.upper()}_THUNKS_H"
lines: List[str] = []
@@ -619,8 +1012,10 @@ def emit_header_mapping(
type_str = _canonical_type_str(arg.type)
args.append(f"{type_str} arg{i}")
param_list = ", ".join(args)
return_type = _canonical_type_str(f.return_type)
if f.source_cc == CallingConv.X86_STDCALL:
return_type = _canonical_type_str(f.return_type.type)
if arch == Arch.X86_64:
cc_attr = ""
elif f.source_cc == CallingConv.X86_STDCALL:
cc_attr = "__attribute__((stdcall)) "
elif f.source_cc == CallingConv.C:
cc_attr = "__attribute__((cdecl)) "
@@ -642,7 +1037,7 @@ def emit_header_mapping(
params.append(f"{type_str} arg{i}")
param_list = ", ".join(params)
return_type = _type_to_string(td.return_type)
return_type = _type_to_string(td.return_type.type)
lines.append(f"{return_type} {thunk}({param_list});")
lines.append("#ifdef __cplusplus\n}\n#endif")
@@ -672,7 +1067,7 @@ def main() -> int:
ap.add_argument(
"--namespace", dest="ns", default=None, help="Namespace filter, e.g. kernel32"
)
ap.add_argument("--arch", choices=["x86"], default="x86")
ap.add_argument("--arch", choices=["x86", "x86_64"], default="x86")
ap.add_argument(
"--out-asm", type=Path, required=True, help="Output assembly file (.S)"
)
@@ -682,10 +1077,17 @@ def main() -> int:
ap.add_argument("-I", dest="incs", action="append", default=[])
args = ap.parse_args()
if args.arch == "x86":
arch = Arch.X86
elif args.arch == "x86_64":
arch = Arch.X86_64
else:
raise ValueError(f"Unsupported architecture: {args.arch}")
target = "i686-pc-linux-gnu" if args.arch == "x86" else "x86_64-pc-linux-gnu"
tu = parse_tu(args.headers, args.incs, target)
funcs = collect_functions(tu, args.ns)
typedefs = collect_typedefs(tu)
funcs = collect_functions(tu, args.ns, arch)
typedefs = collect_typedefs(tu, arch)
variables = collect_variables(tu, args.ns)
if not funcs and not typedefs and not variables:
@@ -694,15 +1096,15 @@ def main() -> int:
lines: List[str] = []
lines.append("# Auto-generated thunks; DO NOT EDIT.")
lines.append(".intel_syntax noprefix")
lines.append('#include "macros.S"')
lines.append('.section .note.GNU-stack, "", @progbits')
lines.append(".text")
emit_guest_to_host_thunks(lines, args.dll, funcs)
emit_host_to_guest_thunks(lines, typedefs)
emit_guest_to_host_thunks(lines, args.dll, funcs, arch)
emit_host_to_guest_thunks(lines, typedefs, arch)
asm = "\n".join(lines) + "\n"
hdr = emit_header_mapping(args.dll, funcs, typedefs, variables)
hdr = emit_header_mapping(args.dll, funcs, typedefs, variables, arch)
args.out_asm.parent.mkdir(parents=True, exist_ok=True)
args.out_hdr.parent.mkdir(parents=True, exist_ok=True)