From 73b1ffb8d6b47cd833822738533753027c5b68f0 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Mon, 3 Nov 2025 21:46:29 -0700 Subject: [PATCH] Numerous msvcrt/crt fixes; support variable resolution --- dll/crt.cpp | 30 ++++- dll/crt.h | 20 ++-- dll/msvcrt.cpp | 230 ++++++++++++++++++++++----------------- dll/msvcrt.h | 79 +++++++------- src/types.h | 16 +++ tools/gen_trampolines.py | 57 ++++++++-- 6 files changed, 272 insertions(+), 160 deletions(-) diff --git a/dll/crt.cpp b/dll/crt.cpp index 06b24bc..ca0a941 100644 --- a/dll/crt.cpp +++ b/dll/crt.cpp @@ -15,6 +15,25 @@ #include #include +namespace { + +FILE *mapToHostFile(_FILE *file) { + if (!file) + return nullptr; + switch (file->_file) { + case STDIN_FILENO: + return stdin; + case STDOUT_FILENO: + return stdout; + case STDERR_FILENO: + return stderr; + default: + return nullptr; + } +} + +} // namespace + namespace crt { int _commode = 0; @@ -302,15 +321,18 @@ 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, - va_list args) { +int CDECL_NO_CONV __stdio_common_vfprintf(unsigned long long 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); - return vfprintf(stream, format, args); + FILE *hostFile = mapToHostFile(stream); + if (!hostFile) + return -1; + 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) { + 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) diff --git a/dll/crt.h b/dll/crt.h index 08ba16d..453cb6c 100644 --- a/dll/crt.h +++ b/dll/crt.h @@ -2,9 +2,9 @@ #include "types.h" -typedef void (_CC_CDECL *_PVFV)(); -typedef int (_CC_CDECL *_PIFV)(); -typedef void (_CC_CDECL *_invalid_parameter_handler)(const WCHAR *, const WCHAR *, const WCHAR *, UINT, UINT_PTR); +typedef void(_CC_CDECL *_PVFV)(); +typedef int(_CC_CDECL *_PIFV)(); +typedef void(_CC_CDECL *_invalid_parameter_handler)(const WCHAR *, const WCHAR *, const WCHAR *, UINT, UINT_PTR); typedef enum _crt_app_type { _crt_unknown_app, @@ -18,12 +18,14 @@ typedef enum _crt_argv_mode { _crt_argv_expanded_arguments, } _crt_argv_mode; -typedef void (_CC_CDECL *signal_handler)(int); -typedef int (_CC_CDECL *sort_compare)(const void *, const void *); -using FILE = struct _IO_FILE; +typedef void(_CC_CDECL *signal_handler)(int); +typedef int(_CC_CDECL *sort_compare)(const void *, const void *); 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 _set_app_type(_crt_app_type type); @@ -65,10 +67,10 @@ 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, - va_list args); +int CDECL_NO_CONV __stdio_common_vfprintf(unsigned long long 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, - void *locale, va_list args); + void *locale, va_list args); void CDECL qsort(void *base, SIZE_T num, SIZE_T size, sort_compare compare); int CDECL puts(const char *str); diff --git a/dll/msvcrt.cpp b/dll/msvcrt.cpp index 67424ec..84cabdf 100644 --- a/dll/msvcrt.cpp +++ b/dll/msvcrt.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -50,7 +51,48 @@ #define O_BINARY 0 #endif -using _onexit_t = _PIFV; +namespace { + +std::mutex g_fileMutex; +std::unordered_map g_files; + +FILE *mapToHostFile(_FILE *file) { + if (!file) + return nullptr; + switch (file->_file) { + case -1: + return nullptr; + case STDIN_FILENO: + return stdin; + case STDOUT_FILENO: + return stdout; + case STDERR_FILENO: + return stderr; + default: + return g_files[file->_file]; + } +} + +_FILE *mapToGuestFile(FILE *file) { + if (!file) + return nullptr; + int fd = file->_fileno; + _FILE *out = new (wibo::heap::guestMalloc(sizeof(_FILE))) _FILE(fd); + std::lock_guard lock(g_fileMutex); + g_files[fd] = file; + return out; +} + +int closeGuestFile(_FILE *file) { + if (!file) + return -1; + int fd = file->_file; + std::lock_guard lock(g_fileMutex); + g_files.erase(fd); + return close(fd); +} + +} // namespace namespace msvcrt { int _commode; @@ -59,13 +101,15 @@ namespace msvcrt { uint16_t** __winitenv; uint16_t* _wpgmptr = nullptr; char* _pgmptr = nullptr; + int __mb_cur_max = 1; + _FILE _iob[_IOB_ENTRIES] = {_FILE{STDOUT_FILENO}, _FILE{STDERR_FILENO}, _FILE{STDIN_FILENO}}; + constexpr int MB_CP_ANSI = -3; constexpr int MB_CP_OEM = -2; constexpr int MB_CP_LOCALE = -4; constexpr int MB_CP_SBCS = 0; constexpr int MB_CP_UTF8 = -5; - static unsigned int mbCurMaxValue = 1; static int mbCodePageSetting = MB_CP_ANSI; static unsigned int floatingPointControlWord = 0x0009001F; // _CW_DEFAULT for x87 @@ -103,7 +147,7 @@ namespace msvcrt { } } - unsigned int mbCurMaxForCodePage(int codepage); + int mbCurMaxForCodePage(int codepage); void updateMbctypeForCodePage(int codepage) { auto &table = mbctypeTable(); @@ -158,7 +202,7 @@ namespace msvcrt { void ensureMbctypeInitialized() { std::call_once(mbctypeInitFlag(), []() { updateMbctypeForCodePage(mbCodePageSetting); - mbCurMaxValue = mbCurMaxForCodePage(mbCodePageSetting); + __mb_cur_max = mbCurMaxForCodePage(mbCodePageSetting); }); } @@ -205,52 +249,21 @@ namespace msvcrt { return storage; } - IOBProxy *standardIobEntries() { - static IOBProxy entries[3] = {}; - return entries; + _FILE *standardIobEntries() { + return _iob; } - IOBProxy *CDECL __iob_func() { + _FILE *CDECL __iob_func() { HOST_CONTEXT_GUARD(); - return standardIobEntries(); + return _iob; } - IOBProxy *CDECL __p__iob() { + _FILE *CDECL __p__iob() { HOST_CONTEXT_GUARD(); - return standardIobEntries(); + return _iob; } - std::unordered_map &iobMapping() { - static std::unordered_map mapping; - return mapping; - } - - std::once_flag &iobInitFlag() { - static std::once_flag flag; - return flag; - } - - void initializeIobMapping() { - std::call_once(iobInitFlag(), []() { - auto &mapping = iobMapping(); - IOBProxy *entries = standardIobEntries(); - mapping.emplace(static_cast(&entries[0]), stdin); - mapping.emplace(static_cast(&entries[1]), stdout); - mapping.emplace(static_cast(&entries[2]), stderr); - }); - } - - FILE *mapToHostFile(FILE *stream) { - initializeIobMapping(); - auto &mapping = iobMapping(); - auto it = mapping.find(stream); - if (it != mapping.end()) { - return it->second; - } - return stream; - } - - void CDECL setbuf(FILE *stream, char *buffer) { + void CDECL setbuf(_FILE *stream, char *buffer) { HOST_CONTEXT_GUARD(); DEBUG_LOG("setbuf(%p, %p)\n", stream, buffer); if (!stream) { @@ -329,7 +342,7 @@ namespace msvcrt { ext ? ext : ""); } - int CDECL _fileno(FILE *stream) { + int CDECL _fileno(_FILE *stream) { HOST_CONTEXT_GUARD(); DEBUG_LOG("_fileno(%p)\n", stream); if (!stream) { @@ -340,7 +353,7 @@ namespace msvcrt { return ::fileno(host); } - unsigned int mbCurMaxForCodePage(int codepage) { + int mbCurMaxForCodePage(int codepage) { switch (codepage) { case MB_CP_SBCS: case MB_CP_ANSI: @@ -363,7 +376,7 @@ namespace msvcrt { void refreshMbCurMax() { ensureMbctypeInitialized(); - mbCurMaxValue = mbCurMaxForCodePage(mbCodePageSetting); + __mb_cur_max = mbCurMaxForCodePage(mbCodePageSetting); } int CDECL _getmbcp() { @@ -373,11 +386,11 @@ namespace msvcrt { return mbCodePageSetting; } - unsigned int* CDECL __p___mb_cur_max() { + int* CDECL __p___mb_cur_max() { HOST_CONTEXT_GUARD(); ensureMbctypeInitialized(); - DEBUG_LOG("__p___mb_cur_max() -> %u\n", mbCurMaxValue); - return &mbCurMaxValue; + DEBUG_LOG("__p___mb_cur_max() -> %u\n", __mb_cur_max); + return &__mb_cur_max; } int CDECL _setmbcp(int codepage) { @@ -402,7 +415,7 @@ namespace msvcrt { mbCodePageSetting = codepage; updateMbctypeForCodePage(codepage); - mbCurMaxValue = mbCurMaxForCodePage(codepage); + __mb_cur_max = mbCurMaxForCodePage(codepage); return 0; } @@ -729,11 +742,20 @@ namespace msvcrt { return 0; } - _PIFV CDECL _onexit(_PIFV func) { + static void runExitFunc(int status, void *arg) { + (void)status; + (void)call__onexit_t(reinterpret_cast<_onexit_t>(arg)); + } + + _onexit_t CDECL _onexit(_onexit_t func) { HOST_CONTEXT_GUARD(); DEBUG_LOG("_onexit(%p)\n", func); - if(!func) return nullptr; - if (atexit(reinterpret_cast(func)) != 0) return nullptr; + if (!func) { + return nullptr; + } + if (on_exit(runExitFunc, reinterpret_cast(func)) != 0) { + return nullptr; + } return func; } @@ -1129,7 +1151,7 @@ namespace msvcrt { return result; } - char *CDECL fgets(char *str, int count, FILE *stream) { + char *CDECL fgets(char *str, int count, _FILE *stream) { HOST_CONTEXT_GUARD(); DEBUG_LOG("fgets(%p, %d, %p)\n", str, count, stream); if (!str || count <= 0) { @@ -1139,14 +1161,14 @@ namespace msvcrt { return ::fgets(str, count, host); } - SIZE_T CDECL fread(void *buffer, SIZE_T size, SIZE_T count, FILE *stream) { + SIZE_T CDECL fread(void *buffer, SIZE_T size, SIZE_T count, _FILE *stream) { HOST_CONTEXT_GUARD(); DEBUG_LOG("fread(%p, %zu, %zu, %p)\n", buffer, size, count, stream); FILE *host = mapToHostFile(stream); return ::fread(buffer, size, count, host); } - FILE *CDECL _fsopen(const char *filename, const char *mode, int shflag) { + _FILE *CDECL _fsopen(const char *filename, const char *mode, int shflag) { HOST_CONTEXT_GUARD(); DEBUG_LOG("_fsopen(%s, %s, %d)\n", filename ? filename : "(null)", mode ? mode : "(null)", shflag); (void)shflag; @@ -1155,7 +1177,7 @@ namespace msvcrt { return nullptr; } auto hostPath = files::pathFromWindows(filename); - return ::fopen(hostPath.c_str(), mode); + return mapToGuestFile(::fopen(hostPath.c_str(), mode)); } int CDECL _sopen(const char *path, int oflag, int shflag, int pmode) { @@ -1802,13 +1824,18 @@ namespace msvcrt { return std::memcmp(lhs, rhs, count); } - void CDECL qsort(void *base, SIZE_T num, SIZE_T size, int (*compar)(const void *, const void *)) { + static thread_local sort_compare currentCompare = nullptr; + + static int doCompare(const void *a, const void *b) { return call_sort_compare(currentCompare, a, b); } + + void CDECL qsort(void *base, SIZE_T num, SIZE_T size, sort_compare compare) { HOST_CONTEXT_GUARD(); - DEBUG_LOG("qsort(%p, %zu, %zu, %p)\n", base, num, size, compar); - std::qsort(base, num, size, compar); + DEBUG_LOG("qsort(%p, %zu, %zu, %p)\n", base, num, size, compare); + currentCompare = compare; + ::qsort(base, num, size, doCompare); } - int CDECL fflush(FILE *stream) { + int CDECL fflush(_FILE *stream) { HOST_CONTEXT_GUARD(); DEBUG_LOG("fflush(%p)\n", stream); if (!stream) { @@ -1818,10 +1845,10 @@ namespace msvcrt { return std::fflush(host); } - int CDECL_NO_CONV vfwprintf(FILE *stream, const uint16_t *format, va_list args) { + int CDECL_NO_CONV vfwprintf(_FILE *stream, const uint16_t *format, va_list args) { HOST_CONTEXT_GUARD(); DEBUG_LOG("vfwprintf(%p, %s, ...)\n", stream, wideStringToString(format).c_str()); - FILE *host = mapToHostFile(stream ? stream : stdout); + FILE *host = mapToHostFile(stream ? stream : &_iob[0]); std::wstring fmt; if (format) { for (const uint16_t *ptr = format; *ptr; ++ptr) { @@ -1832,10 +1859,10 @@ namespace msvcrt { return std::vfwprintf(host, fmt.c_str(), args); } - FILE *CDECL fopen(const char *filename, const char *mode) { + _FILE *CDECL fopen(const char *filename, const char *mode) { HOST_CONTEXT_GUARD(); DEBUG_LOG("fopen(%s, %s)\n", filename ? filename : "(null)", mode ? mode : "(null)"); - return std::fopen(filename, mode); + return mapToGuestFile(std::fopen(filename, mode)); } int CDECL _dup2(int fd1, int fd2) { @@ -1850,25 +1877,28 @@ 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); - return std::fseek(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); - return std::ftell(stream); + FILE* host = mapToHostFile(stream); + return std::ftell(host); } - int CDECL feof(FILE *stream) { + int CDECL feof(_FILE *stream) { HOST_CONTEXT_GUARD(); VERBOSE_LOG("feof(%p)\n", stream); - return std::feof(stream); + FILE* host = mapToHostFile(stream); + return std::feof(host); } - int CDECL fputws(const uint16_t *str, FILE *stream) { + int CDECL fputws(const uint16_t *str, _FILE *stream) { HOST_CONTEXT_GUARD(); DEBUG_LOG("fputws(%s, %p)\n", wideStringToString(str).c_str(), stream); std::wstring temp; @@ -1877,23 +1907,25 @@ namespace msvcrt { temp.push_back(static_cast(*cursor)); } } - return std::fputws(temp.c_str(), stream); + FILE* host = mapToHostFile(stream); + return std::fputws(temp.c_str(), host); } int CDECL _cputws(const uint16_t *string) { HOST_CONTEXT_GUARD(); DEBUG_LOG("_cputws(%s)\n", wideStringToString(string).c_str()); - return fputws(string, stdout); + return fputws(string, &_iob[0]); } - uint16_t* CDECL fgetws(uint16_t *buffer, int size, FILE *stream) { + uint16_t* CDECL fgetws(uint16_t *buffer, int size, _FILE *stream) { HOST_CONTEXT_GUARD(); DEBUG_LOG("fgetws(%p, %d, %p)\n", buffer, size, stream); if (!buffer || size <= 0) { return nullptr; } std::vector temp(static_cast(size)); - wchar_t *res = std::fgetws(temp.data(), size, stream); + FILE* host = mapToHostFile(stream); + wchar_t *res = std::fgetws(temp.data(), size, host); if (!res) { return nullptr; } @@ -1906,13 +1938,14 @@ namespace msvcrt { return buffer; } - WINT_T CDECL fgetwc(FILE *stream) { + WINT_T CDECL fgetwc(_FILE *stream) { HOST_CONTEXT_GUARD(); VERBOSE_LOG("fgetwc(%p)\n", stream); - return std::fgetwc(stream); + FILE* host = mapToHostFile(stream); + return std::fgetwc(host); } - int CDECL _wfopen_s(FILE **stream, const uint16_t *filename, const uint16_t *mode) { + int CDECL _wfopen_s(_FILE **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()); @@ -1927,7 +1960,7 @@ namespace msvcrt { *stream = nullptr; return errno ? errno : EINVAL; } - *stream = handle; + *stream = mapToGuestFile(handle); return 0; } @@ -2210,21 +2243,14 @@ namespace msvcrt { std::fflush(nullptr); } - static FILE *resolveFileStream(FILE *stream) { - if (!stream) { - return nullptr; - } - return mapToHostFile(stream); - } - - int CDECL_NO_CONV vfprintf(FILE *stream, const char *format, va_list args) { + int CDECL_NO_CONV vfprintf(_FILE *stream, const char *format, va_list args) { HOST_CONTEXT_GUARD(); DEBUG_LOG("vfprintf(stream=%p, format=%s, args=%p)\n", stream, format, args); if (!format || !stream) { errno = EINVAL; return -1; } - FILE *native = resolveFileStream(stream); + FILE *native = mapToHostFile(stream); if (!native) { errno = EINVAL; return -1; @@ -2236,7 +2262,7 @@ namespace msvcrt { return result; } - int CDECL_NO_CONV fprintf(FILE *stream, const char *format, ...) { + int CDECL_NO_CONV fprintf(_FILE *stream, const char *format, ...) { HOST_CONTEXT_GUARD(); DEBUG_LOG("fprintf(%p, %s, ...)\n", stream, format); va_list args; @@ -2246,14 +2272,14 @@ namespace msvcrt { return result; } - int CDECL fputc(int ch, FILE *stream) { + int CDECL fputc(int ch, _FILE *stream) { HOST_CONTEXT_GUARD(); DEBUG_LOG("fputc(%d, %p)\n", ch, stream); if (!stream) { errno = EINVAL; return EOF; } - FILE *native = resolveFileStream(stream); + FILE *native = mapToHostFile(stream); if (!native) { errno = EINVAL; return EOF; @@ -2261,14 +2287,14 @@ namespace msvcrt { return std::fputc(ch, native); } - SIZE_T CDECL fwrite(const void *buffer, SIZE_T size, SIZE_T count, FILE *stream) { + SIZE_T CDECL fwrite(const void *buffer, SIZE_T size, SIZE_T count, _FILE *stream) { HOST_CONTEXT_GUARD(); DEBUG_LOG("fwrite(%p, %zu, %zu, %p)\n", buffer, size, count, stream); if (!buffer || !stream) { errno = EINVAL; return 0; } - FILE *native = resolveFileStream(stream); + FILE *native = mapToHostFile(stream); if (!native) { errno = EINVAL; return 0; @@ -2808,7 +2834,7 @@ namespace msvcrt { return wstrtoul(strSource, endptr, base); } - FILE* CDECL _wfsopen(const uint16_t* filename, const uint16_t* mode, int shflag){ + _FILE* CDECL _wfsopen(const uint16_t* filename, const uint16_t* mode, int shflag){ HOST_CONTEXT_GUARD(); if (!filename || !mode) return nullptr; std::string fname_str = wideStringToString(filename); @@ -2832,10 +2858,10 @@ namespace msvcrt { return 0; } - int CDECL fclose(FILE* stream){ + int CDECL fclose(_FILE* stream){ HOST_CONTEXT_GUARD(); VERBOSE_LOG("fclose(%p)\n", stream); - return ::fclose(stream); + return closeGuestFile(stream); } int CDECL _flushall(){ @@ -2843,9 +2869,15 @@ namespace msvcrt { DEBUG_LOG("_flushall()\n"); int count = 0; - if (msvcrt::fflush(stdin) == 0) count++; - if (msvcrt::fflush(stdout) == 0) count++; - if (msvcrt::fflush(stderr) == 0) count++; + if (::fflush(stdin) == 0) count++; + if (::fflush(stdout) == 0) count++; + if (::fflush(stderr) == 0) count++; + + std::lock_guard lock(g_fileMutex); + for (auto &file : g_files) { + if (::fflush(file.second) == 0) + count++; + } return count; } diff --git a/dll/msvcrt.h b/dll/msvcrt.h index 6d74ecb..6866712 100644 --- a/dll/msvcrt.h +++ b/dll/msvcrt.h @@ -7,7 +7,9 @@ using WINT_T = unsigned short; typedef void(_CC_CDECL *_PVFV)(); typedef int(_CC_CDECL *_PIFV)(); -using _onexit_t = _PIFV; +typedef int(_CC_CDECL *_onexit_t)(); +typedef void(_CC_CDECL *signal_handler)(int); +typedef int(_CC_CDECL *sort_compare)(const void *, const void *); struct _utimbuf { long actime; @@ -21,31 +23,26 @@ struct _timeb { short dstflag; }; -typedef void(_CC_CDECL *signal_handler)(int); -using FILE = struct _IO_FILE; - -struct IOBProxy { - char *_ptr; - int _cnt; - char *_base; - int _flag; - int _file; - int _charbuf; - int _bufsiz; - char *_tmpfname; -}; - struct lconv; namespace msvcrt { -IOBProxy *CDECL __iob_func(); -IOBProxy *CDECL __p__iob(); -void CDECL setbuf(FILE *stream, char *buffer); +extern int _commode; +extern int _fmode; +extern char **__initenv; +extern WCHAR **__winitenv; +extern WCHAR *_wpgmptr; +extern char *_pgmptr; +extern int __mb_cur_max; +extern _FILE _iob[_IOB_ENTRIES]; + +_FILE *CDECL __iob_func(); +_FILE *CDECL __p__iob(); +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 _fileno(_FILE *stream); int CDECL _getmbcp(); -unsigned int *CDECL __p___mb_cur_max(); +int *CDECL __p___mb_cur_max(); int CDECL _setmbcp(int codepage); unsigned char *CDECL __p__mbctype(); unsigned short **CDECL __p__pctype(); @@ -57,7 +54,7 @@ void CDECL _initterm(const _PVFV *ppfn, const _PVFV *end); int CDECL _initterm_e(const _PIFV *ppfn, const _PIFV *end); unsigned int CDECL _controlfp(unsigned int newControl, unsigned int mask); int CDECL _controlfp_s(unsigned int *currentControl, unsigned int newControl, unsigned int mask); -_PIFV CDECL _onexit(_PIFV func); +_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); char *CDECL getenv(const char *varname); @@ -92,9 +89,9 @@ 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, ...); -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); +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); @@ -144,20 +141,20 @@ 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, int (*compar)(const void *, const void *)); -int CDECL fflush(FILE *stream); -int CDECL_NO_CONV vfwprintf(FILE *stream, const WCHAR *format, va_list args); -FILE *CDECL fopen(const char *filename, const char *mode); +void CDECL qsort(void *base, SIZE_T num, SIZE_T size, sort_compare compare); +int CDECL fflush(_FILE *stream); +int CDECL_NO_CONV vfwprintf(_FILE *stream, const WCHAR *format, va_list args); +_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 feof(FILE *stream); -int CDECL fputws(const WCHAR *str, 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); +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 _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); @@ -175,10 +172,10 @@ int CDECL _crt_debugger_hook(int value); int CDECL _configthreadlocale(int mode); void CDECL __setusermatherr(void *handler); void CDECL _cexit(); -int CDECL_NO_CONV vfprintf(FILE *stream, const char *format, va_list args); -int CDECL_NO_CONV fprintf(FILE *stream, const char *format, ...); -int CDECL fputc(int ch, FILE *stream); -SIZE_T CDECL fwrite(const void *buffer, SIZE_T size, SIZE_T count, FILE *stream); +int CDECL_NO_CONV vfprintf(_FILE *stream, const char *format, va_list args); +int CDECL_NO_CONV fprintf(_FILE *stream, const char *format, ...); +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); char *CDECL strchr(const char *str, int character); struct lconv *CDECL localeconv(); @@ -220,9 +217,9 @@ 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); -FILE *CDECL _wfsopen(const WCHAR *filename, const WCHAR *mode, int shflag); +_FILE *CDECL _wfsopen(const WCHAR *filename, const WCHAR *mode, int shflag); int CDECL puts(const char *str); -int CDECL fclose(FILE *stream); +int CDECL fclose(_FILE *stream); int CDECL _flushall(); int *CDECL _errno(); LONG_PTR CDECL _wspawnvp(int mode, const WCHAR *cmdname, const WCHAR *const *argv); diff --git a/src/types.h b/src/types.h index b16b273..d5e6bd5 100644 --- a/src/types.h +++ b/src/types.h @@ -444,3 +444,19 @@ typedef struct _MEMORY_BASIC_INFORMATION { DWORD Protect; DWORD Type; } MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION; + +#define _IOB_ENTRIES 20 + +typedef struct _iobuf { + _iobuf() : _file(-1) {} + explicit _iobuf(int file) : _file(file) {} + + char *_ptr = nullptr; + int _cnt = 0; + char *_base = nullptr; + int _flag = 0; + int _file; + int _charbuf = 0; + int _bufsiz = 0; + char *_tmpfname = nullptr; +} _FILE; diff --git a/tools/gen_trampolines.py b/tools/gen_trampolines.py index bf14b54..bc46a74 100644 --- a/tools/gen_trampolines.py +++ b/tools/gen_trampolines.py @@ -29,14 +29,13 @@ from clang.cindex import ( Cursor, CursorKind, Index, + StorageClass, TranslationUnit, Type, TypeKind, conf, ) -from clang.cindex import ( - Type as CXType, -) +from clang.cindex import Type as CXType # Allow libclang path to be specified via environment variable if "LIBCLANG_PATH" in os.environ: @@ -123,6 +122,12 @@ class TypedefInfo: args: List[ArgInfo] = field(default_factory=list) +@dataclass +class VarInfo: + qualified_ns: str + name: str + + def parse_tu( headers: List[str], include_dirs: List[str], target: str ) -> TranslationUnit: @@ -338,6 +343,35 @@ def collect_typedefs(tu: TranslationUnit) -> List[TypedefInfo]: return sorted(out.values(), key=lambda t: t.name) +def collect_variables(tu: TranslationUnit, ns_filter: Optional[str]) -> List[VarInfo]: + """Collect extern variable declarations from the translation unit.""" + want_ns = ns_filter.split("::") if ns_filter else None + out: dict[str, VarInfo] = {} + + def visit(node: Cursor) -> None: + if node.kind == CursorKind.VAR_DECL: + if node.storage_class != StorageClass.EXTERN or node.is_definition(): + return + ns_parts = _cursor_namespace(node) + if want_ns is not None and ns_parts != want_ns: + return + name = node.spelling + if not name: + return + out[name] = VarInfo( + qualified_ns="::".join(ns_parts), + name=name, + ) + + if node.kind in (CursorKind.TRANSLATION_UNIT, CursorKind.NAMESPACE): + for c in node.get_children(): + visit(c) + + if tu.cursor is not None: + visit(tu.cursor) + return sorted(out.values(), key=lambda v: v.name) + + def emit_cc_thunk(f: FuncInfo | TypedefInfo, lines: List[str]): if isinstance(f, TypedefInfo): # Host-to-guest @@ -543,7 +577,10 @@ def emit_host_to_guest_thunks( def emit_header_mapping( - dll: str, funcs: Iterable[FuncInfo], typedefs: Iterable[TypedefInfo] + dll: str, + funcs: Iterable[FuncInfo], + typedefs: Iterable[TypedefInfo], + variables: Iterable[VarInfo], ) -> str: guard = f"WIBO_GEN_{dll.upper()}_THUNKS_H" lines: List[str] = [] @@ -616,6 +653,11 @@ def emit_header_mapping( lines.append( f'\tif (strcmp(name, "{f.name}") == 0) return (void*)&thunk_{dll}_{f.name};' ) + for v in variables: + qualified = f"{v.qualified_ns}::{v.name}" if v.qualified_ns else v.name + lines.append( + f'\tif (strcmp(name, "{v.name}") == 0) return (void*)&{qualified};' + ) lines.append("\treturn NULL;") lines.append("}") @@ -644,9 +686,10 @@ def main() -> int: tu = parse_tu(args.headers, args.incs, target) funcs = collect_functions(tu, args.ns) typedefs = collect_typedefs(tu) + variables = collect_variables(tu, args.ns) - if not funcs and not typedefs: - sys.stderr.write("No functions or typedefs found for generation.\n") + if not funcs and not typedefs and not variables: + sys.stderr.write("No functions, typedefs, or variables found for generation.\n") return 1 lines: List[str] = [] @@ -659,7 +702,7 @@ def main() -> int: emit_host_to_guest_thunks(lines, typedefs) asm = "\n".join(lines) + "\n" - hdr = emit_header_mapping(args.dll, funcs, typedefs) + hdr = emit_header_mapping(args.dll, funcs, typedefs, variables) args.out_asm.parent.mkdir(parents=True, exist_ok=True) args.out_hdr.parent.mkdir(parents=True, exist_ok=True)