Understanding WebAssembly: Modules, Binary and Text Formats, and a Hands‑On Example
This article provides a comprehensive overview of WebAssembly, covering its core concepts such as modules, types, variables, functions, instructions, traps, tables, and linear memory, explains the binary module structure and sections, details the human‑readable text format with S‑expressions and lexical rules, and walks through a step‑by‑step example of writing, compiling, and invoking a simple WebAssembly module.
1. Introduction
After covering WebAssembly's key features, history, and primary use cases, this section introduces the basic concepts that will be explored in depth, including the binary format, text format, and a demo WebAssembly text module.
2. Basic Concepts
2.1 Modules
A WebAssembly module is the fundamental unit containing functions, linear memory, globals, and tables. It is instantiated after loading, decoding, and validation, producing a runtime instance that interacts with the host environment.
2.2 Types
WebAssembly defines four primitive value types— i32 , i64 , f32 , f64 —and later extensions such as v128 (SIMD) and reference types ( funcref , externref ).
2.3 Variables
Variables are either local (function‑scoped) or global, with locals accessed via local.get and globals via global.get / global.set . Globals may be mutable or immutable and can be imported or exported.
2.4 Functions
Functions are the containers for instructions; they accept typed parameters and may return multiple values. Functions cannot be nested.
2.5 Instructions
WebAssembly uses a stack‑based execution model; instructions push and pop operands on an implicit operand stack (e.g., local.get idx loads a local variable onto the stack).
2.6 Traps
Executing an unreachable instruction or other runtime error triggers a trap, which aborts execution and propagates to the host (e.g., a JavaScript RuntimeError ).
2.7 Tables
Tables store a vector of reference elements ( funcref or externref ) and enable indirect calls via call_indirect , effectively providing function‑pointer semantics.
2.8 Linear Memory
Linear memory is a contiguous byte array (default page size 64 KB). A module may define at most one memory, which can be grown with grow_memory and accessed via load / store instructions using i32 offsets.
3. Module Structure
The binary format consists of a magic number, version, and up to twelve optional sections (custom, type, function, table, memory, global, import, export, start, element, code, data, data count). Sections must appear in a defined order, and each section contains vectors of the corresponding definitions.
4. Text Format
4.1 S‑Expressions
The human‑readable format uses S‑expressions, a parenthesized prefix notation similar to Lisp, to represent both code and data.
4.2 Lexical Definitions
WebAssembly text consists of Unicode characters and supports line and block comments. Five lexical value categories exist: integers, floating‑point numbers, strings, names, and identifiers (e.g., $add ).
4.2.1 Values
Integers may be signed/unsigned and decimal/hexadecimal; floating‑point numbers include exponent notation; strings support escape sequences and Unicode code points.
4.2.2 Types
Value types include numeric ( i32 , i64 , f32 , f64 ), vector ( v128 ), and reference types ( funcref , externref ). These are used to declare function signatures, globals, tables, etc.
4.2.3 Instructions
The full instruction set is defined in the specification; this article references a few common instructions such as local.get , call , and call_indirect .
4.3 Writing a Simple WebAssembly Module
The following step‑by‑step example demonstrates how to create a minimal .wat file, define types, imports, functions, and exports, compile it with wat2wasm , and invoke it from JavaScript.
(module)
(type (func (param i32)))
(type (func))
(import "imports" "imported_func" (func (type 0)))
(func (type 1)
i32.const 88
call 0)
(export "exported_func" (func 1))After saving the file as simple.wat , compile it:
# install wat2wasm by `npm install -g wat2wasm`
wat2wasm simple.wat -o simple.wasmJavaScript code to load and run the module:
const fs = require('fs');
const wasm_buffer = fs.readFileSync("simple.wasm");
const js_func = (i) => console.log("From WebAssembly: " + i);
const import_obj = { imports: { imported_func: js_func } };
WebAssembly.instantiate(wasm_buffer, import_obj)
.then(result => result.instance.exports.exported_func());5. Conclusion
WebAssembly's binary and text formats are closely related; the text format provides a readable representation for debugging and manual authoring, while the binary format is used for efficient distribution and execution in browsers and other runtimes.
By studying this material, readers should be able to understand the fundamental concepts of WebAssembly, write simple text modules, and grasp the overall structure of the binary format.
ByteFE
Cutting‑edge tech, article sharing, and practical insights from the ByteDance frontend team.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.