1# wasm2c: Convert wasm files to C source and header
2
3`wasm2c` takes a WebAssembly module and produces an equivalent C source and
4header. Some examples:
5
6```sh
7# parse binary file test.wasm and write test.c and test.h
8$ wasm2c test.wasm -o test.c
9
10# parse test.wasm, write test.c and test.h, but ignore the debug names, if any
11$ wasm2c test.wasm --no-debug-names -o test.c
12```
13
14## Tutorial: .wat -> .wasm -> .c
15
16Let's look at a simple example of a factorial function.
17
18```wasm
19(func (export "fac") (param $x i32) (result i32)
20  (if (result i32) (i32.eq (get_local $x) (i32.const 0))
21    (then (i32.const 1))
22    (else
23      (i32.mul (get_local $x) (call 0 (i32.sub (get_local $x) (i32.const 1))))
24    )
25  )
26)
27```
28
29Save this to `fac.wat`. We can convert this to a `.wasm` file by using the
30`wat2wasm` tool:
31
32```sh
33$ wat2wasm fac.wat -o fac.wasm
34```
35
36We can then convert it to a C source and header by using the `wasm2c` tool:
37
38```sh
39$ wasm2c fac.wasm -o fac.c
40```
41
42This generates two files, `fac.c` and `fac.h`. We'll take a closer look at
43these files below, but first let's show a simple example of how to use these
44files.
45
46## Using the generated module
47
48To actually use our fac module, we'll use create a new file, `main.c`, that
49include `fac.h`, initializes the module, and calls `fac`.
50
51`wasm2c` generates a few symbols for us, `init` and `Z_facZ_ii`. `init`
52initializes the module, and `Z_facZ_ii` is our exported `fac` function, but
53[name-mangled](https://en.wikipedia.org/wiki/Name_mangling) to include the
54function signature.
55
56We can define `WASM_RT_MODULE_PREFIX` before including `fac.h` to generate
57these symbols with a prefix, in case we already have a symbol called `init` (or
58even `Z_facZ_ii`!) Note that you'll have to compile `fac.c` with this macro
59too, for this to work.
60
61```c
62#include <stdio.h>
63#include <stdlib.h>
64
65/* Uncomment this to define fac_init and fac_Z_facZ_ii instead. */
66/* #define WASM_RT_MODULE_PREFIX fac_ */
67
68#include "fac.h"
69
70int main(int argc, char** argv) {
71  /* Make sure there is at least one command-line argument. */
72  if (argc < 2) return 1;
73
74  /* Convert the argument from a string to an int. We'll implictly cast the int
75  to a `u32`, which is what `fac` expects. */
76  u32 x = atoi(argv[1]);
77
78  /* Initialize the fac module. Since we didn't define WASM_RT_MODULE_PREFIX,
79  the initialization function is called `init`. */
80  init();
81
82  /* Call `fac`, using the mangled name. */
83  u32 result = Z_facZ_ii(x);
84
85  /* Print the result. */
86  printf("fac(%u) -> %u\n", x, result);
87
88  return 0;
89}
90```
91
92To compile the executable, we need to use `main.c` and the generated `fac.c`.
93We'll also include `wasm-rt-impl.c` which has implementations of the various
94`wasm_rt_*` functions used by `fac.c` and `fac.h`.
95
96```sh
97$ cc -o fac main.c fac.c wasm-rt-impl.c
98```
99
100Now let's test it out!
101
102```sh
103$ ./fac 1
104fac(1) -> 1
105$ ./fac 5
106fac(5) -> 120
107$ ./fac 10
108fac(10) -> 3628800
109```
110
111You can take a look at the all of these files in
112[wasm2c/examples/fac](/wasm2c/examples/fac).
113
114## Looking at the generated header, `fac.h`
115
116The generated header file looks something like this:
117
118```c
119#ifndef FAC_H_GENERATED_
120#define FAC_H_GENERATED_
121#ifdef __cplusplus
122extern "C" {
123#endif
124
125#ifndef WASM_RT_INCLUDED_
126#define WASM_RT_INCLUDED_
127
128...
129
130#endif  /* WASM_RT_INCLUDED_ */
131
132extern void WASM_RT_ADD_PREFIX(init)(void);
133
134/* export: 'fac' */
135extern u32 (*WASM_RT_ADD_PREFIX(Z_facZ_ii))(u32);
136#ifdef __cplusplus
137}
138#endif
139
140#endif  /* FAC_H_GENERATED_ */
141```
142
143Let's look at each section. The outer `#ifndef` is standard C boilerplate for a
144header. The `extern "C"` part makes sure to not mangle the symbols if using
145this header in C++.
146
147```c
148#ifndef FAC_H_GENERATED_
149#define FAC_H_GENERATED_
150#ifdef __cplusplus
151extern "C" {
152#endif
153
154...
155
156#ifdef __cplusplus
157}
158#endif
159#endif  /* FAC_H_GENERATED_ */
160```
161
162This `WASM_RT_INCLUDED_` section contains a number of definitions required for
163all WebAssembly modules.
164
165```c
166#ifndef WASM_RT_INCLUDED_
167#define WASM_RT_INCLUDED_
168
169...
170
171#endif  /* WASM_RT_INCLUDED_ */
172```
173
174First we can specify the maximum call depth before trapping. This defaults to
175500:
176
177```c
178#ifndef WASM_RT_MAX_CALL_STACK_DEPTH
179#define WASM_RT_MAX_CALL_STACK_DEPTH 500
180#endif
181```
182
183Next we can specify a module prefix. This is useful if you are using multiple
184modules that may use the same name as an export. Since we only have one module
185here, it's fine to use the default which is an empty prefix:
186
187```c
188#ifndef WASM_RT_MODULE_PREFIX
189#define WASM_RT_MODULE_PREFIX
190#endif
191
192#define WASM_RT_PASTE_(x, y) x ## y
193#define WASM_RT_PASTE(x, y) WASM_RT_PASTE_(x, y)
194#define WASM_RT_ADD_PREFIX(x) WASM_RT_PASTE(WASM_RT_MODULE_PREFIX, x)
195```
196
197Next are some convenient typedefs for integers and floats of fixed sizes:
198
199```c
200typedef uint8_t u8;
201typedef int8_t s8;
202typedef uint16_t u16;
203typedef int16_t s16;
204typedef uint32_t u32;
205typedef int32_t s32;
206typedef uint64_t u64;
207typedef int64_t s64;
208typedef float f32;
209typedef double f64;
210```
211
212Next is the `wasm_rt_trap_t` enum, which is used to give the reason a trap
213occurred.
214
215```c
216typedef enum {
217  WASM_RT_TRAP_NONE,
218  WASM_RT_TRAP_OOB,
219  WASM_RT_TRAP_INT_OVERFLOW,
220  WASM_RT_TRAP_DIV_BY_ZERO,
221  WASM_RT_TRAP_INVALID_CONVERSION,
222  WASM_RT_TRAP_UNREACHABLE,
223  WASM_RT_TRAP_CALL_INDIRECT,
224  WASM_RT_TRAP_EXHAUSTION,
225} wasm_rt_trap_t;
226```
227
228Next is the `wasm_rt_type_t` enum, which is used for specifying function
229signatures. The four WebAssembly value types are included:
230
231```c
232typedef enum {
233  WASM_RT_I32,
234  WASM_RT_I64,
235  WASM_RT_F32,
236  WASM_RT_F64,
237} wasm_rt_type_t;
238```
239
240Next is `wasm_rt_anyfunc_t`, the function signature for a generic function
241callback. Since a WebAssembly table can contain functions of any given
242signature, it is necessary to convert them to a canonical form:
243
244```c
245typedef void (*wasm_rt_anyfunc_t)(void);
246```
247
248Next are the definitions for a table element. `func_type` is a function index
249as returned by `wasm_rt_register_func_type` described below.
250
251```c
252typedef struct {
253  uint32_t func_type;
254  wasm_rt_anyfunc_t func;
255} wasm_rt_elem_t;
256```
257
258Next is the definition of a memory instance. The `data` field is a pointer to
259`size` bytes of linear memory. The `size` field of `wasm_rt_memory_t` is the
260current size of the memory instance in bytes, whereas `pages` is the current
261size in pages (65536 bytes.) `max_pages` is the maximum number of pages as
262specified by the module, or `0xffffffff` if there is no limit.
263
264```c
265typedef struct {
266  uint8_t* data;
267  uint32_t pages, max_pages;
268  uint32_t size;
269} wasm_rt_memory_t;
270```
271
272Next is the definition of a table instance. The `data` field is a pointer to
273`size` elements. Like a memory instance, `size` is the current size of a table,
274and `max_size` is the maximum size of the table, or `0xffffffff` if there is no
275limit.
276
277```c
278typedef struct {
279  wasm_rt_elem_t* data;
280  uint32_t max_size;
281  uint32_t size;
282} wasm_rt_table_t;
283```
284
285## Symbols that must be defined by the embedder
286
287Next in `fac.h` are a collection of extern symbols that must be implemented by
288the embedder (i.e. you) before this C source can be used.
289
290A C implementation of these functions is defined in
291[`wasm-rt-impl.h`](wasm-rt-impl.h) and [`wasm-rt-impl.c`](wasm-rt-impl.c).
292
293```c
294extern void wasm_rt_trap(wasm_rt_trap_t) __attribute__((noreturn));
295extern uint32_t wasm_rt_register_func_type(uint32_t params, uint32_t results, ...);
296extern void wasm_rt_allocate_memory(wasm_rt_memory_t*, uint32_t initial_pages, uint32_t max_pages);
297extern uint32_t wasm_rt_grow_memory(wasm_rt_memory_t*, uint32_t pages);
298extern void wasm_rt_allocate_table(wasm_rt_table_t*, uint32_t elements, uint32_t max_elements);
299extern uint32_t wasm_rt_call_stack_depth;
300```
301
302`wasm_rt_trap` is a function that is called when the module traps. Some
303possible implementations are to throw a C++ exception, or to just abort the
304program execution.
305
306`wasm_rt_register_func_type` is a function that registers a function type. It
307is a variadic function where the first two arguments give the number of
308parameters and results, and the following arguments are the types. For example,
309the function `func (param i32 f32) (result f64)` would register the function
310type as
311`wasm_rt_register_func_type(2, 1, WASM_RT_I32, WASM_RT_F32, WASM_RT_F64)`.
312
313`wasm_rt_allocate_memory` initializes a memory instance, and allocates at least
314enough space for the given number of initial pages. The memory must be cleared
315to zero.
316
317`wasm_rt_grow_memory` must grow the given memory instance by the given number
318of pages. If there isn't enough memory to do so, or the new page count would be
319greater than the maximum page count, the function must fail by returning
320`0xffffffff`. If the function succeeds, it must return the previous size of the
321memory instance, in pages.
322
323`wasm_rt_allocate_table` initializes a table instance, and allocates at least
324enough space for the given number of initial elements. The elements must be
325cleared to zero.
326
327`wasm_rt_call_stack_depth` is the current stack call depth. Since this is
328shared between modules, it must be defined only once, by the embedder.
329
330## Exported symbols
331
332Finally, `fac.h` defines exported symbols provided by the module. In our
333example, the only function we exported was `fac`. An additional function is
334provided called `init`, which initializes the module and must be called before
335the module can be used:
336
337```c
338extern void WASM_RT_ADD_PREFIX(init)(void);
339
340/* export: 'fac' */
341extern u32 (*WASM_RT_ADD_PREFIX(Z_facZ_ii))(u32);
342```
343
344All exported names use `WASM_RT_ADD_PREFIX` (as described above) to allow the
345symbols to placed in a namespace as decided by the embedder. All symbols are
346also mangled so they include the types of the function signature.
347
348In our example, `Z_facZ_ii` is the mangling for a function named `fac` that
349takes one `i32` parameter and returns one `i32` result.
350
351## A quick look at `fac.c`
352
353The contents of `fac.c` are internals, but it is useful to see a little about
354how it works.
355
356The first few hundred lines define macros that are used to implement the
357various WebAssembly instructions. Their implementations may be interesting to
358the curious reader, but are out of scope for this document.
359
360Following those definitions are various initialization functions (`init`,
361`init_func_types`, `init_globals`, `init_memory`, `init_table`, and
362`init_exports`.) In our example, most of these functions are empty, since the
363module doesn't use any globals, memory or tables.
364
365The most interesting part is the definition of the function `fac`:
366
367```c
368static u32 fac(u32 p0) {
369  FUNC_PROLOGUE;
370  u32 i0, i1, i2;
371  i0 = p0;
372  i1 = 0u;
373  i0 = i0 == i1;
374  if (i0) {
375    i0 = 1u;
376  } else {
377    i0 = p0;
378    i1 = p0;
379    i2 = 1u;
380    i1 -= i2;
381    i1 = fac(i1);
382    i0 *= i1;
383  }
384  FUNC_EPILOGUE;
385  return i0;
386}
387```
388
389If you look at the original WebAssembly text in the flat format, you can see
390that there is a 1-1 mapping in the output:
391
392```wasm
393(func $fac (param $x i32) (result i32)
394  get_local $x
395  i32.const 0
396  i32.eq
397  if (result i32)
398    i32.const 1
399  else
400    get_local $x
401    get_local $x
402    i32.const 1
403    i32.sub
404    call 0
405    i32.mul
406  end)
407```
408
409This looks different than the factorial function above because it is using the
410"flat format" instead of the "folded format". You can use `wat-desugar` to
411convert between the two to be sure:
412
413```sh
414$ wat-desugar fac-flat.wat --fold -o fac-folded.wat
415```
416
417```wasm
418(module
419  (func (;0;) (param i32) (result i32)
420    (if (result i32)  ;; label = @1
421      (i32.eq
422        (get_local 0)
423        (i32.const 0))
424      (then
425        (i32.const 1))
426      (else
427        (i32.mul
428          (get_local 0)
429          (call 0
430            (i32.sub
431              (get_local 0)
432              (i32.const 1)))))))
433  (export "fac" (func 0))
434  (type (;0;) (func (param i32) (result i32))))
435```
436
437The formatting is different and the variable and function names are gone, but
438the structure is the same.
439