雀康麻将机价格|2018微乐贵阳捉鸡麻将
?

登录/注册

广告一 广告二 广告三 广告四 广告五
首页 文章 Annchain深度之WebAssembly:结构篇

Annchain深度之WebAssembly:结构篇

文章来源:Annchain

Annchain,WebAssembly,

2019/03/01 14:20

2226

文章页2
作者介绍:黑白大彩电,Annchain核心开发成员。软件工程专业,多年C++开发经验,负责Annchain.OG Websocket、RPC以及WebAssembly方面的研发工作。

WebAssembly按照字面意思就是Web世界(浏览器)里的Assembly(汇编语言),也就是浏览器支持的一种底层的语言,它的指令集确实类似汇编指令,虽然事实上并不完全是,但还是?#34892;?#25509;近。严格来说,WASM是一种浏览器支持的二进制文件格式标准,该文件格式定义了基于堆栈运行的图灵完备的指令集所组成的二进制代码段,以及为了运行指定的代码(函数)所需要的相关环境,比如:数据类型、函数签名、数据区、内存区、表区、开始区、代码区等。

WASM文件布局

如图所示,WASM文件(称之为模块)总体上由三块组成:魔数(固定值:0x6d736100,小端存储)、版本号(当前值:0x00000001,小端存储)、以及若干个区(section)。其中,每个区由三部分组成:类型、长度以及?#23548;?#25968;据。图中的varuint32表示使用leb128编码方式。因为WASM是在网络上传输的,所以该格式为了尽量缩小文件体积,在内部广泛使用了数据压缩格式leb128,leb128是变长的整数压缩编码形式。因为在很多情况下,比如一个32位的整数在大部分时间存储的值只需要一个8位的字节存储即可,但是将来又有可能需要32位,因此可以采用采用leb128编码。leb128采用的方式是从低字节开始,每个字节中的最高位不是存储?#23548;?#30340;值,而是用来作为标志位,当该位置位时,表示下一字节还有数据,否则表示下一字节没有数据,没有数据的字节直接省略,从而达到了数据压缩的目的。

模块里定义的各个区根据不同的类型,它们的?#23548;?#25968;据有着不同的定义结构。目前支持的区类?#22836;段?#26159;整数1到11这11种。如图二所示:

在详细介绍每个区结构之前,先来了解下基础知识点:

1. 数据类型,WASM只有四种数据类型i32、i64、f32、f64。分别表示32位整数、64位整数、32位浮点数、64位浮点数。
2. 函数签名,WASM的函数签名是由各个参数类型外加返回值类型组成,形如:(param1_type, param2_type [,...]) result_type。当前版本的函数只支持一个返回值。
3. 索引空间,WASM模块中的函数、内存、表、全局变量都各自有自己的索引空间,用于记录各自的顺序,方便相关指令引用访?#30465;?/span>

有了以上三点基础知识之后,下面分别介绍每个区的结构。

类型区(type值为1)

如图三所示,类型区主要包含整体结构是一个由多个函数签名组成的数组,以及一个数组大小(在数组之前)组成。在每个函数签名结构里,第一个字段是一个固定值0x60,紧接着是函数的参数类型以及返回值类型。参数类型由参数个数以及对应的多个参数类型组成?#29615;?#22238;值类型由返回值个数(当前为1)以及返回值类型组成。

比如一个C函数int add(int a, int b)生成的签名是这样:0x60 2 i32 i32 1 i32,表示有两个参数,?#26469;?#26159;i32 i32类型,一个返回值,类型是i32。


导入区(type值为2)

导入区定义的是本模块从其它模块中导入的函数、表、内存、全局变量等,如图四所示。导入区整体?#24425;?#19968;个数组外加数组的大小,数组中的每个元素表示的是一个导入信息,包括:导入的模块名称(UTF8字符)、导入的字段名称(UTF8字符)、导入类型(0-3)以及和导入类型相关的描述信息。其中,导入类型0表示函数,后面紧跟的是该函数的函数签名在类型区所在数组中的索引;导入类型1表示表,后面紧跟的是表中元素类型以及表的初始容量和最大容量信息;导入类型2表示导入的是内存,后面紧跟的是内存的初始容量和最大容量,内存的单位是页,每页大小是65536字节;导入类型3表示全局变量,后面紧跟着的是全局标量的类型以及是否只读。


导出区(type值为7)

导出区定义的是本模块中导出的函数、表、内存、全局变量。只有导出的内容才能被其它模块导入,它的整体结构?#24425;?#19968;个数组结构以及数组长度。每个数组元素定义的是单独的一个导出信息,包括导出字段名、导出类型以及和导出类型所对应的指向其索引空间中的索引值。导出类型和导入区中的导入类型一致。


全局区(type值为6)

全局区定义?#22235;?#22359;中的全局变量,以及属性信息,比如是否只读。它的结构?#24425;?#19968;个数组以及数组大小,如图六所示。每个数组元素定义了全局变量的如下信息:类型、是否只读以及用于初始化全局变量的表达式。


开始区(type值为8)

开始区结构很简单,只有一个字段,指向本模块函数索引空间的索引值。当模块加载完成后,如果存在开始区,那么会首先调用开始区指向的函数。


函数区(type值为3)

函数区定义了本模块中所有函数的函数签名的索引数组以及该数组大小,如?#21450;?#25152;示。

函数区中每个元素分别和如下介绍的代码区中的每个函数代码一一对应。而本元素中的内容是指向类型区中函数签名数组?#24515;?#20010;签名的索引。

代码区(type值为10)

代码区定义?#22235;?#22359;中一个或者多个由指令集组成的函数定义,它分别和函数区中的函数签名一一对应。如图九所示:

它由多个函数体组成的数组以及数组大小构成,每个函数体又分别包括:函数体大小(本函数体的字节数)、局部变量、代码。在WASM中,局部变量包括函数的参数以及函数内定义的局部变量,代码区里的局部变量不包括函数参数部分。代码部分是由具体的指令集中的指令组成来完成该函数要实现的功能。

表区(type值为4)

表区是WASM模块里比较令人迷糊的东西,它?#23548;?#19978;存放的是本模块中定义的函数的索引的列表,用于在运行时调用其指向的函数。类似于C语言中的函数指针,之所以不把它放到内存区,是基于安全性考虑,它的结构如图十所示。图中的resizable_limits包含初始大小以?#30333;?#22823;大小字段。其中每个元素定义了一个表。

每个元素由两部分构成:类型(目前只支持anyfunc,表示任意的函数类型)、大小信息(包括初始大小、最大大小)。

元素区(type值为9)

表区定义了表的类型及大小,而元素区用于填充表区。元素区本身?#24425;?#19968;个数组结构,里面的每个元素定义了需要填充的表索引、表中的偏移值、指向的函数索引。如图十一所示:

正如元素区用于填充表区一样,下面介绍的内存区和数据区?#24425;?#36825;种关系,数据区用于填充内存区。

内存区(type值为5)

内存区定义?#22235;?#22359;中运行时所需要的内存空间,在模块初始化的时候由数据区进行填充。该区像表区一样,定义?#22235;?#23384;区的大小,但是没有类型,因为类型是字节型。该区每个元素定义了一块内存,如图十二所示:

数据区(type值为11)

数据区像元素区一样,定义了如何填充内存区的结构,它本身?#24425;?#19968;个数组,每个元素填充一?#25991;?#23384;。如图十三所示:

文章下面
?

比特币多空调查

看涨
盘整
看跌
  • 看涨
  • 盘整
  • 看跌
投票

PC?#20063;?50*250
内页右边3
?
雀康麻将机价格