Extern "C" and Wasm with C dependency

I'm surprised this happens.

One trick I've used in the past to introduce a "seam" for dependency injection is to declare some extern "Rust" functions that are used in a shared crate high up in the dependency tree, but only provide their #[no_mangle] extern "Rust" implementations in the leaf crate that is being compiled to WebAssembly. Effectively leaving the linker to wire up dependency injection for me.

This always worked correctly every time, and the linker was always able to see that the symbols for __proc_block_metadata() and friends being used by the shared crate were being provided by the leaf crate.

From the outside, my setup should look pretty much identical to what ring is doing, except my code was pure Rust and using extern "Rust", while ring is using extern "C" and a WebAssembly object file that came from a C compiler.

Maybe the linker is somehow not "seeing" the ring-xous library as something that can provide your symbols, so it assumes they'll be provided by the runtime (env)? I dunno, it's weird...

The #[link(...)] attribute explicitly tells the compiler/linker "these symbols will be provided by my_c_library" instead of the default behaviour of looking for the symbols in all the libraries you are linking with.

Maybe have a play around and see if that fixes the "seeing" issue I mentioned?

I'd be careful with this. Both the caller and the callee need to use the same calling convention, so if you only removed the extern "C" from one side you might have set yourself up for a bad time.

You might get away with most simple functions because WebAssembly is more "strongly typed" than x86 assembly (arguments are explicitly specified in a function call instead of making implicit assumptions about the stack's state, etc.), but more complex functions could open you up to some weird errors when loading the WebAssembly module.

2 Likes