I think the state of the art for that is "provide a WASM glue layer and load plugins as WASM modules with a program-provided execution environment". One big benefit there is that plugins can be isolated from each other as well as from the program as much as is wanted because you don't have to worry about loading some binary-poking native code invalidating assumptions all over the place.
Wasm doesn't always work though. It is not something I worked with myself but as I understand it, SIMD isn't a thing in WASM, nor is things like Vulkan GPU access.
I believe one of the driving use cases is for reloading code in game development, and I fear that Wasm wouldn't be a good solution there.
It also wouldn't work for reloadable drivers in a kernel context, as I believe there is no support for MMIO from WASM. (BPF might be relevant here, at least on Linux, but I'm more interested in the general case for Rust native OSes.)
It is not possible to load a regular dylib that uses TLS with a custom dynamic linker, not even import TLS variables from another library. And the standard library uses TLS in several places and even needs to import TLS variables from libc. The reason TLS is not possible this way is because the format of the TLS area is only know by and fully controlled by the dynamic linker of libc. Importing TLS variables requires getting either the TLS area offset or the TLS module id + TLS module offset, which the dynamic linker doesn't provide an api to get and rather requires you to use relocations in the dynamic library that needs it which get applied when doing dlopen (which is exactly not what we want here). And defining TLS variables ourselves requires rewriting the TLS area which would require knowing the locations of all TLS variables in all loaded dynamic libraries (which we don't) and cause corruption of internal data structures of the libc dynamic linker.
Wasm does have simd128 which is the common subset of the 128bit simd support for all major architectures.
Nothing is stopping you from exporting a function to the wasm module that does an MMIO load or store... Not that that is a great solution however.
Oh that must be new since I last looked at wasm a few years ago. Good to know.
as a MVP perhaps dyn_unload crates would have to be no_std, and it the future there could be a subset of std available for them?
On the C side it might (?) be incompatible. The C standards are a little vague on what types are compatible with void * and what types can be cast to void *. You can definitely cast all pointers-to-objects to void *, but a function pointer is not a pointer-to-object, and is not even guaranteed to be the same size on all architectures. On the other hand, the C standards are clear that all function pointers (regardless of number or type of arguments) can be safely cast to void (*)(void).
Hence, I've seen some C projects that use union TypeErased { void *obj_ptr; void (*fn_ptr)(void); } to be maximally paranoid standard-abiding.
I believe a "subset of std" would have to be its own crate boundary of some kind as any "feature" to disable things would not be an additive thing. But something to consider if dyn_unload and no_std proves useful first.
Yeah, for sure, it would need to be its own sysroot crate, same as core.
Well, for C in general the situation is indeed not clear, but for POSIX, dlsym returns a void *, which you have to cast to a function pointer (if it is a function, which is the common case).
So all POSIX compatible systems habe to allow this. That would be all currently relevant non-embedded systems except for Windows at this point (I suspect this works fine on Windows too, there is no reason it shouldn't on x86-64 or ARM, which are the only platforms Windows currently support).
I'm not sure about the state of function pointers on embedded in general (aren't PIC and AVR both Harvard architecture for example? Though I believe RISCV and ARM Cortex M are more popular for new designs), but generally those systems tend to not allow for loading and unloading code on the fly anyway.
I would argue this is because there is no framework that allows you to easily write unload-safe code. For certain mid-size embedded systems, it actually seems extremely desirable to be able to safely unload and reload certain sub-systems as an alternative to having a whole OS (imagine an embedded kiosk that can switch between 3 different modes, being able to unload the code for inactive modes while they aren't being used would free up memory for the active functionality)
of course, these systems would not use the standard unloading functions, but instead would use a system-specific function (similarly to how Sync and Send are still used on embedded systems, despite needing platform-specific functionality to do anything)
The Win32 function GetProcAddress is effectively the same thing as dlsym except the other way around: it returns a generic function pointer, which you are expected to cast to an object pointer if the thing you looked up is actually a variable. So Windows has to allow casts between function and object pointers as well.
However, there is no obstacle to Rust supporting a hypothetical assembly-level ABI in which function addresses and object addresses are not interconvertible. As I said earlier, we're almost there already: the intent of the "null pointer optimization guarantees" for Option is clearly that transmute::<Option<&T>>(ptr::null<T>()) produces None, for all T, both function and object types, the wording "just" needs to be corrected to actually say that. Then Option<extern "C" fn()> could safely be used as the Rust-side argument type for a function called from C with a nullable callback parameter.
As I said earlier, we're almost there already: the intent of the "null pointer optimization guarantees" for
Optionis clearly thattransmute::<Option<&T>>(ptr::null<T>())producesNone, for all T, both function and object types, the wording "just" needs to be corrected to actually say that. ThenOption<extern "C" fn()>could safely be used as the Rust-side argument type for a function called from C with a nullable callback parameter.
I suggest opening a bug or even PR about this.
This topic was automatically closed 540 days after the last reply. New replies are no longer allowed.