WebAssembly Studio is an online IDE for WASM that allows you to develop complete WASM projects in C/C++, Rust and AssemblyScript (TypeScript subset to generate WASM) in a simple way without installing anything in your workstation.
We are going to use WebAssembly Studio to generate a new version of Hello WebAssembly, this time using the full toolchain of Emscripten.
This section of the tutorial is completly based on WebAssembly Studio's own Hello Wolrd in C tutorial.
Go to WebAssembly Studio and choose Create New Project -> Hello World in C. We are going to print Hello World
in the console, but instead of implementing it using JavaScript's console.log
, we are using the C printf
function. This function in turn uses several POSIX APIs that are implemented in JavaScript using DOM APIs.
There are two main files in the project:
main.c
- Importsstdio.h
and callsprintf("Hello World")
.main.js
- Initializes a runtime environment for the WebAssembly module and implements the necessary WebAssembly imports.
-
Click Build to compile
main.c
file toout/main.wasm
. -
Open the
out/main.wasm
file and notice that there's quite a bit of code. This is somewhat surprising given that our program is so small. The vast majority of this code implements the printf function. -
Notice the imports section, these are
SysCalls
. To get this WebAssembly module running you'll have to implement these functions first. However, note that these import names don't actually tell you whatSysCalls
are used, they are merely function stubs (one for each number of parameters).(import "env" "__syscall0" (func $env.__syscall0 (type $t2))) (import "env" "__syscall3" (func $env.__syscall3 (type $t5))) (import "env" "__syscall1" (func $env.__syscall1 (type $t8))) ...
-
To figure that out which
SysCalls
are being used, you'll have to run the module. I ran it and got 45, 146 and 192. You can figure out what these numbers mean by looking them up in the Linux SysCall Reference. They are brk(), writev() and mmap(). To make this WebAssembly module run, you'll just have to implement a tiny Linux kernel in JavaScript, no biggie. -
Take a look at
src/main.js
, this file emulates these basicSysCalls
in JavaScript.-
brk()
can be stubbed to return0
, which is the success error code.brk()
is used to allocate more memory to a process. WebAssembly does handles memory differently, so there's no need to do special here. -
mmap2()
is used to request more memory within the process. In our example, it's implemented as a call to the WebAssemblymemory.grow()
function. -
writev()
is used to write data to files. Its signature iswritev(int fd, const struct iovec *iov, int iovcnt)
. We can ignore the fd file descriptor parameter, and focus on theiov
structure. The problem here is that on the JavaScript side we have a hard time pulling the structiovec
abart. We could figure it out, but a neat hack is to call back into the WebAssembly module and have some C code unpack it for us.
-
-
Click Run
You can download the whole project from WebAssembly Studio and execute it in your local project.
Modify your app/index.html
file to add the new demo:
<li>
<a href="./WebAssemblyStudioHelloWorld/src/main.html">
Hello World with WebAssembly Studio
</a>
</li>
And you have the new demo:
In the next step you are going to use WebAssembly Studio to compile an existing library, an AssemblyScript implementation of Conway's Game of Life.