WebAssembly Custom Section を書き出す
インラインアセンブリでの、.custom_section で始まるセクションが WebAssembly Custom Section として出力される。
C/C++ ソースコードでは __attribute__((section(".custom_section.(任意の名前)")))
と同等のはずだが、これで修飾したセクションは WebAssembly Data Section に乗ってしまうため、C/C++ の範囲での記述方法はない。
インラインアセンブリ
.section .custom_section.my_data,"",@
.asciz "Hello, WebAssembly"
出力
(module
;; custom section "my_data", size 19
)
WebAssembly ネイティブな setjmp/longjmp
コンパイルフラグに -mllvm -wasm-enable-sjlj
を追加することで、setjmp/longjmp を WebAssembly Exception Handling にマッピングするコードを出力できる。
emscripten では JavaScript での例外処理/setjmp/longjmp を無効化する必要があるので、コンパイルフラグに -sSUPPORT_LONGJMP=wasm -sDISABLE_EXCEPTION_THROWING=1
を指定する。
ソース
# include <stdio.h>
# include <setjmp.h>
jmp_buf t;
void test() {
longjmp(t, 1);
}
int main() {
if (setjmp(t) == 0) {
test();
} else {
printf("Jumped!\n");
}
return 0;
}
参照
extenref/funcref を使う
extenref/funcref はそれぞれ __externref_t
と __funcref
を修飾した関数ポインタにマッピングされている。
externref
__attribute__((import_name("receive_object")))
__externref_t receive_object(void);
__attribute__((import_name("send_object")))
void send_object(__externref_t);
int main() {
send_object(receive_object());
return 0;
}
funcref
using main_fp_t = int (*__funcref)();
int main() {
return 0;
}
__attribute__((used))
extern "C" main_fp_t exportMainAsFuncRef() {
// WebAssembly での関数ポインタの正体は WebAssembly Table Index
auto main_fp = &main;
__asm(R"(
local.get %0
table.get __indirect_function_table
return
)"
: : "r"(main_fp));
}
なお、関数ポインタを直接 funcref に変換することはできない模様。
__attribute__((used))
extern "C" main_fp_t exportMainAsFuncRef() {
return (main_fp_t)&main;
}
// Cannot select: 0x2004f5a0ad8: funcref = addrspacecast[0 -> 20]
WebAssembly Table を定義する
C/Cpp
// static で 0 サイズな __externref_t のグローバル変数の配列が WebAssembly Table になる
static __externref_t table[0];
// 組み込み関数も用意されている
__builtin_wasm_table_grow(table, __builtin_wasm_ref_null_extern(), 1);
アセンブリ
subtable:
.global subtable
.tabletype subtable, funcref, 1
clang/emscripten を使ってできないこと
- start function の指定