WABT install! :Converting WebAssembly text format to wasm
Let's have a go at converting the above .wat
text representation example into .wasm
assembly format.
ref: wasmのtutorial備忘録。
- To start with, make a copy of the above listing inside a text file; call it
simple.wat
.
simple.wat
(module
(func $i (import "imports" "imported_func") (param i32))
(func (export "exported_func")
i32.const 42
call $i
)
)
(module
;; imported_func という名前の関数を imports というモジュールからインポートし、$1に格納している。
;; このimported_func関数の引数として渡す型は32ビット整数
(func $i (import "imports" "imported_func") (param i32))
;; exported_func という名称で関数をエクスポートする。これをWebアプリ上から利用する形となる
;; 以下ネストしている部分はexported_func内の処理
(func (export "exported_func")
;; 32ビット整数を(ここでは42)を定義してスタックにプッシュしている
i32.const 42
;; $1(つまりimported_func関数)を実行する。さきほどpushした42が引数として渡される
call $i
)
)
- We need to assemble this textual representation into the assembly language the browser actually reads before we can use it. To do this, we can use the wabt tool, which includes compilers to convert between WebAssembly's text representation and wasm, and vice versa, plus more besides. Go to https://github.com/webassembly/wabt — follow the instructions on this page to set up the tool.
WABT: The WebAssembly Binary Toolkit
Cloning
Clone as normal, but don't forget to get the submodules as well:
$ git clone --recursive https://github.com/WebAssembly/wabt $ cd wabt $ git submodule update --init
This will fetch the testsuite and gtest repos, which are needed for some tests.
Building using CMake directly (Linux and macOS)
You'll need CMake. You can then run CMake, the normal way:
$ mkdir build $ cd build $ cmake .. $ cmake --build .
This will produce build files using CMake's default build generator. Read the CMake documentation for more information.
NOTE: You must create a separate directory for the build artifacts (e.g. build
above). Running cmake
from the repo root directory will not work since the build produces an executable called wasm2c
which conflicts with the wasm2c
directory.
cmake .. でerror
┌─(~/dev/wat_test/build)────────┐
└─(21:32:56 on main ✖ ✹ ✭)──> cmake .. ──(Tue,May16)─┘
CMake Warning:
Ignoring extra path from command line:
".."
CMake Error: The source directory "/Users/$HOME/dev/wat_test" does not appear to contain CMakeLists.txt.
Specify --help for usage, or press the help button on the CMake GUI.
- cMakeについて勉強するならここ
cmake Errorあっさり解決!⇒ cloneしたwabtの下(inside)でbuildする必要があったのね…
┌─(~)───────────────────────────┐
└─(22:16:05 on main ✖ ✹ ✭)──> cd devtool ──(Tue,May16)─┘
┌─(~/devtool)───────────────────┐
└─(22:16:11 on main ✖ ✹ ✭)──> cd wabt ──(Tue,May16)─┘
┌─(~/devtool/wabt)──────────────┐
└─(22:16:16 on main)──> mkdir build ──(Tue,May16)─┘
┌─(~/devtool/wabt)──────────────┐
└─(22:16:36 on main)──> cd build ──(Tue,May16)─┘
┌─(~/devtool/wabt/build)────────┐
└─(22:16:41 on main)──> cmake .. ──(Tue,May16)─┘
-- The C compiler identification is AppleClang 14.0.0.14000029
-- The CXX compiler identification is AppleClang 14.0.0.14000029
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /Applications/Xcode.app/Contents/Developer/usr/bin/gcc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /Applications/Xcode.app/Contents/Developer/usr/bin/g++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found Git: /usr/local/bin/git (found version "2.40.0")
-- Looking for alloca.h
-- Looking for alloca.h - found
-- Looking for unistd.h
-- Looking for unistd.h - found
-- Looking for snprintf
-- Looking for snprintf - found
-- Looking for strcasecmp
-- Looking for strcasecmp - found
-- Looking for sys/types.h
-- Looking for sys/types.h - found
-- Looking for stdint.h
-- Looking for stdint.h - found
-- Looking for stddef.h
-- Looking for stddef.h - found
-- Check size of ssize_t
-- Check size of ssize_t - done
-- Check size of size_t
-- Check size of size_t - done
-- Looking for __i386__
-- Looking for __i386__ - not found
-- Looking for __SSE2_MATH__
-- Looking for __SSE2_MATH__ - found
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Success
-- Found Threads: TRUE
-- Found PythonInterp: /usr/local/bin/python3 (found suitable version "3.11.3", minimum required is "3.5")
-- Configuring done (17.2s)
-- Generating done (0.2s)
-- Build files have been written to: /Users/$HOME/devtool/wabt/build
# wabt このpathの書き方は今までよりもimprove
export WABT_BIN="/Users/$HOME/devtool/wabt/bin"
export PATH=$PATH:$WABT_BIN
wabtの各コマンドが実行できるようになった。
┌─(~/devtool/wabt/build)────────┐
└─(22:22:39 on main)──> wasm2wat --version ──(Tue,May16)─┘
1.0.32
- Once you've got the tool built, add the
/wabt/out/clang/Debug
directory to your systemPATH
.
参照blogがやってなかったから省略してしまいました
4.Next, execute the wat2wasm program, passing it the path to the input file, followed by an -o
parameter, followed by the path to the output file:
wasm file作れた!わーい
┌─(~/dev/wat_test)──────────────┐
└─(23:12:42 on main ✖ ✹ ✭)──> wat2wasm simple.wat -o simple.wasm
┌─(~/dev/wat_test)──────────────┐
└─(23:14:06 on main ✖ ✹ ✭)──> ls ──(Tue,May16)─┘
build simple.wasm simple.wat
This will convert the wasm into a file called simple.wasm
, which contains the .wasm
assembly code.
Note: You can also convert the assembly back into the text representation using the wasm2wat tool; for example wasm2wat simple.wasm -o text.wat
.
┌─(~/dev/wat_test)──────────────┐
└─(23:14:10 on main ✖ ✹ ✭)──> wasm2wat simple.wasm -o text.wat ──(Tue,May16)─┘
┌─(~/dev/wat_test)──────────────┐
└─(23:17:54 on main ✖ ✹ ✭)──> ls ──(Tue,May16
build simple.wasm simple.wat text.wat
Viewing the assembly output
Because the output file is assembly-based, it can't be viewed in a normal text editor. However, you can view it using the wat2wasm tool's -v
option. Try this:
wat2wasm simple.wat -v
┌─(~/dev/wat_test)──────────────┐
└─(23:24:56 on main)──> wat2wasm simple.wat -v ──(Tue,May16)─┘
0000000: 0061 736d ; WASM_BINARY_MAGIC
0000004: 0100 0000 ; WASM_BINARY_VERSION
; section "Type" (1)
0000008: 01 ; section code
0000009: 00 ; section size (guess)
000000a: 02 ; num types
; func type 0
000000b: 60 ; func
000000c: 01 ; num params
000000d: 7f ; i32
000000e: 00 ; num results
; func type 1
000000f: 60 ; func
0000010: 00 ; num params
0000011: 00 ; num results
0000009: 08 ; FIXUP section size
; section "Import" (2)
0000012: 02 ; section code
0000013: 00 ; section size (guess)
0000014: 01 ; num imports
; import header 0
0000015: 07 ; string length
0000016: 696d 706f 7274 73 imports ; import module name
000001d: 0d ; string length
000001e: 696d 706f 7274 6564 5f66 756e 63 imported_func ; import field name
000002b: 00 ; import kind
000002c: 00 ; import signature index
0000013: 19 ; FIXUP section size
; section "Function" (3)
000002d: 03 ; section code
000002e: 00 ; section size (guess)
000002f: 01 ; num functions
0000030: 01 ; function 0 signature index
000002e: 02 ; FIXUP section size
; section "Export" (7)
0000031: 07 ; section code
0000032: 00 ; section size (guess)
0000033: 01 ; num exports
0000034: 0d ; string length
0000035: 6578 706f 7274 6564 5f66 756e 63 exported_func ; export name
0000042: 00 ; export kind
0000043: 01 ; export func index
0000032: 11 ; FIXUP section size
; section "Code" (10)
0000044: 0a ; section code
0000045: 00 ; section size (guess)
0000046: 01 ; num functions
; function body 0
0000047: 00 ; func body size (guess)
0000048: 00 ; local decl count
0000049: 41 ; i32.const
000004a: 2a ; i32 literal
000004b: 10 ; call
000004c: 00 ; function index
000004d: 0b ; end
0000047: 06 ; FIXUP func body size
0000045: 08 ; FIXUP section size
- Magic Number and Version:
- The first four bytes are the magic number
0061736D
, indicating the start of a Wasm binary. - The next four bytes
01000000
represent the Wasm binary version number.
- The first four bytes are the magic number
- Section "Type" (1):
- The section code is
01
, indicating that this is the "Type" section. - The section size is
00
(guess). - This section defines function types.
- There are two function types defined in this example.
- Function Type 0:
- It specifies a function with one parameter of type
i32
(signed 32-bit integer) and no results.
- It specifies a function with one parameter of type
- Function Type 1:
- It specifies a function with no parameters and no results.
- The section code is
- Section "Import" (2):
- The section code is
02
, indicating that this is the "Import" section. - The section size is
00
(guess). - This section defines imported functions.
- Import Header 0:
- The import module name is "imports" (length: 7 characters).
- The import field name is "imported_func" (length: 13 characters).
- The import kind is
00
, representing a function import. - The import signature index is
00
, referring to Function Type 0.
- The section code is
- Section "Function" (3):
- The section code is
03
, indicating that this is the "Function" section. - The section size is
00
(guess). - This section defines the functions present in the module.
- Function 0:
- It has a signature index of
01
, referring to Function Type 1.
- It has a signature index of
- The section code is
- Section "Export" (7):
- The section code is
07
, indicating that this is the "Export" section. - The section size is
00
(guess). - This section defines the exports of the module.
- Export 0:
- The export name is "exported_func" (length: 13 characters).
- The export kind is
00
, representing a function export. - The export function index is
01
, referring to Function 0.
- The section code is
- Section "Code" (10):
- The section code is
0a
, indicating that this is the "Code" section. - The section size is
00
(guess). - This section contains the actual function code.
- Function Body 0:
- The function body size is
00
(guess). - There are no local declarations.
- The function body contains the following instructions:
i32.const 2a
: Pushes the value42
(hexadecimal2a
) onto the stack.call 00
: Calls the function at index00
(imported_func).end
: Ends the function body.
- The function body size is
- The section code is
Note that the section sizes are initially marked as 00
and later fixed up based on the actual sizes of the sections.
This is a simplified representation of a Wasm file in a textual format. In its actual binary form, it would consist of bytes representing the instructions and their corresponding values.
WAT上で定義した imported_func
部分は上のコードでは importedFunc
として定義している。これを imported_func
としてimportし、wasm側に渡している。
ローカルでサーバを立ち上げてsimple.html
に実行することでブラウザのコンソール上に num: 42
という数値が表示されるのを確認した。
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Simple wasm example</title>
</head>
<body>
<script>
const importedFunc = (num) => console.log("num: ", + num);
WebAssembly.instantiateStreaming(fetch("simple.wasm"), {imports : { imported_func: importedFunc }})
.then(obj => {
obj.instance.exports.exported_func();
});
</script>
</body>
</html>
これ表示されてないけど保留で!
このwabt install成功したからemscriptenの実行error解決にもう一度tryしてみよう。