Stream: wasmtime

Topic: exporting a rust fn


view this post on Zulip Adam Carter (May 15 2020 at 22:32):

Good evening, folks - Is it possible to export a rust fn and consume it through wasmtime? I tried doing so through with wasm-bindgen? I tried doing so but I am getting an error. Ultimately, I'd like to export a functions from wasm modules and link them together - similar to the linking example but using rust instead of the text format.

Thanks!

view this post on Zulip Alex Crichton (May 18 2020 at 13:51):

@Adam Carter you likely won't want to use wasm-bindgen with wasmtime since wasm-bindgen is targeted at web environments, for exporting a Rust function you should be able to use #[no_mangle] to get an exported function which you can call

view this post on Zulip Adam Carter (May 19 2020 at 11:59):

Thanks, @Alex Crichton. So, I have an error returning a string from a rust function. My steps are:

given the following

#[no_mangle]
pub extern "C" fn greet() -> String {
format!("Hello, world!")
}

When I run cargo wasi build and wasmtime --invoke greet target/wasm32-wasi/debug/wasi_example.wasi.wasm I get the following output

**Error: failed to run main module target/wasm32-wasi/debug/wasi_example.wasi.wasm

Caused by:
multiple tables: tables count must be at most 1 (at offset 376)**

view this post on Zulip Adam Carter (May 19 2020 at 12:00):

Removed duplicate message (this UI is confusing lol)

view this post on Zulip Alex Crichton (May 19 2020 at 14:02):

@Adam Carter hm do you still have wasm-bindgen in your dependency graph? You may need to remove that because if that runs it uses anyref

view this post on Zulip Adam Carter (May 21 2020 at 12:30):

Thanks @Alex Crichton. That was indeed the issue. I still wasn't able to get --invoke. The generated wat shows that greet takes two arguments (instead of none).

(module
(type $t0 (func (param i32)))
(func $greet (type $t0) (param $p0 i32)
(local $l1 i32) (local $l2 i32)
(local.set $l1
(i32.const 12))
(i32.store offset=4
(local.get $p0)
(local.get $l1))
(local.set $l2
(i32.const 1048576))
(i32.store
(local.get $p0)
(local.get $l2))
(return))
(table $T0 1 1 funcref)
(memory $memory 17)
(global $g0 (mut i32) (i32.const 1048576))
(global $__data_end i32 (i32.const 1048588))
(global $__heap_base i32 (i32.const 1048588))
(export "memory" (memory 0))
(export "greet" (func $greet))
(export "__data_end" (global 1))
(export "__heap_base" (global 2))
(data $d0 (i32.const 1048576) "Hello, World"))

Do you know why this is? What would the correct parameters be when calling this function from either --invoke or from rust?

view this post on Zulip Yury Delendik (May 21 2020 at 13:39):

Did you mean to say one: (func $greet (type $t0) (param $p0 i32)

view this post on Zulip Yury Delendik (May 21 2020 at 13:41):

It is an output param-reference to "String" which gets assigned by (i32.store (local.get $p0) (local.get $l2))at the end

view this post on Zulip Yury Delendik (May 21 2020 at 13:45):

you have to --invoke with offset/reference into wasm memory

view this post on Zulip Alex Crichton (May 21 2020 at 14:08):

yes String in Rust doesn't have a stable ABI, so it does "whatever is necessary". In this case the first parameter is a pointer of where to write the string

view this post on Zulip Alex Crichton (May 21 2020 at 14:09):

that's probably not what you want but unfortunately returning a string isn't easy right now. Interface types should improve the situation!

view this post on Zulip Adam Carter (May 21 2020 at 15:07):

Ok, that makes sense! Thank you all!


Last updated: Oct 23 2024 at 20:03 UTC