Make breaking change to cosmo_dlsym()

The cosmo_dlsym() function now returns the raw function address. You
need to call cosmo_dltramp() on the result, to make it safe to call.
This change is important, because cosmo_dltramp() magic can't always
work; for some tricky functions, you need to translate ABIs by hand.
This commit is contained in:
Justine Tunney 2024-01-06 15:45:26 -08:00
parent f224a55d57
commit 5e7137097d
No known key found for this signature in database
GPG key ID: BE714B4575D6E328

View file

@ -774,13 +774,10 @@ static void *dlopen_silicon(const char *path, int mode) {
* WARNING: Our API uses a different naming because cosmo_dlopen() lacks * WARNING: Our API uses a different naming because cosmo_dlopen() lacks
* many of the features one would reasonably expect from a UNIX dlopen() * many of the features one would reasonably expect from a UNIX dlopen()
* implementation; and we don't want to lead ./configure scripts astray. * implementation; and we don't want to lead ./configure scripts astray.
* You're limited to 5 integral function parameters maximum. Calling an * Foreign libraries also can't link symbols defined by your executable,
* imported function currently goes much slower than a normal function * which means using this for high-level language plugins is completely
* call. You can't pass callback function pointers to foreign libraries * out of the question. What cosmo_dlopen() can do is help you talk to
* safely. Foreign libraries also can't link symbols defined by your * GPU and GUI libraries like CUDA and SDL.
* executable; that means using this for high-level language plugins is
* completely out of the question. What cosmo_dlopen() can do is help
* you talk to GPU and GUI libraries like CUDA and SDL.
* *
* @param mode is a bitmask that can contain: * @param mode is a bitmask that can contain:
* - `RTLD_LOCAL` (default) * - `RTLD_LOCAL` (default)
@ -818,8 +815,26 @@ void *cosmo_dlopen(const char *path, int mode) {
/** /**
* Obtains address of symbol from dynamic shared object. * Obtains address of symbol from dynamic shared object.
* *
* On Windows you can only use this to lookup function addresses. * WARNING: You almost always want to say this:
* Returned functions are trampolined to conform to System V ABI. *
* pFunction = cosmo_dltramp(cosmo_dlsym(dso, "function"));
*
* That will generate code at runtime for automatically translating to
* Microsoft's x64 calling convention when appropriate. However the
* automated solution doesn't always work. For example, the prototype:
*
* void func(int, float);
*
* Won't be translated correctly, due to the differences in ABI. We're
* able to smooth over most of them, but that's just one of several
* examples where we can't. A good rule of thumb is:
*
* - More than four float/double args is problematic
* - Having both integral and floating point parameters is bad
*
* For those kinds of functions, you need to translate the ABI by hand.
* This can be accomplished using the GCC `__ms_abi__` attribute, where
* you'd have two function pointer types branched upon `IsWindows()`.
* *
* @param handle was opened by dlopen() * @param handle was opened by dlopen()
* @return address of symbol, or NULL w/ dlerror() * @return address of symbol, or NULL w/ dlerror()
@ -829,16 +844,12 @@ void *cosmo_dlsym(void *handle, const char *name) {
if (IsWindows()) { if (IsWindows()) {
func = dlsym_nt(handle, name); func = dlsym_nt(handle, name);
} else if (IsXnuSilicon()) { } else if (IsXnuSilicon()) {
if ((func = __syslib->__dlsym(handle, name))) { func = __syslib->__dlsym(handle, name);
func = foreign_thunk_sysv(func);
}
} else if (IsXnu()) { } else if (IsXnu()) {
dlerror_set("dlopen() isn't supported on x86-64 MacOS"); dlerror_set("dlopen() isn't supported on x86-64 MacOS");
func = 0; func = 0;
} else if (foreign_init()) { } else if (foreign_init()) {
if ((func = __foreign.dlsym(handle, name))) { func = __foreign.dlsym(handle, name);
func = foreign_thunk_sysv(func);
}
} else { } else {
func = 0; func = 0;
} }