Fix TlsGetValue & more (#48)

`TlsGetValue` disambiguates 0 and an error by relying on `GetLastError`. Depending on the program state, `GetLastError` could be non-0, even though `TlsGetValue` succeeded. Resolve this by always setting `wibo::lastError`. This matches the behavior described by the documentation.

Additionally, when reading resources, later versions of mwcc and mwld call `GetModuleHandleA` with the program path, and then call `LoadStringA` on that handle. Support this behavior by _actually_ loading the PE at the path passed in to `GetModuleHandleA`, instead of assuming it's the current program.

(This is especially useful because sjiswrap relies on overriding `GetModuleFileNameA`, so the wrapped program reads its own resources, rather than sjiswrap's.)

Other small changes:
- Add ms-win-crt `exit` & run atexit funcs
- Implements vcruntime `memmove`
- Implements kernel32 `GetModuleFileNameA`
This commit is contained in:
2023-10-01 23:56:35 -04:00
committed by GitHub
parent 8a6aacb82d
commit c4de05946d
7 changed files with 145 additions and 31 deletions

View File

@@ -250,14 +250,14 @@ namespace kernel32 {
unsigned int WIN_FUNC WaitForSingleObject(void *hHandle, unsigned int dwMilliseconds) {
DEBUG_LOG("WaitForSingleObject (%u)\n", dwMilliseconds);
// TODO - wait on other objects?
// TODO: wait for less than forever
assert(dwMilliseconds == 0xffffffff);
assert(dwMilliseconds == 0xffffffff);
processes::Process* process = processes::processFromHandle(hHandle, false);
int status;
waitpid(process->pid, &status, 0);
@@ -268,7 +268,7 @@ namespace kernel32 {
// Specific exit codes don't really map onto any of these situations - we just know it's bad.
// Specify a non-zero exit code to alert our parent process something's gone wrong.
DEBUG_LOG("WaitForSingleObject: Child process exited abnormally - returning exit code 1.");
process->exitCode = 1;
process->exitCode = 1;
}
return 0;
@@ -366,30 +366,42 @@ namespace kernel32 {
}
}
DEBUG_LOG("...returning nothing\n");
return 0xFFFFFFFF;
wibo::lastError = 1;
return 0xFFFFFFFF; // TLS_OUT_OF_INDEXES
}
unsigned int WIN_FUNC TlsFree(unsigned int dwTlsIndex) {
DEBUG_LOG("TlsFree(%u)\n", dwTlsIndex);
if (dwTlsIndex >= 0 && dwTlsIndex < MAX_TLS_VALUES && tlsValuesUsed[dwTlsIndex]) {
tlsValuesUsed[dwTlsIndex] = false;
return 1;
} else {
wibo::lastError = 1;
return 0;
}
}
void *WIN_FUNC TlsGetValue(unsigned int dwTlsIndex) {
// DEBUG_LOG("TlsGetValue(%u)\n", dwTlsIndex);
if (dwTlsIndex >= 0 && dwTlsIndex < MAX_TLS_VALUES && tlsValuesUsed[dwTlsIndex])
return tlsValues[dwTlsIndex];
else
return 0;
// DEBUG_LOG("TlsGetValue(%u)", dwTlsIndex);
void *result = nullptr;
if (dwTlsIndex >= 0 && dwTlsIndex < MAX_TLS_VALUES && tlsValuesUsed[dwTlsIndex]) {
result = tlsValues[dwTlsIndex];
// See https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-TlsGetValue#return-value
wibo::lastError = ERROR_SUCCESS;
} else {
wibo::lastError = 1;
}
// DEBUG_LOG(" -> %p\n", result);
return result;
}
unsigned int WIN_FUNC TlsSetValue(unsigned int dwTlsIndex, void *lpTlsValue) {
// DEBUG_LOG("TlsSetValue(%u, %p)\n", dwTlsIndex, lpTlsValue);
if (dwTlsIndex >= 0 && dwTlsIndex < MAX_TLS_VALUES && tlsValuesUsed[dwTlsIndex]) {
tlsValues[dwTlsIndex] = lpTlsValue;
return 1;
} else {
wibo::lastError = 1;
return 0;
}
}
@@ -1303,16 +1315,42 @@ namespace kernel32 {
}
}
unsigned int WIN_FUNC GetModuleFileNameA(void* hModule, char* lpFilename, unsigned int nSize) {
DWORD WIN_FUNC GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, DWORD nSize) {
DEBUG_LOG("GetModuleFileNameA (hModule=%p, nSize=%i)\n", hModule, nSize);
if (lpFilename == nullptr) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return 0;
}
*lpFilename = 0; // just NUL terminate
std::string path;
if (wibo::isMainModule(hModule)) {
const auto exePath = files::pathFromWindows(wibo::argv[0]);
const auto absPath = std::filesystem::absolute(exePath);
path = files::pathToWindows(absPath);
} else {
path = static_cast<wibo::ModuleInfo *>(hModule)->name;
}
const size_t len = path.size();
if (nSize == 0) {
wibo::lastError = ERROR_INSUFFICIENT_BUFFER;
return 0;
}
wibo::lastError = 0;
return 0;
const size_t copyLen = std::min(len, nSize - 1);
memcpy(lpFilename, path.c_str(), copyLen);
if (copyLen < nSize) {
lpFilename[copyLen] = 0;
}
if (copyLen < len) {
wibo::lastError = ERROR_INSUFFICIENT_BUFFER;
return nSize;
}
wibo::lastError = ERROR_SUCCESS;
return copyLen;
}
unsigned int WIN_FUNC GetModuleFileNameW(void* hModule, uint16_t* lpFilename, unsigned int nSize) {
DWORD WIN_FUNC GetModuleFileNameW(HMODULE hModule, LPWSTR lpFilename, DWORD nSize) {
DEBUG_LOG("GetModuleFileNameW (hModule=%p, nSize=%i)\n", hModule, nSize);
*lpFilename = 0; // just NUL terminate