前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >WebAssembly之wasm格式解析

WebAssembly之wasm格式解析

作者头像
李小白是一只喵
发布2020-09-11 06:38:43
3K0
发布2020-09-11 06:38:43
举报
文章被收录于专栏:算法微时光

WebAssembly 二进制格式

WebAssembly 使用LEB128编码。

LEB128编码

LEB128编码是一种使用广泛的可变长度编码格式,在DWARF调试格式信息、Android 的Dalvik虚拟机、xz压缩文件等诸多领域中都有广泛的使用,WebAssembly二进制文件中也使用LEB128编码表示整数与字符串长度等信息。

LEB128编码的核心思想主要有两点:

  1. 采用小端序表示编码数据
  2. 采用128进制编码数据

主流编程语言中,一个整形数一般采用本地序表示,同时每个字节8位(bit)用于表达256进制的一个数位。如果每个字节只用于表达LEB128的128进制的一个数位,那么将只需要7位。LEB128将每个字节剩余的1位用于表达是否终结的标志位,如果标志位是1表示编码数据还没有结束,如果标志位位0则表示编码已经结束。

样例的格式:

wasm格式分析

首先因为大小端问题,这里的存放和源文件是不同的,wasm的魔数为0x6d736100,版本号为0x01,所以前四个为魔数00 61 73 6d,后四个是版本号01 00 00 00,大小端颠倒了。

头部

WebAssembly的头部是一个四字节的魔数: [0x00, 0x61, 0x73, 0x6d],对应"\0asm"字符串。其中0x61, 0x73, 0x6d分别对应着字母的ASCALL码。

魔数后面的四字节是当前WebAssembly文件的版本,目前是有版本1。

段类型

模块主体主要是由多个段组成,段数据包含了模块段全部信息,每个段都对应一个ID。

ID

说明

0

自定义段(Custom)

主要用于存储调试信息等数据

1

类型段(Type)

存储导入函数、模块内部函数的函数参数列表

2

导入段(Import)

用于存储导入函数的函数名称、函数参数索引

3

函数段(Function)

用于存储函数索引值

4

表格段(Table)

用于存储对象引用,通过表格段可以实现函数指针的功能(call_indirect指令),可以从外部宿主导入,同时也可以导出到外部宿主环境

5

内存段(Memory)

用于存储程序的运行时动态数据,可以从外部宿主导入,同时也可以导出到外部宿主环境

6

全局段(Global)

用于存储全部变量值

7

导出段(Export)

用于存储导出函数的函数名称、函数参数索引

8

开始段(Start)

用于指定模块初始化时的函数索引值

9

元素段(Elem)

表格段并没有显式地初始化,元素段用于存储函数的索引值

10

代码段(Code)

用于存储函数的指令代码

11

数据段(Data)

用于存储初始化内存的静态数据

自定义段(Custom)

(暂未写)

类型段(Type)

接下来首先是类型段。

代码语言:javascript
复制
01 8C 80 80 80 00 02 60 01 7F 01 7F 60 02 7F 7F 01 7F

01是type,表示函数签名的Type Section,后面的 8C 80 80 80 00是LEB128编码方式表示长度为0c。

后续的表示:

02 60 01 7F 01 7F 60 02 7F 7F 01 7F

02表示entries数量为2,60表示是个函数的签名,01 表示参数为1,7f表示参数为i32类型,01表示有一个返回值,7f表示返回值为i32类型,这个是printf的函数声明; 同理,60 02 7F 7F 01 7F表示两个带有i32类型并返回i32类型的函数声明,也就是main的函数声明。

导入段(Import)
代码语言:javascript
复制
02 8C 80 80 80 00 01 03 65 6E 76 04 70 75 74 73 00 00

02表示Import Section.

长度为12, 02 8c 80 80 80 00,内容为:01 03 65 6E 76 04 70 75 74 73 00 00

01则只有一个引用,module长度为3,名称为env,field长度为4,名称为puts,最后的kind表示引入的类型,00表示引入的是个函数。

函数段(Function)
代码语言:javascript
复制
03 82 80 80 80 00 01 01

03是函数段Function Section

长度为82 80 80 80 00,内容为:01 01

01表示签名索引数量为1,01表示在type区中的索引值值1,即printf函数的签名。

表格段(Table)
代码语言:javascript
复制
04 84 80 80 80 00 01 70 00 00

04是Table Section。

长度为84 80 80 80 00 ,内容为:01 70 00 00

01表示数量为1,类型为70,目前只能是70,表示anyfunc。

内存段(Memory)
代码语言:javascript
复制
05 83 80 80 80 00 01 00 01

05是内存段(Memory)

长度为83 80 80 80 00 , 内容为: 01 00 01

全局段(Global)
代码语言:javascript
复制
06 81 80 80 80 00 00

06是全局段(Global)

长度为 81 80 80 80 00 , 内容为: 00

导出段(Export)
代码语言:javascript
复制
07 91 80 80 80 00 02 06 6D 65 6D 6F 72 79 02 00 04 6D 61 69 6E 00 01

07是Export Section

长度为91 80 80 80 00 , 内容为: 02 06 6D 65 6D 6F 72 79 02 00 04 6D 61 69 6E 00 01

02表示export数量为2,06表示第一个entry长度,名称为memory,02表示类型为memory类型,index为00,表示在对应索引空间的索引值; 04表示第二个entry长度为4,名称为main,类型为00,function类型,索引为01

代码段(Code)
代码语言:javascript
复制
0A 8F 80 80 80 00 01 89 80 80 80 00 00 41 10 10 00 1A 41 00 0B

0a表示Code Section

长度为 8F 80 80 80 00 , 内容为:01 89 80 80 80 00 00 41 10 10 00 1A 41 00 0B

01表示数量为1,89 80 80 80 00表示size为9,00是locals数量,为0则locals就没有,41 10 10 00 1a 41 00是code,0b是end。

数据段(Data)
代码语言:javascript
复制
0B 92 80 80 80 00 01 00 41 10 0B 0C 48 65 6C 6C 6F 20 57 6F 72 6C 64 00

0b是Data Section,

长度为92 80 80 80 00,内容为: 01 00 41 10 0B 0C 48 65 6C 6C 6F 20 57 6F 72 6C 64 00

01表示数量为1,00表示在线性内存中的索引为0,41表示iConst.32, 10表示call操作码, 0b表示offset,0c表示参数长度为12,68 65 6c 6c 6f 20 77 6f 72 6c 64 00表示我们打印的内容为hello world 至此,文件解析完毕。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • WebAssembly 二进制格式
    • LEB128编码
    • wasm格式分析
      • 头部
        • 段类型
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档