Stream: general

Topic: Linkers, module instantiations and default functions


view this post on Zulip Alexandru Ene (Jun 25 2020 at 12:58):

Hello,

We have a way to use a linker to add a WASI module.
However, from what I can tell this method: wasmtime_linker_module(linker, &empty, _module) magically instantiates the module.
As it is shown in the wasi.c example, calling the default method just works, without having a module instance.
https://github.com/bytecodealliance/wasmtime/blob/3715e19c67ab7e59fadf750a1de2ba48f1e6f4ce/examples/wasi/main.c#L84

I didn't manage to find a way on how to tell what the default method is (it seems to be fn main() ) for a main.rs compiled with cargo build --target wasm32-wasi. But in case of a lib that has a:

#[no_mangle]
pub extern "C" fn main() {`

This main is not considered a default method. That's fine. It's surprising that I could call in a function returned by wasmtime_linker_get_default that is non-null in my lib case. So who knows what that called into, but it's not my main function :D.

That being said, I would like to get my exports and find the fn main() somwhere in the export list. Is there some example code somewhere that can show me how this is done?

Also would calling wasmtime_linker_instantiate(...) instantiate my module twice? (as wasmtime_linker_module seems to do that already).

I've found:

    wasm_extern_vec_t externs;
    wasm_instance_exports(instance, &externs);
    assert(externs.size == 1);
    wasm_func_t *gcd = wasm_extern_as_func(externs.data[0]);
    assert(gcd != NULL);

But these are some opaque data structures and I can't tell what the names of the methods are.

Standalone JIT-style runtime for WebAssembly, using Cranelift - bytecodealliance/wasmtime

view this post on Zulip Jakub Konka (Jun 25 2020 at 13:06):

I'd love to know the answer to it as well for my pet project wasmtime-zig. From some prelim research, but @Alex Crichton can correct me here, I think we could search for an export by name using wasmtime_caller_export_get. As far as an example is concerned, I'm following @Alex Crichton's excellent wasmtime-go integration. In particular, here's the shim which wraps wasmtime_caller_export_get in Go: https://github.com/bytecodealliance/wasmtime-go/blob/main/shims.c#L28 Is that what you're after BTW?

Zig embedding of Wasmtime. Contribute to kubkon/wasmtime-zig development by creating an account on GitHub.
Go WebAssembly runtime powered by Wasmtime. Contribute to bytecodealliance/wasmtime-go development by creating an account on GitHub.
Go WebAssembly runtime powered by Wasmtime. Contribute to bytecodealliance/wasmtime-go development by creating an account on GitHub.

view this post on Zulip Alexandru Ene (Jun 25 2020 at 13:12):

How did you create the wasmtime_caller_t*?
What I tried was:

    wasm_func_t* func = nullptr;
    wasm_name_t name;
    wasm_name_new_from_string(&name, "main");
    auto error = wasmtime_linker_get_default(_linker, &empty, &func);

This gets me back a method, but I am almost certain it's not the correct one, as it doesn't print anything and doesn't trigger any breakdpoint in the rust code that was used to compile it.

The interesting thing is that using any random string in wam_name_new_from_string(&name, "randomstuff");, is absolutely fine and I do still get a func back that's not nullptr that I can call with wasmtime_func_call(

view this post on Zulip Alexandru Ene (Jun 25 2020 at 13:49):

Oh, wait, that name is not the function name, but the module name from where the _default_ function is returned.

It's not nullptr as the default is (in linker.rs):

        // Otherwise return a no-op function.
        Ok(Func::new(
            &self.store,
            FuncType::new(Vec::new().into_boxed_slice(), Vec::new().into_boxed_slice()),
            move |_, _, _| Ok(()),
        ))

view this post on Zulip Alex Crichton (Jun 25 2020 at 14:02):

@Alexandru Ene FWIW dealing with the "default export" is mostly for wasi things

view this post on Zulip Alex Crichton (Jun 25 2020 at 14:02):

if your modules use wasi then you'll want to use that, otherwise you'll likely want to use the wasmtime_linker_instantiate API to get an instance back out

view this post on Zulip Alex Crichton (Jun 25 2020 at 14:03):

otherwise there's Rust APIs for getting items from a Linker, but they may not be bound in the C API yet

view this post on Zulip Alexandru Ene (Jun 25 2020 at 14:06):

So I want to have a method, that works with WASI and can have a way of returning wasm_func_t functions for things I marked as "extern C" in rust (the thing that's compiled to WASM).

It's fine for now to say that it needs to be a main() from a rust binary. But I am not sure how to extract from a module functions that need WASI and a linker.

I would have expected that get_function to return nullptr if it's not found tho, it's slightly confusing it returns a no-op

view this post on Zulip Alex Crichton (Jun 25 2020 at 14:14):

@Alexandru Ene the simplest thing to do today would be to make a wasmtime_linker_t, add wasi to it, then call wasmtime_linker_instantiate to get a wasm_instance_t

view this post on Zulip Alex Crichton (Jun 25 2020 at 14:14):

then you can iterate over the exports and work with the module

view this post on Zulip Alex Crichton (Jun 25 2020 at 14:15):

that doesn't handle the reactor/command difference right now, but that's a relatively new concept and may not need to be handled by you just yet

view this post on Zulip Alexandru Ene (Jun 25 2020 at 14:16):

That seems great. I wasn't sure if wasmtime_linker_instantiate would duplicate the instance as wasmtime_linker_module seems to create an instance under the hood (without exposing it to C)

view this post on Zulip Alexandru Ene (Jun 25 2020 at 14:16):

Thanks for all the help Alex

view this post on Zulip Alex Crichton (Jun 25 2020 at 14:18):

oh it would duplicate the instance

view this post on Zulip Alex Crichton (Jun 25 2020 at 14:18):

wasmtime_linker_module registers a module to be instantiated by the linker automatically under a given name

view this post on Zulip Alex Crichton (Jun 25 2020 at 14:19):

whereas wasmtime_linker_instantiate will create a new instance and return it, not registering anything with the linker

view this post on Zulip Alexandru Ene (Jun 25 2020 at 14:21):

Oh great then. Like this it does exactly what i need. I thought the call to wasmtime_linker_module was mandatory. If I can use linker_instrantiate instead it's perfect

view this post on Zulip Alex Crichton (Jun 25 2020 at 14:21):

ah yeah wasmtime_linker_module is just optional!

view this post on Zulip Alexandru Ene (Jun 25 2020 at 14:39):

As for linker.rs, get_default(), it should probably return an Err() if there's no default method, having a no-op as the default makes kind of hard on the users of the library to figure out why things don't work as expected and there are probably not so many cases when that's actually desirable (running a no-op method).
The signature is already pub fn get_default(&self, module: &str) -> Result<Func> {


Last updated: Dec 23 2024 at 12:05 UTC