// POSIX compatibility support for dynamic module loading. #include #include #include #include "posix.h" #include "posix_path.h" #include "posix_fd.h" static char gDlError[160]; static int gDlErrorPending; // Clears the process-local dynamic-loader error string. static void DlClearError(void) { gDlError[0] = '\0'; gDlErrorPending = 0; } // Stores one process-local dynamic-loader error string. static void DlSetError(const char* message) { if (!message) message = "dynamic loader error"; strncpy(gDlError, message, sizeof(gDlError) - 1); gDlError[sizeof(gDlError) - 1] = '\0'; gDlErrorPending = 1; } // Converts one native loader status to errno and a dlerror message. static void DlSetStatusError(const char* operation, uint32_t status) { (void)status; errno = PosixStatusToErrno(status); DlSetError(operation); } // Loads one DLL-like user module through the native module loader. __declspec(dllexport) void* dlopen(const char* filename, int flags) { (void)flags; DlClearError(); if (!filename || !filename[0]) { errno = EINVAL; DlSetError("dlopen requires a module path"); return 0; } char native[512]; const char* path = PosixTranslatePath(filename, native, sizeof(native)); if (!path || strcmp(path, SYNTH_DEVNULL) == 0 || strcmp(path, SYNTH_DEVZERO) == 0) { errno = EINVAL; DlSetError("dlopen path is not a loadable module"); return 0; } uint32_t handle = 0; SYS_LOAD_MODULE_REQUEST req; memset(&req, 0, sizeof(req)); req.Size = sizeof(req); req.Path = SysSvFromCstr(path); req.ModuleHandleOut = &handle; uint32_t status = SysLoadModule(&req); if (status != NTLSTATUS_SUCCESS || handle == 0) { DlSetStatusError("dlopen failed", status); return 0; } return (void*)(uintptr_t)handle; } // Resolves one named export from a native module handle. __declspec(dllexport) void* dlsym(void* handle, const char* symbol) { DlClearError(); if (!handle || !symbol || !symbol[0]) { errno = EINVAL; DlSetError("dlsym requires a module handle and symbol name"); return 0; } uintptr_t address = 0; SYS_GET_MODULE_EXPORT_REQUEST req; memset(&req, 0, sizeof(req)); req.Size = sizeof(req); req.ModuleHandle = (uint32_t)(uintptr_t)handle; req.Name = SysSvFromCstr(symbol); req.AddressOut = &address; uint32_t status = SysGetModuleExport(&req); if (status != NTLSTATUS_SUCCESS || address == 0) { DlSetStatusError("dlsym failed", status); return 0; } return (void*)address; } // Releases one module handle returned by dlopen. __declspec(dllexport) int dlclose(void* handle) { DlClearError(); if (!handle) { errno = EINVAL; DlSetError("dlclose requires a module handle"); return -1; } uint32_t status = SysUnloadModule((uint32_t)(uintptr_t)handle); if (status != NTLSTATUS_SUCCESS) { DlSetStatusError("dlclose failed", status); return -1; } return 0; } // Returns and clears the most recent dynamic-loader error string. __declspec(dllexport) char* dlerror(void) { if (!gDlErrorPending || !gDlError[0]) return 0; gDlErrorPending = 0; return gDlError; }