WebAssembly & CloudABI

A match made in heaven

WebAssembly is a great technology. It brings ubiquity to our applications, so they can run anywhere: from browsers to servers, from Windows to Unix, from Desktop to Mobile…

I know, JavaScript already does that! 🚶‍♂️

…but not that fast though. 🏃‍♂️

So once applications are compiled to WebAssembly, how can we make sure they run on all platforms?

Or —in other words — what is the best ABI that all applications should target?

Let’s start from the beginning…

What’s exactly an ABI?

ABI stands for Application Binary Interface (wiki page).

We can see an ABI as a contract between two binary applications, to assure that one binary is able to access certain native functions from the other binary.

Each time we compile a C or C++ application there is a set of system calls that the application will normally use, for example, to open a file, read its contents… or even opening a socket.

For doing that, the applications normally target the POSIX ABI to run these syscalls in Unix-like systems. There are different implementations following POSIX, such as libc, musl…

WebAssembly ABIs

The same concept can be applied when we compile applications to WebAssembly. What is the most common & complete set of syscalls that we should run there?

These are the most ABI strategies used for WebAssembly:

Emscripten : Emscripten defines a subset on top of the POSIX ABI.

Its main goal was to execute C/C++ applications inside a browser. So most of the syscalls are “emulated” in JavaScript (such as the filesystem or sockets calls).

: Emscripten defines a subset on top of the POSIX ABI. Its main goal was to execute C/C++ applications inside a browser. So most of the syscalls are “emulated” in JavaScript (such as the filesystem or sockets calls). Go : Go doesn’t define any explicit ABI. Different dependencies can plug its own exports into the WebAssembly imported functions. It’s a very flexible approach but can get messy when trying to reach a platform-agnostic application.

Olin, however, takes an interesting approach for its ABI.

: Go doesn’t define any explicit ABI. Different dependencies can plug its own exports into the WebAssembly imported functions. It’s a very flexible approach but can get messy when trying to reach a platform-agnostic application. Olin, however, takes an interesting approach for its ABI. Rust: there is not yet an official ABI for WebAssembly. However, there are certain tools such as wasm-bindgen that help on the interop between WebAssembly and other languages (right now mainly JavaScript).

Wasmer currently only supports Emscripten. But, Why?

Focusing on running Emscripten generated WebAssembly modules (such as Nginx and Lua!) helped us build a proof-of-concept before needing to build all the toolchain around it.

But… wouldn’t be great if there is a common ABI that Go, Rust, C, C++, etc. can all use as a target while being platform-independent?

This way, we would only need to implement the ABI one time and have easy interoperability between different WebAssembly compiled modules in any platform and context.

PWSIX : POSIX for WebAssembly

One initiative that we think will stick on the long term will be creating a new ABI like POSIX, but created specifically for WebAssembly environments: PWSIX.

However, we are still far from having a standard defined that will fit all platforms with a common set of syscalls. Because of that, we think there might be an easier strategy for the short-term: CloudABI.

CloudABI

CloudABI was born with the goal of providing a common permission mechanism on top the syscalls.

WebAssembly provides a secure sandbox which only allows a program to call functions provided by the host environment. CloudABI is a minimal POSIX style API which allows strict control over the resources a program is allowed to access. By combining a secure sandbox and a capabilities-based security host environment, a new finer-grained compute is possible without the overhead of containers or virtualization.

Instead of allowing applications to open arbitrary files on disk and connect to arbitrary systems on the network, you as a user exactly inject those resources that the application should access

— nuxi.nl

So, what can we learn from CloudABI?

Apart from introducing the concept of permissions to execute certain syscalls, it also reduces the number of syscalls needed for the implementer to just 49.

Here’s a great intro on what are all the advantages of using CloudABI: