infix
A JIT-Powered FFI Library for C
Loading...
Searching...
No Matches
loader.c
Go to the documentation of this file.
1
32
33// Platform-specific headers for dynamic library handling.
34#if defined(INFIX_OS_WINDOWS)
35#include <windows.h>
36#else
37#include <dlfcn.h>
38#endif
39
50 void * handle;
51};
52
66 if (path == nullptr)
67 return nullptr;
68
69 // Allocate memory for our opaque wrapper struct.
71 if (lib == nullptr) {
73 return nullptr;
74 }
75
76#if defined(INFIX_OS_WINDOWS)
77 // On Windows, use LoadLibraryA to load the DLL.
78 // 'A' specifies the ANSI version, which matches the `const char*` input.
79 lib->handle = LoadLibraryA(path);
80#else
81 // On POSIX systems, use dlopen.
82 // - RTLD_LAZY: Resolves symbols only when they are first used (lazy binding),
83 // which can improve startup performance.
84 // - RTLD_GLOBAL: Makes symbols from this library available for resolution
85 // by subsequently loaded libraries. This is important for handling
86 // complex dependencies between shared objects.
87 lib->handle = dlopen(path, RTLD_LAZY | RTLD_GLOBAL);
88#endif
89
90 // Both LoadLibraryA and dlopen return NULL on failure.
91 if (lib->handle == nullptr) {
92#if defined(INFIX_OS_WINDOWS)
94#else
96#endif
97 // If the OS call failed, we must free the wrapper struct we allocated
98 // to prevent a memory leak.
99 infix_free(lib);
100 return nullptr;
101 }
102 return lib;
103}
104
114 if (lib == nullptr)
115 return;
116
117 // Only attempt to unload if the native handle is valid.
118 if (lib->handle) {
119#if defined(INFIX_OS_WINDOWS)
120 // On Windows, FreeLibrary decrements the library's reference count.
121 // The DLL is unloaded when its reference count reaches zero.
122 FreeLibrary((HMODULE)lib->handle);
123#else
124 // On POSIX, dlclose does the same.
125 dlclose(lib->handle);
126#endif
127 }
128 // Finally, free our wrapper struct.
129 infix_free(lib);
130}
131
144c23_nodiscard void * infix_library_get_symbol(infix_library_t * lib, const char * symbol_name) {
145 if (lib == nullptr || lib->handle == nullptr || symbol_name == nullptr)
146 return nullptr;
147
148#if defined(INFIX_OS_WINDOWS)
149 // On Windows, use GetProcAddress. The return type is technically FARPROC,
150 // which must be cast to a generic `void*` for our cross-platform API.
151 return (void *)GetProcAddress((HMODULE)lib->handle, symbol_name);
152#else
153 // On POSIX, use dlsym. It directly returns a `void*`.
154 return dlsym(lib->handle, symbol_name);
155#endif
156}
157
171 const char * symbol_name,
172 const char * type_signature,
173 void * buffer) {
174 if (buffer == nullptr)
176
177 // Find the address of the global variable in the library.
178 void * symbol_addr = infix_library_get_symbol(lib, symbol_name);
179 if (symbol_addr == nullptr) {
182 }
183
184 // Parse the type signature to determine the size of the variable.
185 // This creates a temporary arena to hold the type information.
186 infix_type * type = nullptr;
187 infix_arena_t * arena = nullptr;
188 infix_status status = infix_type_from_signature(&type, &arena, type_signature, nullptr);
189
190 if (status != INFIX_SUCCESS)
191 return status;
192
193 // Perform a memory copy of the correct size.
194 infix_memcpy(buffer, symbol_addr, type->size);
195
196 // Clean up the temporary arena used for parsing.
198 return INFIX_SUCCESS;
199}
200
214 const char * symbol_name,
215 const char * type_signature,
216 void * buffer) {
217 if (buffer == nullptr)
219
220 // Find the address of the global variable in the library.
221 void * symbol_addr = infix_library_get_symbol(lib, symbol_name);
222 if (symbol_addr == nullptr) {
225 }
226
227 // Parse the type signature to determine the size of the variable.
228 infix_type * type = nullptr;
229 infix_arena_t * arena = nullptr;
230 infix_status status = infix_type_from_signature(&type, &arena, type_signature, nullptr);
231
232 if (status != INFIX_SUCCESS)
233 return status;
234
235 // Perform a memory copy of the correct size.
236 infix_memcpy(symbol_addr, buffer, type->size);
237
238 // Clean up the temporary arena used for parsing.
240 return INFIX_SUCCESS;
241}
infix_arena_t * arena
Definition 005_layouts.c:57
infix_status status
Definition 103_unions.c:74
#define c23_nodiscard
Definition compat_c23.h:93
@ INFIX_CODE_SYMBOL_NOT_FOUND
The requested symbol could not be found within the lib.
Definition infix.h:1083
@ INFIX_CODE_LIBRARY_LOAD_FAILED
Definition infix.h:1084
@ INFIX_CODE_OUT_OF_MEMORY
Failure to allocate memory. Likely due to lack of system resources.
Definition infix.h:1061
@ INFIX_CATEGORY_ALLOCATION
An error related to memory allocation.
Definition infix.h:1042
@ INFIX_CATEGORY_GENERAL
A general or miscellaneous error.
Definition infix.h:1041
c23_nodiscard infix_status infix_write_global(infix_library_t *lib, const char *symbol_name, const char *type_signature, void *buffer)
Writes a value to a global variable in a loaded library.
Definition loader.c:213
c23_nodiscard infix_status infix_read_global(infix_library_t *lib, const char *symbol_name, const char *type_signature, void *buffer)
Reads the value of a global variable from a loaded library.
Definition loader.c:170
c23_nodiscard infix_status infix_type_from_signature(infix_type **, infix_arena_t **, const char *, infix_registry_t *)
Parses a signature string representing a single data type.
Definition signature.c:1090
void infix_library_close(infix_library_t *lib)
Closes a dynamic library handle and unloads it.
Definition loader.c:113
c23_nodiscard void * infix_library_get_symbol(infix_library_t *lib, const char *symbol_name)
Retrieves the memory address of a symbol (function or global variable).
Definition loader.c:144
c23_nodiscard infix_library_t * infix_library_open(const char *path)
Opens a dynamic library and returns a handle to it.
Definition loader.c:65
#define infix_free
A macro for the memory deallocation function.
Definition infix.h:280
void infix_arena_destroy(infix_arena_t *)
Frees an entire memory arena and all objects allocated within it.
Definition arena.c:68
#define infix_memcpy
A macro for copying memory from a source to a destination pointer.
Definition infix.h:290
#define infix_malloc
A macro for the memory allocation function used by the library.
Definition infix.h:250
infix_status
An enumeration of all possible success or failure codes from the public API.
Definition infix.h:351
@ INFIX_SUCCESS
The operation completed successfully.
Definition infix.h:352
@ INFIX_ERROR_INVALID_ARGUMENT
An invalid argument was provided to a function.
Definition infix.h:354
Declarations for internal-only functions, types, and constants.
void _infix_set_error(infix_error_category_t, infix_error_code_t, size_t)
Sets the thread-local error details for a library-internal error.
Definition error.c:44
void _infix_set_system_error(infix_error_category_t, infix_error_code_t, long, const char *)
Sets the thread-local error details for an error originating from the OS.
Definition error.c:56
Definition infix_internals.h:130
Definition loader.c:49
void * handle
Definition loader.c:50
The central structure for describing any data type in the FFI system.
Definition infix.h:161
size_t size
The total size of the type in bytes, per sizeof.
Definition infix.h:163