为何每个导出的WASM函数都会调用全局对象的构造函数?
问题原因
你遇到的重复调用全局构造函数的问题,是wasm-ld默认行为和当前编译参数共同导致的:
- 你使用了
--no-entry参数指定无传统入口函数,wasm-ld在该模式下默认会在所有导出函数的开头插入全局构造函数调用桩,兜底保证导出函数执行前全局状态已经完成初始化 - 你添加了
--no-standard-libraries参数,跳过了编译器自带WASM运行时启动文件的链接,而启动文件中本来包含构造函数仅执行一次的守卫逻辑,最终导致每个导出函数执行时都会直接触发全局构造函数调用。
解决方案
可以通过添加clang/链接器参数实现构造函数调用时机的完全控制,不需要修改业务代码:
- 给链接器添加
-Wl,--no-call-ctors-on-exports参数,直接关闭「向所有导出函数开头自动插入构造调用桩」的默认行为 - 给链接器添加
-Wl,--export=__wasm_call_ctors参数,导出链接器自动生成的全局构造统一入口函数__wasm_call_ctors,该函数会按正确顺序执行所有全局对象的构造函数,且自带仅执行一次的守卫逻辑,重复调用不会重复执行构造。
修改后的完整编译命令参考:
clang++ \ -Wall \ --target=wasm32 \ -Ofast \ -flto \ --no-standard-libraries \ -Wl,--export=init \ -Wl,--export=update \ -Wl,--export=uninit \ -Wl,--no-entry \ -Wl,--lto-O3 \ -Wl,-allow-undefined-file=wasm.syms \ -Wl,--import-memory \ -Wl,--no-call-ctors-on-exports \ -Wl,--export=__wasm_call_ctors \ -o ./bin/main.wasm \ -I./src \ ./src/lib.cpp \ ./src/main.cpp
调用方式
在JS侧完成WASM模块实例化后,先主动调用一次__wasm_call_ctors完成全局初始化,之后再正常调用init/update/uninit即可,全局对象t的构造函数仅会在你调用__wasm_call_ctors时执行一次,不会再出现在导出函数中重复触发的问题。
如果不希望在JS侧做额外调用,也可以在
init函数的最开头手动调用一次__wasm_call_ctors,依靠该函数自带的一次性守卫保证构造逻辑仅执行一次。
内容的提问来源于stack exchange,提问作者Woowoo
相关产品推荐
相关产品推荐

