Wasm 介绍(三):内存
source link: https://mp.weixin.qq.com/s/Wup2Jl_tMw05ch7xR7NJog
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
上一篇文章介绍了WebAssembly(简称Wasm)指令集以及指令的操作码(Opcode)、立即数(Immediate Arguments)、操作数(Operands)、操作数栈(Operand Stack,简称栈)等概念,并且详细介绍了参数指令和数值指令。 这篇文章将介绍Wasm内存和相关指令。
内存
每个Wasm模块都可以定义或者导入一个内存,内存大小以页为单位,每一页是64K。 定义内存时,需要指定内存的页数下限。 页数上限可选,可以指定也可以不指定。 内存的初始数据则可以在数据段中指定。 下面是一个WAT例子,展示了内存和数据段的定义:
(module
(memory 1 8) ;; { min: 1, max: 8 }
(data 0 (offset (i32.const 100)) "hello")
;; ...
)
和内存相关的指令共有25条,下面分别介绍。
memory.size
memory.size
指令(操作码 0x3F
)把内存的当前页数按 i32
类型推入栈顶。 memory.size
指令带有一个1字节立即数,可以指定操作的是哪个内存。由于Wasm1.0规范规定最多只能有一个内存,所以目前这个立即数只能是0。下面是 memory.size
指令的示意图:
bytecode:
...][ memory.size ][ 0 ][...
stack:
| | | |
| | ➘| p(i32) | # page count
| d | | d |
| c | | c |
| b | | b |
| a | | a |
└───────────┘ └───────────┘
memory.grow
memory.grow
指令(操作码 0x40
)将内存增长 n
页,其中 n
是一个 i32
类型的整数,从栈顶弹出。如果操作成功,将 增长前
的页数按 i32
类型推入栈顶,否则将 -1
推入栈顶。和 memory.size
指令一样, memory.grow
指令也带有一个1字节立即数,且取值必须为0。下面是 memory.grow
指令的示意图:
bytecode:
...][ memory.grow ][ 0 ][...
stack:
| | | |
| n(i32) |➚ ➘| p(i32) | # grow n pages
| d | | d |
| c | | c |
| b | | b |
| a | | a |
└───────────┘ └───────────┘
load
load
指令从内存读取数据,然后推入栈顶。具体读取多少字节的数据,以及将数据解释为何种类型的数,因指令而异。Wasm采用了“立即数+操作数”的内存寻址方式,所有 load
指令都带有两个 u32
类型(LEB28编码的32位无符号整数)的立即数,一个表示对齐方式,另一个表示内存偏移量。 load
指令还需要从栈顶弹出一个 i32
类型的操作数,立即数和操作数相加即可得到实际要读取的内存起始地址。对齐方式仅起提示作用,不影响实际操作,本文不做介绍,具体请参考Wasm规范。以 i64.load
指令(操作码 0x29
)为例,下面是它的示意图:
bytecode:
...][ i64.load ][ align ][ offset ][...
stack:
| | | |
| | | |
| d(i32) |➚ ➘|m[offset+d]| # i64
| c | | c |
| b | | b |
| a | | a |
└───────────┘ └───────────┘
load
指令一共有14条,为了统一说明这些指令,我们假设指令执行时计算出的内存地址是 a
,此处存放的数据是 0xABCDEF1234567890
。由于Wasm使用小端在前的方式存放数据,因此内存数据看起来是下面这样:
mem:
...[ 0x90 ][ 0x78 ][ 0x56 ][ 0x34 ][ 0x12 ][ 0xEF ][ 0xCD ][ 0xAB ]...
下表给出这14条 load
指令的操作码、实际读取到的字节,以及如何解释这些字节:
store
store
指令从栈顶弹出操作数,然后写入内存。具体如何解释操作数,以及写入多少字节,因指令而异。所有的 store
指令也都带有两个立即数,含义和 load
指令一样。和 load
指令不同的是, store
指令要从栈顶弹出两个操作数,一个用于计算内存地址,另一个是要写入的数据。以 i64.store
指令(操作码 0x37
)为例,下面是它的示意图:
bytecode:
...][ i64.store ][ align ][ offset ][...
stack:
| | | |
| e(i64) |➚ | |
| d(i32) |➚ | | # m[offset+d]=e
| c | | c |
| b | | b |
| a | | a |
└───────────┘ └───────────┘
store
指令一共有9条,为了统一说明这些指令,我们也假设指令执行时计算出的内存地址是 a
。下表给出这9条指令的操作码、栈顶操作数以及实际执行效果(Go伪代码, mem
表示内存, LE
表示小端编码后的字节数组):
*本文由CoinEx Chain开发团队成员Chase撰写。 CoinEx Chain是全球首条基于Tendermint共识协议和Cosmos SDK开发的DEX专用公链,借助IBC来实现DEX公链、智能合约链、隐私链三条链合一的方式去解决可扩展性(Scalability)、去中心化(Decentralization)、安全性(security)区块链不可能三角的问题,能够高性能的支持数字资产的交易以及基于智能合约的Defi应用。
Recommend
-
126
Today we will see how we can interact with WebAssembly, from Go: how to execute WebAssembly bytecode from Go and how to generate WebAssembly bytecode with Go. But first of all: what is WebAssembly? WebAssembly Ac...
-
35
前面的文章详细介绍了WebAssembly(简称Wasm)二进制格式和指令集,这篇文章将介绍Wasm文本格式(WebAssembly Text Format,后面简称WAT)。 整体结...
-
26
市场需求 人们对透明全内存加密这个功能的需求主要来自对机密和敏感数据的保护。普通 RAM 里面储存的数据,在掉电之后,一般都以为是彻底消失了。但其实在一些复杂的离线攻击下,这些数据仍然是能被恢复出来并导致泄密;而持久...
-
5
[翻译]虚拟内存介绍 2020-06-27 分类:Linux / 操作系统 阅读(3...
-
4
linux内核研究笔记(一)内存管理 – page介绍 浏览:7382次 出处信息 ============ “不负责任”声明 begin ===...
-
0
【翻译/介绍】jump consistent hash 零内存消耗,均匀,快速,简洁,来自Google的一致性哈希算法 jump consistent hash是一种一致性哈希算法, 此算法零内存消耗,均匀分配,快速...
-
5
介绍下Java内存区域(运行时数据区) Java 虚拟机在执行 Java 程序的过程中会把它管理的内存划分成若干个不同的数据区域。JDK 1.8 和之前的版本略有不同。 下图是 JDK 1.8 对JVM做的改动,把方法区的具体实现--...
-
1
作者:蒋卫峰 李涛 前面一篇文章中介绍了loongarch架构中的基础部分,包括基础的整数运算指令、浮点运算指令、访存指令等,以及loongarch架构中的一些寄存器约定和汇编写法。 这篇文章则主要介绍loongarch架构中内存一致性模型相关...
-
2
c/c++指针从浅入深介绍——基于数据内存分配的理解(上)
-
9
本文内容主要译自 SAP HANA Overview | SAP Blogs,阅读时间约为15分钟 本文包含以下内容: 1.什么是HANA? 2.SAP S/4 HANA与 SAP Suite on HANA...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK