// POSIX compatibility support for dynamic module loading. #include #include #include #include #include #include "posix_internal.h" #include "posix_path.h" #include "posix_fd.h" // Clears the current thread's dynamic-loader error string. static void DlClearError(void) { PosixRuntimeClearDlError(); } // Stores one current-thread dynamic-loader error string. static void DlSetError(const char* message) { PosixRuntimeSetDlError(message); } // 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]; uint32_t status = PosixProcessPath(filename, native, sizeof(native)); if (status != NTLSTATUS_SUCCESS) { errno = EINVAL; DlSetError("dlopen path is not a loadable module"); return 0; } if (!strchr(native, '/')) { size_t length = strlen(native); if (length + sizeof("system/") > sizeof(native)) { errno = ERANGE; DlSetError("dlopen path is too long"); return 0; } memmove(native + 7, native, length + 1u); memcpy(native, "system/", 7); } SYS_HANDLE root = SYS_HANDLE_INVALID; status = NtlResourceOpenSystemRoot(SYS_RIGHT_QUERY | SYS_VOLUME_RIGHT_OPEN, &root); if (status != NTLSTATUS_SUCCESS) { DlSetStatusError("dlopen system root failed", status); return 0; } NTL_MODULE_HANDLE handle = NTL_MODULE_HANDLE_INVALID; NTL_LOAD_MODULE_AT_REQUEST req; memset(&req, 0, sizeof(req)); req.Size = sizeof(req); req.Flags = NTL_MODULE_LOAD_FLAG_NONE; req.RootHandle = root; req.Path = SysSvFromCstr(native); req.ModuleRootHandle = root; req.ModuleDirectory = SYS_SV_LITERAL("system"); req.ResolveModuleName = PosixResolveModuleName; req.ModuleHandleOut = &handle; status = NtlLoadModuleAt(&req); (void)SysCloseHandle(root); if (status != NTLSTATUS_SUCCESS || handle == NTL_MODULE_HANDLE_INVALID) { 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; uint32_t status = NtlGetModuleExport((NTL_MODULE_HANDLE)(uintptr_t)handle, SysSvFromCstr(symbol), &address); 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 = NtlUnloadModule((NTL_MODULE_HANDLE)(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) { return PosixRuntimeTakeDlError(); }