问题
我已经启动并运行了wasmtime
,从Rust主机调用TinyGo WASM/WASI模块。一切都很好,直到我尝试从Go WASI模块返回一个字符串,这似乎是每个人都在努力的事情。我理解在特定位置访问WASM模块的内存并阅读特定长度的概念;我不明白的是如何用offset
来代替指针。
我在想,对wasmtime
自己的example from their docs的澄清可能会为我指明正确的方向:
use wasmtime::{Memory, Store, MemoryAccessError};
fn safe_examples(mem: Memory, store: &mut Store<()>) -> Result<(), MemoryAccessError> {
let offset = 5;
mem.write(&mut *store, offset, b"hello")?;
let mut buffer = [0u8; 5];
mem.read(&store, offset, &mut buffer)?;
assert_eq!(b"hello", &buffer);
assert_eq!(&mem.data(&store)[offset..offset + 5], b"hello");
mem.data_mut(&mut *store)[offset..offset + 5].copy_from_slice(b"bye!!");
Ok(())
}
字符串
常见问题
1.什么是offset
?我的印象是它不是一个指针地址,而是从WASM模块的内存开始的usize偏移量。
1.假设这是正确的,我如何得到一个特定变量的偏移量?我看到了很多例子,其中一个随机值(比如5
或10
),但在我自己的例子中,任何大于0 segfaults。我想我可能误解了offset
是什么。
1.共享的WASM内存需要由主机分配吗?我的假设是WASM模块本身会自然地扩展自己的内存(就像它在本机运行时一样)。如果我必须在主机上分配内存,如果是WASM模块创建了使用内存的变量,我如何确定要分配多少内存?
1条答案
按热度按时间ldfqzlk81#
关于您的问题
1.是的,
offset
是从WASM内存开始的偏移量。它就像WASM内存中的指针。试图在主机Rust应用程序中访问offset
作为正常指针可能会导致segfault。1.宿主Rust应用程序的变量与WASM内存分离。它们不会自动成为WASM内存内容的一部分。这就是WASM的全部技巧。所有内容都必须显式复制到WASM内存中,或者从WASM内存中读取并写入宿主应用程序的变量。
1.如果您需要WASM示例内部的内存,您必须手动分配它,例如使用导出的
malloc()
函数(稍后详细介绍)。对于每次分配,您需要知道需要多少字节。如何从TinyGo WASM模块中读取字符串
(ptr, len)
元组。1.由于返回非平凡类型是一个相当新的特性[2],TinyGo使用了一种解决方法(可能是为了向后兼容):它不是返回
(ptr, len)
元组,而是要求 * 你 * 传递一个指向空闲内存段/缓冲区的指针,在那里它可以存储(ptr, len)
元组。因为ptr
和len
是i32
类型,你需要传递一个8字节的缓冲区。1.从哪里获取缓冲区?首先需要分配它,这必须发生在WASM内存中,所以需要调用模块的导出
malloc
函数。1.现在您可以调用返回字符串的函数,同时将缓冲区作为参数传递。
1.然后必须从WASM内存中读取
(ptr, len)
元组。1.最后,从WASM内存中读取
[ptr..ptr+len]
,并将字节转换为Rust String。一个简单的例子:
1.创建一个基本的TinyGo WASM模块,导出一个返回字符串的函数:
字符串
使用TinyGo将其编译为WASM:
tinygo build -o return_string.wasm -target wasm ./return_string.go
型
输出量:
型