最近,我尝试使用尽可能少的助手来尝试 WebAssembly。
所以我创建了 ac 项目,包含一些库(stb_image.h)并尝试编译它。
这是一个简短的可重现示例:
#include <emscripten.h>
#define STBI_NO_STDIO
#define STBI_NO_FAILURE_STRINGS
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
EMSCRIPTEN_KEEPALIVE
void test(){
stbi_load_from_memory(NULL, 0, NULL, NULL, NULL, 0);
}
Run Code Online (Sandbox Code Playgroud)
这是我使用的命令:
emcc converter.c -s STANDALONE_WASM -o converter.wasm --no-entry
这工作正常并给了我一个有效的 wasm 文件。
但后来我尝试使用 javascript 在浏览器中实例化它,而不使用其他任何东西:
let wasm = await Webassembly.instantiateStreaming(fetch('converter.wasm'), {});
Run Code Online (Sandbox Code Playgroud)
但我收到这个错误:
未捕获(承诺中) TypeError: WebAssembly.instantiate(): Import #0 module="wasi_snapshot_preview1" 错误:模块不是对象或函数
我检查了 WebAssembly,确实我的 WebAssembly 需要这些功能:
(func $wasi_snapshot_preview1.fd_close (;0;) (import "wasi_snapshot_preview1" "fd_close") (param i32) (result i32))
(func $wasi_snapshot_preview1.fd_seek (;1;) (import "wasi_snapshot_preview1" "fd_seek") (param i32 i64 i32 …Run Code Online (Sandbox Code Playgroud) (1) 我听说 WebAssembly 通过提供线性内存而安全。我想知道这个线性存储器包含什么?wasm栈和堆是否位于这个内存空间?如果是的话,我认为 wasm 堆栈和粘合代码堆栈(例如 JavaScript、Python 等)是分开的,对吧?
(2)我可以通过使用导入表来了解wasm的内存安全性。换句话说,wasm函数不能调用线性内存之外的任何函数,因为它只能使用索引来调用导入的函数。除此之外,wasm 还提供哪些其他安全功能?可能是上面的堆栈问题。
(3) 看起来wasm中也有控制流完整性。也就是说每个函数的返回地址都是固定的,不能在函数内部修改。这是正确的理解吗?
我想用Cargo-wasi编译以下代码。
// reqwest = { version = "0.11", features = ["json"] }
// tokio = { version = "1", features = ["full"] }
use std::collections::HashMap;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let resp = reqwest::get("https://httpbin.org/ip")
.await?
.json::<HashMap<String, String>>()
.await?;
println!("{:#?}", resp);
Ok(())
}
Run Code Online (Sandbox Code Playgroud)
尝试编译后,出现以下错误,因为mio 目前不支持 WASI
$ cargo wasi run
Compiling mio v0.7.9
Compiling parking_lot v0.11.1
Compiling serde_json v1.0.64
Compiling idna v0.2.2
error[E0432]: unresolved import `crate::sys::IoSourceState`
--> /home/ducaale/.cargo/registry/src/github.com-1ecc6299db9ec823/mio-0.7.9/src/io_source.rs:12:5
|
12 | use crate::sys::IoSourceState;
| …Run Code Online (Sandbox Code Playgroud) 我有一个用 C++ 编写的项目,要部署的平台有 256KB 二进制大小的限制。
工具链是wasi-sdk-16.0 clang++,我们使用这个编译器将源代码编译成WASM格式的二进制文件。在此步骤中,我们使用以下 CXX_FLAGS 编译源代码。
-fstack-protector-strong -Os -D_FORTIFY_SOURCE=2 -fPIC -Wformat -Wformat-security -Wl,-z,relro,-z,now -Wno-psabi
Run Code Online (Sandbox Code Playgroud)
然后我们将strip二进制文件与
strip -s output_binary.wasm
Run Code Online (Sandbox Code Playgroud)
经过上述步骤后,这一步编译出来的二进制文件大小为254KB。
然后我们wamrc在 WAMR 中使用 AOT 运行时编译 WASM 二进制文件,命令如下所示。
wamrc --enable-indirect-mode --disable-llvm-intrinsics -o output.aot output.wasm
Run Code Online (Sandbox Code Playgroud)
输出二进制大小变为 428KB,远大于限制(256KB)。
谷歌搜索后,我用来wasm-opt缩小尺寸,
wasm-opt -Oz output.wasm -o output.wasm
Run Code Online (Sandbox Code Playgroud)
大小变小 4KB。(几乎没用)
我试图确认我的代码对二进制大小的影响有多大,所以我编写了简单的最小示例代码,称为标准 C++ 库,如下所示,
-fstack-protector-strong -Os -D_FORTIFY_SOURCE=2 -fPIC -Wformat -Wformat-security -Wl,-z,relro,-z,now -Wno-psabi
Run Code Online (Sandbox Code Playgroud)
编译后的二进制大小已经变成了205KB。
我还尝试使用二进制大小分析器 ( twiggy) 来跟踪二进制文件每个部分的大小,但该工具无法打开该二进制文件。
所以我想问一下
虽然仅包含两个标准 C++ 头文件会使二进制大小达到大小限制,但如何使用我真正使用的函数剥离 C++ 标准库(我不能使用剥离未使用的函数标志,因为我的项目是提供给其他人的库),或者C++ 标准库真的影响了二进制大小吗?
是否有任何其他编译器标志,或剥离标志,或任何其他优化工具可以显着减少二进制大小?
我知道 clang(通过使用 target=wasm32)和 emscripten 都可以将 C 代码编译成 webassembly,但它们有什么不同?
看起来他们都使用 LLVM 作为后端。其实,我什至不太明白 llvm 和 clang 之间的关系......
我已经阅读了一段时间的 WebAssembly,但我对它缺乏低级理解。非常感谢您的参与!!
我想使用 console.log 的消息进行调试。
我们有一个 rust wasm32-wasi 函数从在 Nodejs 中运行的 JavaScript 调用。由于其他限制,我们无法使用 ssvm/ssvmup。
我们可以做些什么来在控制台中查看来自 wasm 代码的消息吗?