Hey! I am trying to experiment with strings, but whenever I use the code I get a Failed to link module error.
The code that I am using is:
#[no_mangle]
pub extern "C" fn __modlib_return_string(ptr: *const u8, len: usize) -> *mut c_char {
let string: String = String::from("Returning a string");
let cstr = CString::new(string).unwrap();
cstr.into_raw()
}
Could anyone explain what am I doing wrong?
Is this extern "C" function host code that's called from wasm code?
@Dan Gohman this function is compiled to wasm code and called externally from the host using wasmtime.
It's probably also worth mentioning that the error is Link error: wasi_snapshot_preview1/fd_write
I was going to guess that the error was because you're passing a pointer argument. This will need to be translated from a wasm pointer, which is 32-bit and relative to the wasm linear memory, to a host pointer, which I assume is 64-bit for you.
But I don't know what would cause an fd_write link error. Can you show the code that calls fd_write?
@Dan Gohman I kind of changed the example now. Nevertheless I am still getting the same error.
The module code (it basically tries to call a function from a host which loads another module). It also had to be wrapped in unsafe as without it the compiler spits out errors.
#[link(wasm_import_module = "env")]
extern "C" {
pub fn load(name: i32) -> i32;
}
#[no_mangle]
pub extern "C" fn __modlib_memory() {
unsafe {
load(0);
}
}
And the load function in the host is:
pub fn load(name: i32) -> i32 {
let store = Store::default();
let mod_name = format!("{}.{}", name, "wasm");
let module = Module::from_file(&store, mod_name).expect("Cannot load a module");
let instance = Instance::new(&module, &[]).expect("Cannot instantiate a module");
instances.with(|mut i| {
let new_instance = ModuleInstance::new(name, instance);
(*i.borrow_mut()).lock().unwrap().push(new_instance);
});
// Success.
return 0;
}
It's a bit of a hacky code, but I suppose the error is in the modules themselves rather than in main, but of course I might be wrong.
This code calls another module, but that module is super simple without any returns and with one line of println!("OK")
I also saw this issue. Not sure if it's relevant in this case.
Oh and instances is just a:
thread_local!(static instances: Mutex<Vec<ModuleInstance>> = Mutex::new(Vec::new()));
@daubaris it looks like you're compiling for the wasm32-wasi target which requires wasi imports to be satisfied. For that you'll need to pull in the wasmtime-wasi crate and iterate over the module exports to hook them up to wasi functions. If you want to generate a wasm module that doesn't have wasi imports you'll want to use the wasm32-unknown-unknown target. The fd_write intrinsic here is most likely showing up because of panics, which trigger writes to stderr
@Alex Crichton Oooh, okay. By the way, about hooking up the exports, I assume you are talking about this repository. I am a bit puzzled on how this "hooking up" is done, any hints?
@daubaris oh it sort of depends, are you using the wasmtime crate or the C API?
I am using wasmtime crate.
Ah the hooking up happens in Instance::new w
which has docs about what the imports argument there is
and for wasi you'd be using the wasmtime_wasi crate
and namely the get_export method
Hmmm, in the previously mentioned example, I already had the Instance::new, but the problem is that load is being called in the module itself
I think I get the idea. I'll try it out and report how it goes :+1: thanks for the help!
Last updated: Dec 06 2025 at 06:05 UTC