当前位置: 首页 > news >正文

关于 WASM:1. WASM 基础原理

一、WASM 简介

1.1 WebAssembly 是什么?

WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C++、Rust)编译生成,并由浏览器中的 WebAssembly 引擎执行。

简而言之,WASM 是浏览器中的一个“轻量虚拟机”,它的目标是运行速度快、安全性高、体积小,适合执行计算密集型任务。

1.2 设计目标与用途

目标解释说明
 高性能WASM 的指令非常接近底层机器语言,性能可达原生应用的 80%~90%。
 可移植编译后的 .wasm 文件可以在任意支持 WASM 的环境中运行,如浏览器、Node.js、区块链运行时等。
 安全执行运行在浏览器的沙箱环境中,无法直接访问文件系统或网络,只能访问明确授权的资源。
 与 JavaScript 协同设计目标不是取代 JS,而是补强——JS 做逻辑控制,WASM 处理高强度任务。
 可快速加载.wasm 是压缩后的二进制格式,比 .js 加载更快、体积更小。

主要用途

  •  图像/音频/视频处理:如将 C 写的 FFmpeg 编译为 WASM 在浏览器中运行;

  •  游戏引擎移植:如 Unity、Unreal Engine 游戏编译成 Web 版本;

  •  加解密算法实现:比如 AES、SHA256;

  •  PDF / Word / Markdown 渲染

  •  AI/ML 推理模块

  •  区块链智能合约执行环境(如 EOS、Polkadot)

1.3 与 JavaScript 的关系与运行方式

WebAssembly 的运行方式高度依赖 JavaScript,主要是 JS 扮演“调用者”的角色,WASM 负责“执行者”。

协作模式

  • JS 调用 WASM: 加载 .wasm 模块、传参、获取结果;

  • WASM 导出函数: 供 JS 调用;

  • WASM 可导入 JS 提供的函数: 比如浏览器的打印、时间、内存等 API;

  • 共享内存: 二者可以共享 ArrayBuffer(线性内存)。

示例流程图:

           [ C/C++/Rust ]|↓┌───────────────┐│ 编译成 .wasm  │ <── LLVM、Emscripten└───────────────┘↓┌──────────────────────────┐│ JavaScript 加载 .wasm    ││ └ fetch / instantiate    │└──────────────────────────┘↓┌──────────────────────────┐│ 浏览器 WASM 引擎执行代码 │└──────────────────────────┘

实际代码调用方式

HTML 页面中 JavaScript 调用 add.wasm

fetch('add.wasm') // 从服务器获取名为 'add.wasm' 的 WebAssembly 模块文件.then(response => response.arrayBuffer()) // 将响应数据转换为 ArrayBuffer(二进制格式).then(bytes => WebAssembly.instantiate(bytes)) // 将 ArrayBuffer 实例化为 WebAssembly 模块.then(result => { // 实例化成功后执行这个回调函数const add = result.instance.exports.add; // 从模块中导出名为 'add' 的函数console.log(add(5, 7)); // 调用导出的 'add' 函数,传入参数 5 和 7,输出结果 12});

注:需要先将一个用 C 写的加法函数编译为 .wasm 文件,JS 才能调用。

1.4 浏览器对 WASM 的支持情况

WASM 是由 Google、Mozilla、Microsoft、Apple 四大厂商联合设计的标准,当前所有主流浏览器均已支持 WebAssembly。

浏览器支持版本(最低)是否默认开启
Chrome57+ 是
Firefox52+ 是
Safari11+ 是
Edge(旧版)16+ 是
Edge(Chromium)所有版本 是
Node.js8+ 是

检测支持的方法:

console.log(typeof WebAssembly === "object"); // true 表示支持

二、WASM 架构与运行模型

WebAssembly 本质上是一个基于栈机的运行时系统,核心架构包括:

  • 模块(Module)

  • 实例(Instance)

  • 内存(Memory)与表(Table)

  • 导入与导出(Import / Export)

  • 栈式指令结构(Stack Machine Model)

2.1 模块(Module)

定义:模块是 WebAssembly 的最小部署单元,可以理解为 .wasm 文件中封装的逻辑程序块,就像一个 JavaScript 模块或 C 的动态链接库(.so/.dll)。

它包含:

  • 类型(函数签名)

  • 函数(函数体)

  • 内存/表定义

  • 全局变量

  • 导入(import)项

  • 导出(export)项

  • 启动函数(start,可选)

示例

(module                         ;; 定义一个 WebAssembly 模块(func $add                   ;; 声明一个名为 $add 的函数(param $a i32)             ;; 函数参数 $a,类型为 i32(32 位整数)(param $b i32)             ;; 函数参数 $b,类型为 i32(result i32)               ;; 返回值类型为 i32local.get $a              ;; 读取本地变量 $a 的值local.get $b              ;; 读取本地变量 $b 的值i32.add)                  ;; 对 $a 和 $b 执行加法运算(export "add" (func $add))   ;; 将 $add 函数导出,命名为 "add",供外部调用
)

以上 .wat 表示一个导出 add 函数的模块,两个参数相加。

注意:

特性.wat.wasm
全称WebAssembly Text formatWebAssembly Binary format
表现形式可读的文本格式压缩的二进制格式
人类可读性(适合调试、学习)(需反编译工具查看)
执行效率(需先转为 .wasm(浏览器/引擎直接执行)
使用场景编写、调试 WebAssembly 模块运行、部署 WebAssembly 模块
转换工具使用 wat2wasm 转为 .wasm使用 wasm2wat 转为 .wat

2.2 实例(Instance)

定义:模块是“代码模板”,实例(Instance)是模块在内存中的实际运行副本,加载后才具有运行能力。

它包含:

  • 运行时内存

  • 已绑定的导入值

  • 各类资源的实例化副本(函数、表、内存、全局变量)

关系图:

   .wasm↓ 编译Module(静态)↓ 实例化Instance(运行态)

通过 JS 调用 .wasm,其实是使用模块创建了一个实例,然后调用其导出函数。

2.3 内存(Memory)与表(Table)

内存(Memory)

WebAssembly 的内存是一个线性内存(Linear Memory),表现为一个连续的字节数组(ArrayBuffer),供模块读写数据。

  • 单位是“页”,每页 64KB(65536 bytes

  • 只支持一段内存(Memory Index 为 0)

  • 可以动态增长(grow)

  • 由 JS 与 WASM 共享

// JS 中获取 wasm memory:
const memory = instance.exports.memory;
const bytes = new Uint8Array(memory.buffer);  // 访问 wasm 中的内存数据

表(Table)

WebAssembly 的表是用于存储**函数引用(Function References)**的结构,用于支持间接调用(Indirect Calls)。

常用于:

  • 动态函数调用(类似 C 的函数指针)

  • 多态实现(如虚函数表)

2.4 导入与导出(Import / Export)

导入(Import)

允许模块使用外部定义的函数、内存、表、全局变量等,通常由 JavaScript 提供

示例:

(import "env" "log" (func $log (param i32)))

上述表示模块希望导入一个 JS 的 env.log 函数。

导出(Export)

允许模块暴露函数、内存、表等供外部使用(JS 调用)。

(export "add" (func $add))

表示把 add 函数导出。

JS 调用关系

const imports = {                        // 定义导入对象 imports,供 wasm 模块使用env: {                                 // 创建一个 "env" 命名空间(WebAssembly 中常见的导入命名空间)log: (arg) => console.log("WASM Log:", arg)  // 定义一个 JS 函数 log,它会被 WebAssembly 模块中的代码调用,用于打印日志}
};WebAssembly.instantiate(bytes, imports) // 使用 imports 导入对象实例化 WebAssembly 模块.then(result => {                     // 实例化成功后执行这个回调const add = result.instance.exports.add; // 从模块中获取导出的函数 "add"console.log(add(2, 3));             // 调用 add(2, 3),输出 5(例如是加法函数)});

2.5 栈机结构(Stack Machine Model)

定义:WebAssembly 是一门基于栈的虚拟机语言(Stack Machine),所有指令不需要显式传参,而是通过操作数栈进行计算。

特点

  • 无寄存器:不像 x86 或 ARM,WASM 不使用寄存器;

  • 操作数栈工作方式:先压栈,再计算,再出栈;

  • 函数、局部变量、控制流全靠指令栈操作完成

示例:

(func (param $a i32) (param $b i32) (result i32)local.get $a   ;; → 将 $a 放入栈顶local.get $b   ;; → 将 $b 放入栈顶i32.add        ;; → 出栈两个数相加,将结果入栈
)

执行流程是这样的(假设 a=3,b=4):

[ ]            ← 初始空栈
[3]            ← local.get $a
[3, 4]         ← local.get $b
[7]            ← i32.add(弹出两个数,相加,再压入)

结果 7 就是函数返回值。

2.6 小结图示

┌──────────────┐
│  Module (.wasm) │
└──────┬───────┘↓ 实例化
┌──────────────┐
│ Instance       │
│ ┌───────────┐ │
│ │ Memory     │◄── JS 可访问 ArrayBuffer
│ └───────────┘ │
│ ┌───────────┐ │
│ │ Table      ││── 动态函数表
│ └───────────┘ │
│ ┌───────────┐ │
│ │ Export     │◄── JS 调用函数
│ └───────────┘ │
└──────────────┘▲│ Import│┌──────────────┐│ JavaScript   │└──────────────┘
组件作用描述
Module静态代码定义 .wasm 文件
Instance模块运行时实例(JS 调用它)
Memory线性内存,WASM/JS 共享
Table函数表,支持间接调用
Import模块向外请求的资源(JS 提供)
Export模块向外暴露的函数或变量
Stack Machine栈结构执行指令,支持无寄存器运算

三、WASM 文件格式

WebAssembly 文件主要有三种格式:

  • .wasm:二进制格式,供浏览器加载执行

  • .wat:文本格式,便于阅读与手写

  • .wast:测试格式(已废弃)

3.1 .wasm 二进制格式

定义:.wasm 是 WebAssembly 的主流部署格式,采用高度压缩的二进制编码(binary encoding),专为浏览器高效解析而设计。

特点

特性描述
高性能加载与编译速度快,接近原生执行
不可读对人类不友好,必须借助工具解析
可移植不依赖平台,跨浏览器兼容
安全沙箱所有行为在沙箱中运行,不会直接访问本地资源

文件结构(简化)

+---------------------+
| Magic Header (4B)   | 0x00 0x61 0x73 0x6D → "\0asm"
| Version (4B)        | 当前一般是 0x01 0x00 0x00 0x00
+---------------------+
| Section 1: Type     |
| Section 2: Import   |
| Section 3: Function |
| Section 4: Table    |
| Section 5: Memory   |
| Section 6: Export   |
| Section 7: Code     |
| Section 8: Data     |
+---------------------+

可以使用工具如 wasm-objdump 来反编译:

wasm-objdump -x my_module.wasm  # 查看段结构
wasm-objdump -d my_module.wasm  # 反汇编

3.2 .wat 文本格式(WebAssembly Text Format)

定义:.wat 是 WebAssembly 的文本表示形式,类似汇编语言,用于手写、调试与学习

特点

特性描述
可读性强类 Lisp 风格,结构化、显式函数与局部变量
易于调试方便修改和反编译观察
.wasm 可互转通过官方工具如 wat2wasmwasm2wat

示例 .wat 文件

(module;; 从 JS 中导入一个名为 "log" 的函数,接受一个 i32 参数(import "env" "log" (func $log (param i32)));; 定义加法函数 $add(func $add (param $a i32) (param $b i32) (result i32)local.get $a         ;; 获取参数 alocal.get $b         ;; 获取参数 bi32.add              ;; 相加,栈顶变为结果(保留在栈顶);; 为了既返回又调用 log,我们使用 local.tee,把结果保存到临时变量local.tee 0          ;; 把结果存到局部变量 0,并保留在栈上用于返回call $log            ;; 调用 log 打印结果)(export "add" (func $add)) ;; 导出函数
)

搭配 JavaScript 使用:

const imports = {env: {log: (arg) => console.log("WASM Log:", arg) // log 会在 WASM 中被调用}
};WebAssembly.instantiate(bytes, imports).then(result => {const add = result.instance.exports.add;console.log("JS Result:", add(2, 3)); // 先 WASM 打印,再 JS 打印
});

输出效果:

WASM Log: 5       // 来自 WebAssembly 内部调用 log
JS Result: 5      // 来自 JS 的 console.log

格式转换

需要安装 WABT 工具集(WebAssembly Binary Toolkit):

# 安装
brew install wabt  # MacOS
sudo apt install wabt  # Ubuntu# 转换为二进制
wat2wasm add.wat -o add.wasm# 反编译为文本
wasm2wat add.wasm -o add.wat

3.3 工具推荐

工具作用
wat2wasm文本转二进制
wasm2wat二进制转文本
wasm-objdump查看段信息
wasm-interp执行 wast 测试脚本
WebAssembly Studio在线 IDE
wasm-packRust 生成 WebAssembly
binaryen优化 .wasm

四、WebAssembly 实战

4.1 安装 WebAssembly 工具:WABT

WABT(WebAssembly Binary Toolkit) 是官方的 WASM 编译工具链,包含:

  • wat2wasm将文本 .wat 转成二进制 .wasm

  • wasm2wat反编译 .wasm 为文本

  • wasm-objdump查看段信息

MacOS:

brew install wabt

Ubuntu/Debian:

sudo apt update
sudo apt install wabt

Windows:

  • 前往 GitHub 下载编译好的 ZIP: https://github.com/WebAssembly/wabt/releases

  • 解压并将 bin/ 目录添加到系统环境变量 Path

4.2 项目目录结构

mkdir wasm-demo && cd wasm-demo

项目目录:

wasm-demo/
├── index.html        # 网页
├── main.js           # JavaScript 逻辑
├── add.wat           # WebAssembly 文本源码
├── add.wasm          # 编译生成的二进制文件

4.3 编写 WebAssembly 文本文件(add.wat)

创建文件 add.wat

;; 文件:add.wat
(module(func $add (param $a i32) (param $b i32) (result i32)local.get $alocal.get $bi32.add)(export "add" (func $add))
)

这是一个简单的加法函数,接收两个 i32 整数,返回它们的和,并通过 export 导出。

4.4 编译 .wat 为 .wasm

wat2wasm add.wat -o add.wasm

成功后看到生成的 add.wasm 二进制文件,浏览器可以直接加载它。

4.5 编写 HTML 页面(index.html)

<!-- 文件:index.html -->
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>WebAssembly 加法演示</title>
</head>
<body><h1>WebAssembly 示例:3 + 4 = <span id="result">?</span></h1><script src="main.js"></script>
</body>
</html>

4.6 编写 JS 加载逻辑(main.js)


// 文件:main.jsasync function initWASM() {const response = await fetch('add.wasm');              // 从服务器加载名为 add.wasm 的 WebAssembly 文件const bytes = await response.arrayBuffer();            // 将响应内容转换为 ArrayBuffer(二进制)const { instance } = await WebAssembly.instantiate(bytes); // 实例化 WebAssembly 模块,获取模块实例const result = instance.exports.add(3, 4);              // 调用导出的 add 函数,传入 3 和 4document.getElementById('result').textContent = result; // 将计算结果显示在页面 id="result" 的元素中
}initWASM(); // 执行函数,初始化并调用 WASM 模块

说明:

  • fetch() 加载 .wasm 文件

  • WebAssembly.instantiate() 编译 + 实例化

  • 调用导出的函数 add(3, 4)

  • 显示结果到网页

4.7 运行本地服务器测试

浏览器无法直接读取本地文件的 .wasm,必须通过 HTTP 服务运行它。

推荐方法:使用 Python(快速)

# Python 3.x
python -m http.server 8080

然后访问:

http://localhost:8080

如果一切成功,网页上会显示:

WebAssembly 示例:3 + 4 = 7

4.8 小结

步骤内容
1编写 .wat 文件
2使用 wat2wasm 编译
3写 HTML 页面结构
4用 JS 加载 .wasm
5使用本地 HTTP 服务运行
http://www.xdnf.cn/news/956197.html

相关文章:

  • linux 下常用变更-8
  • VisualXML全新升级 | 新增数据库编辑功能
  • 怎么让Comfyui导出的图像不包含工作流信息,
  • 三网智能切换技术如何造富?拆解格行WiFi代理的管道收益模型
  • 直播APP平台中如何实现人脸美颜功能?美颜SDK技术详解
  • React第五十七节 Router中RouterProvider使用详解及注意事项
  • Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
  • PLC入门【4】基本指令2(SET RST)
  • 分布式系统简述
  • Appium下载安装配置保姆教程(图文详解)
  • 基于 Three.js 的数字雨波纹效果技术解析
  • 浏览器工作原理11 [#] this:从JavaScript执行上下文视角讲this
  • SpringBoot请求限流(RateLimiter)
  • 针对药品仓库的效期管理问题,如何利用WMS系统“破局”
  • align-items: start和align-items: flex-start的区别
  • 技术创新赋能产业升级:国际数字影像产业园引领变革浪潮
  • 【网络安全】开源系统getshell漏洞挖掘
  • UI 自动化测试工具推荐
  • [KCTF]CORE CrackMe v2.0
  • ​小学五年级的语言来解释符号​
  • ui框架-文件列表展示
  • 拉曼光谱效应:分子指纹的科学与应用
  • 视觉slam--三维刚体运动
  • java教程笔记(十四)-线程池
  • DAY 44 训练
  • RK3588开发笔记-wifi6 SDIO接口rtl8822cs调试笔记
  • Mysql故障排插与环境优化
  • ESP32-S3 IDF V5.4.1 LVGL 9.2.0 fatfs
  • RabbitMQ优先级队列的使用
  • 掌握业务三板斧:目标、过程、成果