Files
nt-lite/code/user/personalities/posix/posix_dlfcn.c
T

119 lines
3.3 KiB
C

// POSIX compatibility support for dynamic module loading.
#include <stdint.h>
#include <string.h>
#include <ntlite/syscall.h>
#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;
}