Writing Hello World in Web Assembly
Tags: webassembly, javascript
Published: 2019-06-07 16:08:18

---
title: Writing Hello World in Web Assembly
published: true
description: Republished from https://wa9ace.net/2017/04/20/hello-world-web-assembly.html
canonical_url: https://wa9ace.net/2017/04/20/hello-world-web-assembly.html
tags:
- web-assembly
- javascript
---

Syndicated from [WA9ACE.net](https://wa9ace.net/2017/04/20/hello-world-web-assembly.html). Originally published on April 20th, 2017.

Before we get into the details we're going to define some terminology.

* WASM: [Web Assembly](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md)
* WAST: [WASM Abstract Syntax Tree](https://webassembly.github.io/spec/)
* WAVM: [Web Assembly Virtual Machine](https://github.com/WebAssembly/spec/tree/master/interpreter)
* WABT: [WebAssembly Binary Toolkit](https://github.com/WebAssembly/wabt)

Web Assembly was [recently decided to be a finished MVP](https://lists.w3.org/Archives/Public/public-webassembly/2017Feb/0002.html)
including

> a JavaScript API and binary format accompanied by a reference interpreter.

Web Assembly is written in an s-expression syntax (wast) and then needs to be translated down to binary encoded wasm. Below is a gist of wast that imports the `stdlib.print` function taking a memory location offset and a length, as well as importing a [block of memory](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Memory) from the controlling runtime. We then store the string `"Hello World"` at memory location 0. We then export a main function that calls the aforementioned `print` function with the memory location offset and length.

### hello.wast

```assembly
module
  (import "stdlib" "print" (func $print (param i32 i32)))
  (import "js" "mem" (memory 20))
  (data (i32.const 0) "Hello World")
  (func (export "main")
    i32.const 0  ;; pass offset 0 to log
    i32.const 20 ;; pass length 20 to log
    call $print))
```

If you know JavaScript the below will look rather mundane. The only interesting part is really the `log` function and creating the `memory` passed into the instantiated wasm. It's 20 pages (1280KiB) which is pretty overkill for this application. Try playing with that value and watch at which point the wasm fails and how. You can see the `exposed` object is how we make functions from JavaScript available to the wasm underneath.

### hello.js

```javascript
document.addEventListener("DOMContentLoaded", main)

function log(offset, length) {
  const bytes = new Uint8Array(memory.buffer, offset, length)
  const string = new TextDecoder('utf8').decode(bytes)
  console.log(string)
}

var memory = new WebAssembly.Memory({ initial : 20 });

const exposed = {
  stdlib: { print: log },
  js: { mem: memory }
}

function main(event) {
  fetch('hello.wasm').then(response =>
    response.arrayBuffer()
  ).then(bytes =>
    WebAssembly.instantiate(bytes, exposed)
  ).then(result =>
    result.instance.exports.main()
  )
}
```

Now this is all fine and dandy aside from the fact that we can't run the wast.

In order to run the wast we'll need to turn into binary encoded wasm. Fortunately wabt exists. After you've headed [over here](https://github.com/WebAssembly/wabt)
and compiled the toolchain you should have a binary called `wast2wasm` among others.

Running this command should produce a runnable wasm binary.

`wast2wasm hello.wast -o hello.wasm`

Now that we have the binary encoded wasm, we need to run it somewhere. As of Node 7.9.0 it uses V8 version 5.5.372.43. Chrome 57 uses V8 5.7.492.71. The older version does not support the latest wasm spec meaning we can't run our wasm in current stable Node (this will probably be wrong when you read this). Node version 8 nightly builds will try running the wasm however it errors out on my Macbook with `Illegal Instruction: 4`. To try running it in Node when this is solved you can call Node with `node --expose-wasm hello.js`.

Until then we'll be running it in current Chrome. Here's some HTML you can copy pasta, and if all goes well you should see `"Hello World"` in your dev tools console!

### index.html

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="icon" href="data:;base64,iVBORw0KGgo=">
    <title>Hello World WASM</title>
  </head>
  <body>
  <script src="hello.js"></script>
  </body>
</html>
```