【WebAssembly 】WebAssembly 组成部分详解(0~12 段 ID 详解)
WebAssembly 二进制文件由多个段Section组成每个段有唯一的ID。本文详细介绍 ID 0-12 共 13 个标准段的完整结构。一、文件整体结构一个.wasm文件的结构如下------------------ 0x00 | 魔数 (4 字节) | \0asm ------------------ 0x04 | 版本号 (4 字节) | 1 ------------------ 0x08 | 段 0 (Custom) | ------------------ | 段 1 (Type) | ------------------ | 段 2 (Import) | ------------------ | 段 3 (Function) | ------------------ | 段 4 (Table) | ------------------ | 段 5 (Memory) | ------------------ | 段 6 (Global) | ------------------ | 段 7 (Export) | ------------------ | 段 8 (Start) | ------------------ | 段 9 (Element) | ------------------ | 段 10 (Code) | ------------------ | 段 11 (Data) | ------------------ | 段 12 (DataCount)| ------------------二、段通用格式每个段遵循相同的编码格式------------------ | 段 ID (1 字节) | 0x00 ~ 0x0C ------------------ | 段长度 (LEB128) | 该段的总字节数变长编码 ------------------ | 段内容 (N 字节) | 具体数据 ------------------LEB128 编码变长整数编码小端序最高位表示是否还有后续字节。三、段 ID 详解段 0Custom Section自定义段ID:0x00自定义段用于存储调试信息、名称、工具链元数据等不影响语义解析器可跳过。结构------------------ | 段名称长度 | LEB128 ------------------ | 段名称 | UTF-8 字符串 ------------------ | 自定义数据 | 任意二进制 ------------------常见子类型名称说明name函数名、局部变量名调试用sourceMappingURLSource Map 映射producers工具链信息编译器、版本WAT 示例(module;; 自定义段命名函数(customname\01\00\01\00\01\00add\00)(func$add(parami32 i32)(resulti32)(i32.add(local.get0)(local.get1))))段 1Type Section类型段ID:0x01定义函数签名类型供后续段引用。结构------------------ | 类型数量 | LEB128 ------------------ | 类型 0 | | -------------- | | 类型形式 (0x60)| 函数类型标记 | -------------- | | 参数数量 | LEB128 | -------------- | | 参数类型列表 | 每个 1 字节 | -------------- | | 返回值数量 | LEB128 (0 或 1) | -------------- | | 返回值类型 | 1 字节如果有 | -------------- | 类型 1 | ... ------------------数据类型编码类型字节值i320x7Fi640x7Ef320x7Df640x7Cv1280x7Bfuncref0x70externref0x6FWAT 示例(module(type(func(parami32 i32)(resulti32)));; 类型索引 0(type(func(paramf64)(resultf64)));; 类型索引 1(type(func));; 类型索引 2)二进制解析01 ; 段 ID: Type 09 ; 段长度: 9 字节 03 ; 3 个类型 60 02 7F 7F 01 7F ; 类型0: func(i32,i32)-i32 60 01 7C 01 7C ; 类型1: func(f64)-f64 60 00 00 ; 类型2: func()-void段 2Import Section导入段ID:0x02声明从外部环境导入的函数、全局变量、内存、表格。结构------------------ | 导入数量 | LEB128 ------------------ | 导入 0 | | -------------- | | 模块名长度 | LEB128 | -------------- | | 模块名 | UTF-8 | -------------- | | 名称长度 | LEB128 | -------------- | | 名称 | UTF-8 | -------------- | | 导入类型 | 1 字节 | -------------- | | 类型描述 | 根据导入类型决定 | -------------- | 导入 1 | ... ------------------导入类型编码类型字节值描述内容Function0x00类型索引 (LEB128)Table0x01表格类型Memory0x02内存类型Global0x03全局类型WAT 示例(module(importenvlog(func$log(parami32)));; 导入函数(importenvmemory(memory1));; 导入内存(importenvtable(table10funcref));; 导入表格(importenvcounter(global$counter(muti32)));; 导入全局变量)段 3Function Section函数段ID:0x03声明模块内部的函数只存储函数签名索引函数体在 Code 段。结构------------------ | 函数数量 | LEB128 ------------------ | 函数 0 类型索引 | LEB128 ------------------ | 函数 1 类型索引 | LEB128 ------------------ | ... | ------------------WAT 示例(module(type(func(parami32 i32)(resulti32)));; 类型 0(type(func(parami32)(resulti32)));; 类型 1(func(type0)...);; 函数 0使用类型 0(func(type1)...);; 函数 1使用类型 1(func(type0)...);; 函数 2使用类型 0)段 4Table Section表格段ID:0x04定义函数表格用于间接调用。结构------------------ | 表格数量 | LEB128 ------------------ | 表格 0 | | -------------- | | 元素类型 | 1 字节 (0x70 funcref, 0x6F externref) | -------------- | | 限制类型 | 1 字节 (0x00 最小, 0x01 最小最大) | -------------- | | 最小大小 | LEB128 | -------------- | | 最大大小 | LEB128 (如果限制类型为 0x01) | -------------- | 表格 1 | ... ------------------WAT 示例(module(table10funcref);; 最小 10无最大(table$t2520funcref);; 最小 5最大 20)段 5Memory Section内存段ID:0x05定义线性内存单位页1页 64KB。结构------------------ | 内存数量 | LEB128 ------------------ | 内存 0 | | -------------- | | 限制类型 | 1 字节 (0x00 最小, 0x01 最小最大) | -------------- | | 最小页数 | LEB128 | -------------- | | 最大页数 | LEB128 (如果限制类型为 0x01) | -------------- | 内存 1 | ... ------------------WAT 示例(module(memory1);; 初始 1 页无上限(memory$mem2210);; 初始 2 页最大 10 页)段 6Global Section全局段ID:0x06定义全局变量。结构------------------ | 全局变量数量 | LEB128 ------------------ | 全局变量 0 | | -------------- | | 类型 | 1 字节 (0x7F i32, 0x7E i64, ...) | -------------- | | 可变性 | 1 字节 (0x00 const, 0x01 var) | -------------- | | 初始值 | 常量表达式 | -------------- | 全局变量 1 | ... ------------------常量表达式支持的指令i32.const/i64.const/f32.const/f64.constglobal.get仅导入的全局变量ref.null/ref.funcWAT 示例(module(global$answer i32(i32.const42));; 常量(global$counter(muti32)(i32.const0));; 可变(global$ptr(muti32)(i32.const0));; 指针)段 7Export Section导出段ID:0x07声明对外暴露的接口函数、全局变量、内存、表格。结构------------------ | 导出数量 | LEB128 ------------------ | 导出 0 | | -------------- | | 名称长度 | LEB128 | -------------- | | 名称 | UTF-8 | -------------- | | 导出类型 | 1 字节 | -------------- | | 内部索引 | LEB128 | -------------- | 导出 1 | ... ------------------导出类型编码类型字节值Function0x00Table0x01Memory0x02Global0x03WAT 示例(module(func$add ...)(memory$mem1)(global$version i32(i32.const1))(table$tbl10funcref)(exportadd(func$add))(exportmemory(memory$mem))(exportversion(global$version))(exporttable(table$tbl)))段 8Start Section启动段ID:0x08指定模块实例化后自动执行的函数无参数、无返回值。结构------------------ | 启动函数索引 | LEB128 ------------------WAT 示例(module(func$init(call$setup))(start$init);; 实例化后自动执行 $init)段 9Element Section元素段ID:0x09初始化表格Table中的函数引用。结构------------------ | 元素段数量 | LEB128 ------------------ | 元素段 0 | | -------------- | | 表格索引 | LEB128 (通常为 0) | -------------- | | 偏移表达式 | 常量表达式计算起始索引 | -------------- | | 元素类型 | 0x00 funcref, 0x01 externref | -------------- | | 元素数量 | LEB128 | -------------- | | 函数索引列表 | LEB128 数组 | -------------- | 元素段 1 | ... ------------------WAT 示例(module(table10funcref)(func$add ...)(func$sub ...);; 初始化表格前 2 个槽位(elem(i32.const0)$add $sub);; 使用偏移表达式(elem(i32.const5)$add $sub $mul))段 10Code Section代码段ID:0x0A存储函数体实际指令序列。结构------------------ | 函数数量 | LEB128 (必须与 Function 段数量一致) ------------------ | 函数 0 | | -------------- | | 函数体大小 | LEB128 | -------------- | | 局部变量数量 | LEB128 | -------------- | | 局部变量组 | 每组的 (数量, 类型) | -------------- | | 指令序列 | 字节码 | -------------- | 函数 1 | ... ------------------局部变量编码------------------ | 局部组数量 | LEB128 ------------------ | 组 0 | | -------------- | | 变量数量 | LEB128 | -------------- | | 变量类型 | 1 字节 | -------------- | 组 1 | ... ------------------WAT 示例(module(func$add(param$a i32)(param$b i32)(resulti32)(local$temp i32);; 1 个局部变量(local$x i32)($yi32);; 2 个局部变量可合并(local.set $temp(i32.add(local.get $a)(local.get $b)))(local.get $temp)))段 11Data Section数据段ID:0x0B初始化线性内存中的数据。结构------------------ | 数据段数量 | LEB128 ------------------ | 数据段 0 | | -------------- | | 内存索引 | LEB128 (通常为 0) | -------------- | | 偏移表达式 | 常量表达式计算起始地址 | -------------- | | 数据长度 | LEB128 | -------------- | | 数据内容 | 原始字节 | -------------- | 数据段 1 | ... ------------------WAT 示例(module(memory1);; 静态字符串(data(i32.const0)Hello, World!);; 二进制数据(data(i32.const100)\00\01\02\03);; 命名数据段(data$message(i32.const200)Welcome))段 12Data Count Section数据计数段ID:0x0C可选段预先声明 Data 段的数量用于批量内存操作指令的验证。结构------------------ | 数据段数量 | LEB128 ------------------用途支持memory.init和data.drop指令时需要此段。WAT 示例(module(memory1)(data$d1(i32.const0)hello)(data$d2(i32.const10)world);; 编译器自动生成 DataCount 段值为 2)四、完整示例从 WAT 到二进制WAT 源代码(module;; 类型段(type(func(parami32 i32)(resulti32)));; 导入段(importenvlog(func$log(parami32)));; 函数段(func$add(type0)(local.get0)(local.get1)i32.add);; 导出段(exportadd(func$add));; 代码段;; (由编译器自动生成))十六进制表示00 61 73 6D ; 魔数 01 00 00 00 ; 版本 1 01 ; 段1: Type 07 ; 长度 7 01 ; 1个类型 60 ; 函数类型 02 ; 2个参数 7F 7F ; i32, i32 01 ; 1个返回值 7F ; i32 02 ; 段2: Import 0C ; 长度 12 01 ; 1个导入 03 ; 模块名长度 3 65 6E 76 ; env 03 ; 名称长度 3 6C 6F 67 ; log 00 ; 导入类型: Function 00 ; 类型索引 0 03 ; 段3: Function 02 ; 长度 2 01 ; 1个函数 00 ; 类型索引 0 07 ; 段7: Export 07 ; 长度 7 01 ; 1个导出 03 ; 名称长度 3 61 64 64 ; add 00 ; 导出类型: Function 00 ; 函数索引 0 0A ; 段10: Code 09 ; 长度 9 01 ; 1个函数 07 ; 函数体长度 7 00 ; 0个局部变量组 20 00 ; local.get 0 20 01 ; local.get 1 6A ; i32.add 0B ; end五、段 ID 总结表ID名称必选说明0Custom否调试信息、名称1Type是函数签名定义2Import否导入项3Function是有内部函数时函数签名索引4Table否表格定义5Memory否内存定义6Global否全局变量7Export否导出项8Start否启动函数9Element否表格初始化10Code是有内部函数时函数体11Data否内存初始化12DataCount否数据段计数用于批量操作顺序要求除 Custom 段外所有标准段必须按 ID 递增顺序出现Custom 段可以出现在任意位置通常放在开头或结尾
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2442009.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!