PWASM (pronounced "possum") is a command-line tool and library for handling WebAssembly modules.
The pwasm
command lets you inspect and disassemble WebAssembly
modules. See the PWASM Command-Line Tool
section below for more.
The library allows you to parse WebAssembly modules and and run functions from WebAssembly modules inside your application. See the PWASM Library section below for more.
The pwasm
command lets you inspect WebAssembly module files.
The pwasm
tool can:
- Disassemble modules into WebAssembly Text (WAT) files.
- List the imports and exports of a module.
- Extract the contents of a custom section from a module.
- Run the built-in test suite.
Use the pwasm help
command for a list of available commands:
> pwasm help
Usage:
pwasm <command> [args]
Module Commands:
cat: Extract data for a custom section from a WASM file.
customs: List custom sections in a WASM file.
exports: List exports in a WASM file.
func: Show parameters and results for an exported function.
imports: List imports in a WASM file.
wat: Convert one or more WASM files to WAT files.
Other Commands:
help: Show help.
test: Run tests.
Use "help <command>" for more details on a specific command.
Below are a couple of examples which use the pwasm
command-line tool
to extract information from a WebAssembly module.
This example uses the exports
command to list the type and name of
the exports in a WebAssembly module stored in the file
01-fib.wasm
.
> pwasm exports 01-fib.wasm
type,name
func,"fib_recurse"
func,"fib_iterate"
This example uses the wat
command disassemble a WebAssembly module
stored in the file 03-mem.wasm
into WebAssembly text (WAT)
format.
> pwasm wat ./03-mem.wasm
(module
(memory $m0 1)
(func $f0 (param $v0 i32) (result i32)
(local.get $v0)
(i32.load)
)
(func $f1 (param $v0 i32) (param $v1 i32) (result i32)
(local.get $v0)
(local.get $v1)
(i32.store)
(local.get $v1)
)
(export "mem" (memory $m0))
(export "get" (func $f0))
(export "set" (func $f1)))
The PWASM library has the following features:
- Easy to embed. Two files:
pwasm.c
andpwasm.h
. - Easy to create isolated execution environments.
- Built-in interpreter which should run on just about anything.
- Modular architecture. Use the parser and ignore the interpreter, write your own JIT, etc.
- No dependencies other than the C standard library.
- Customizable memory allocator.
- Parser uses amortized O(1) memory allocation.
- "Native" module support. Call native functions from a WebAssembly module.
- Written in modern C11.
- MIT-licensed.
- Multi-value block, SIMD, and
trunc_sat
extended opcode support. - x86-64 JIT compiler (via DynASM).
Coming Soon
PWASM is meant to be embedded in an existing application.
Here's how:
- Copy
pwasm.h
andpwasm.c
into the source directory of an existing application. - Add
pwasm.c
to your build. - Link against
-lm
.
To execute functions from a WebAssembly module, do the following:
- Create a PWASM memory context.
- Read the contents of the module.
- Parse the module with
pwasm_mod_init()
. - Create an interpreter environment with
pwasm_env_init()
. - Add the parsed module into the environment with
pwasm_env_add_mod()
. - Call module functions with
pwasm_call()
.
The example below does the following:
- Parses a WebAssembly module.
- Creates an interpreter environment.
- Adds the parsed module to the interpreter.
- Executes the
pythag.f32()
module function. - Prints the result to standard output.
- Executes
pythag.f64()
module function. - Prints the result to standard output.
- Finalizes the interpreter and the parsed module.
/**
* 00-pythag.c: minimal standalone PWASM example.
*
* Usage:
* # compile examples/00-pythag.c and pwasm.c
* cc -c -W -Wall -Wextra -Werror -pedantic -std=c11 -I. -O3 examples/00-pythag.c
* cc -c -W -Wall -Wextra -Werror -pedantic -std=c11 -I. -O3 pwasm.c
*
* # link and build as ./example-00-pythag
* cc -o ./example-00-pythag {00-pythag,pwasm}.o -lm
*
* Output:
* # run example-00-pythag
* > ./example-00-pythag
* pythag.f32(3.0, 4.0) = 5.000000
* pythag.f64(5.0, 6.0) = 7.810250
*
*/
#include <stdlib.h> // EXIT_FAILURE
#include <stdio.h> // printf()
#include <stdint.h> // uint8_t, etc
#include <err.h> // errx()
#include <pwasm.h>
/**
* Blob containing a small WebAssembly (WASM) module.
*
* This WASM module exports two functions:
*
* * f32 (f32, f32 -> f32): Calculate the length of the
* hypotenuse of a right triangle from the lengths of the other
* two sides of the triangle.
*
* * f64 (f64, f64 -> f64): Calculate the length of the
* hypotenuse of a right triangle from the lengths of the other
* two sides of the triangle.
*/
static const uint8_t PYTHAG_WASM[] = {
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
0x01, 0x0d, 0x02, 0x60, 0x02, 0x7d, 0x7d, 0x01,
0x7d, 0x60, 0x02, 0x7c, 0x7c, 0x01, 0x7c, 0x03,
0x03, 0x02, 0x00, 0x01, 0x07, 0x0d, 0x02, 0x03,
0x66, 0x33, 0x32, 0x00, 0x00, 0x03, 0x66, 0x36,
0x34, 0x00, 0x01, 0x0a, 0x1f, 0x02, 0x0e, 0x00,
0x20, 0x00, 0x20, 0x00, 0x94, 0x20, 0x01, 0x20,
0x01, 0x94, 0x92, 0x91, 0x0b, 0x0e, 0x00, 0x20,
0x00, 0x20, 0x00, 0xa2, 0x20, 0x01, 0x20, 0x01,
0xa2, 0xa0, 0x9f, 0x0b
};
static void test_pythag_f32(pwasm_env_t * const env) {
pwasm_stack_t * const stack = env->stack;
// set parameters values and parameter count
stack->ptr[0].f32 = 3;
stack->ptr[1].f32 = 4;
stack->pos = 2;
// call function, check for error
if (!pwasm_call(env, "pythag", "f32")) {
errx(EXIT_FAILURE, "pythag.f32: pwasm_call() failed");
}
// print result (the first stack entry) to standard output
printf("pythag.f32(3.0, 4.0) = %f\n", stack->ptr[0].f32);
}
static void test_pythag_f64(pwasm_env_t * const env) {
// get stack from environment
pwasm_stack_t * const stack = env->stack;
// set parameters
stack->ptr[0].f64 = 5;
stack->ptr[1].f64 = 6;
stack->pos = 2;
// call function, check for error
if (!pwasm_call(env, "pythag", "f64")) {
errx(EXIT_FAILURE, "f64: pwasm_call() failed");
}
// print result (the first stack entry) to standard output
printf("pythag.f64(5.0, 6.0) = %f\n", stack->ptr[0].f64);
}
int main(void) {
// create a memory context
pwasm_mem_ctx_t mem_ctx = pwasm_mem_ctx_init_defaults(NULL);
pwasm_mod_t mod;
{
// wrap pythag.wasm data in buffer
pwasm_buf_t buf = { PYTHAG_WASM, sizeof(PYTHAG_WASM) };
// parse module, check for error
if (!pwasm_mod_init(&mem_ctx, &mod, buf)) {
errx(EXIT_FAILURE, "pwasm_mod_init() failed");
}
}
// set up stack (used to pass parameters and results and
// to execute the stack machine inside functions)
pwasm_val_t stack_vals[10];
pwasm_stack_t stack = {
.ptr = stack_vals,
.len = 10,
};
// get interpreter callbacks
const pwasm_env_cbs_t * const interp_cbs = pwasm_new_interpreter_get_cbs();
// create interpreter environment, check for error
pwasm_env_t env;
if (!pwasm_env_init(&env, &mem_ctx, interp_cbs, &stack, NULL)) {
errx(EXIT_FAILURE, "pwasm_env_init() failed");
}
// add parsed module to interpreter environment with a
// name of "pythag", check for error
if (!pwasm_env_add_mod(&env, "pythag", &mod)) {
errx(EXIT_FAILURE, "pythag: pwasm_env_add_mod() failed");
}
// call "f32" function
test_pythag_f32(&env);
// call "f64" function
test_pythag_f64(&env);
// finalize interpreter environment and parsed module
pwasm_env_fini(&env);
pwasm_mod_fini(&mod);
// return success
return EXIT_SUCCESS;
}
There are two sets of PWASM documentation:
- User Documentation: This documentation
covers the
pwasm
command-line tool and provides a high-level overview of using the PWASM library. - API Documentation. This documentation covers the PWASM library API.
Descriptions and build instructions for each set of documentation are avaialable in the sections below.
The user documentation covers the pwasm
command-line tool and provides
a high-level overview of using the PWASM library.
The latest PWASM user documentation is always available online at the following URL:
https://pwasm.org/docs/latest/
The user documentation is stored as a set of Markdown files in the
docs/
directory. You can build the PWASM documentation yourself
with MkDocs by doing the following:
- Clone the PWASM Git repository.
- Create and activate a
pwasm
virtual environment. - Switch to the directory of the cloned Git repository.
- Install the following packages in the virtual environment:
mkdocs
,mkdocs-minify-plugin
,mkdocs-material
- Run
mkdocs build
to generate the documentation in thesite/
directory.
Example:
# create venv in ~/venv/pwasm-docs
# debian uses "python3"; your distribution may differ
> python3 -m venv ~/venv/pwasm-docs
# activate virtual environment
> source ~/venv/pwasm-docs/bin/activate
# install packages
> pip install mkdocs mkdocs-minify-plugin mkdocs-material
# clone pwasm git repo into ~/git/pwasm
> git clone https://github.com/pablotron/pwasm ~/git/pwasm
> cd ~/git/pwasm
# build docs in ./site/
> mkdocs build
The API documentation covers the PWASM library API.
The latest PWASM API documentation is always available online at the following URL:
https://pwasm.org/docs/latest/api/
The PWASM API documentation is generated from annotations in the
pwasm.h
header file. You can build the API documentation yourself
with Doxygen by doing the following:
- Clone the PWASM Git repository.
- Switch to the directory of the cloned Git repository.
- Run
doxygen
to generate the API documentation in theapi-docs/
directory.
Note: The API documentation is currently incomplete.
Copyright 2020 Paul Duncan
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.