以太坊虚拟机介绍2-栈操作指令

上一篇文章对EVM和它的指令集进行了简单介绍,本文将介绍POP指令、PUSHx系列指令、DUPx系列指令、SWAPx系列指令。这些指令只对EVM栈进行单纯的操作,它们的操作码分布如下图所示:

POP指令
POP指令(操作码0x50)从栈顶弹出一个元素。下面是POP指令的操作示意图(白色表示元素即将发生变动):

PUSHx指令
PUSH系列指令把紧跟在指令后面的N(1 ~ 32)字节元素推入栈顶。PUSH系列指令一共有32条,从PUSH1(操作码0x60)一直到PUSH32(操作码0x7A)。EVM是大端机器,以PUSH2指令为例,下面是该指令的操作示意图(不完整的灰色纸带表示字节码):

DUPx指令
DUP系列指令复制从栈顶开始数的第N(1 ~ 16)个元素,并把复制后的元素推入栈顶。DUP系列指令一共有16条,从DUP1(操作码0x80)一直到DUP16(操作码0x8A)。比如PUSH1指令复制栈顶元素,如下图所示:

下面是DUP2指令的操作示意图:

SWAPx指令
SWAP系列指令把栈顶元素和从栈顶开始数的第N(1 ~ 16)+ 1 个元素进行交换。SWAP系列指令一共有16条,从SWAP1(操作码0x90)一直到SWAP16(操作码0x9A)。比如SWAP1指令交换位于栈顶的两个元素,如下图所示:

下面是SWAP2指令的操作示意图:

实例分析
我们用Solidity语言编写一个简单的智能合约,看看以上这些指令是如何应用的:

// stack_demo.sol
pragma solidity ^0.4.24;

contract C {
function foo() public view {
uint32 x = 3;
uint32 y = 4;
uint32 z = x + y;
}
}
用solc --asm stack_demo.sol命令编译上面的智能合约,观察编译器生产的汇编代码(下面仅给出部分输出):

ASM

tag_5:
/* "stack_demo.sol":80:88 uint32 x */
0x0
/* "stack_demo.sol":102:110 uint32 y */
dup1
/* "stack_demo.sol":124:132 uint32 z */
0x0
/* "stack_demo.sol":91:92 3 */
0x3
/* "stack_demo.sol":80:92 uint32 x = 3 */
swap3
pop
/* "stack_demo.sol":113:114 4 */
0x4
/* "stack_demo.sol":102:114 uint32 y = 4 */
swap2
pop
/* "stack_demo.sol":139:140 y */
dup2
/* "stack_demo.sol":135:136 x */
dup4
/* "stack_demo.sol":135:140 x + y */
add
/* "stack_demo.sol":124:140 uint32 z = x + y */
swap1
pop
/* "stack_demo.sol":43:147 function foo() public view {... */
pop
pop
pop
jump // out
我们暂时忽略ADD指令和JUMP指令,下面是指令操作示意图(指令从左到右执行,指令上面是指令操作之后的栈状态):

总结
本文介绍了EVM栈操作指令,下一篇文章将介绍EVM算术运算指令。

原文地址:https://www.cnblogs.com/405845829qq/p/9998211.html

时间: 2024-10-07 22:10:30

以太坊虚拟机介绍2-栈操作指令的相关文章

以太坊虚拟机介绍5-比较操作指令

以太坊虚拟机比较操作指令 EVM定义了6条比较操作指令,见下表: 下面是比较操作指令的操作码分布图: LT.GT.SLT.SGT.EQ这5条指令都是从栈顶弹出两个元素,进行比较,然后把结果(1表示true,0表示false)推入栈顶.其中LT和GT把弹出的元素解释为无符号整数进行比较,SLT和SGT把弹出的元素解释为有符号数进行比较,EQ不关心符号.以LT指令为例,下面是它的操作示意图: ISZERO ISZERO指令从栈顶弹出一个元素,判断它是否为0,如果是,则把1推入栈顶,否则把0推入栈顶.

以太坊虚拟机介绍4-按位运算指令

以太坊虚拟机按位运算指令 EVM定义了8条按位运算指令,见下表: 下面是按位运算指令的操作码分布图: AND.OR.XOR.NOT AND.OR.XOR指令从栈顶弹出两个元素,进行按位运算,然后把结果推入栈顶.以AND指令为例,下面是它的操作示意图: NOT指令将栈元素按位取反,下面是它的操作示意图: 这四条指令分别与Solidity语言里的&.|.^和~运算符直接对应,下面的Solidity代码演示了这四条指令的具体应用(读者可以运行solc --asm --opcodes bitwise_d

以太坊虚拟机介绍

近期打算写一些关于以太坊虚拟机(后面简称EVM)的文章,这是其中的第一篇.这一系列文章想站在EVM指令集的角度,带领读者逐步理解EVM工作原理,进而理解以太坊区块链技术细节.由于网上介绍以太坊的文章也比较多,所以这一系列文章将最大程度减少不必要的废话,直接提供文章想要表达的信息. EVM基本信息编程语言虚拟机一般有两种类型,基于栈,或者基于寄存器.大部分我们所熟知的语言都采用基于栈的虚拟机,比如最著名的Java虚拟机.在游戏领域非常流行的Lua语言则采用了基于寄存器的虚拟机.和JVM一样,EVM

以太坊虚拟机介绍3-算术运算指令

以太坊虚拟机算术运算指令EVM总共定义了11条算术运算指令,见下表: 这些指令从栈顶弹出两到三个元素,进行相应计算,然后把结果推入栈顶.参与计算的元素和结果均被解释为按二的补码编码的整数.如果计算结果(假设为x)溢出(超出2^256),则最终的结果x'取值x % 2^256(%表示取模运算,^表示指数运算). 下面是算术运算指令的操作码分布图: ADD.MUL.SUB.DIV.SDIV.MOD.SMOD.EXP这8条指令操作方式比较类似,从栈顶弹出两个元素,进行计算,然后把计算结果推入栈顶.由于

深入了解以太坊虚拟机第5部分——一个新合约被创建后会发生什么

在该系列文章的前部分,我们学了EVM汇编基础,也学了ABI编码是如何允许外部程序与合约进行通信的.在本文中,我们将会学习一个合约是如何从零创建的. 本系列的相关文章(按照顺序): EVM汇编代码的介绍(第1部分) 固定长度数据类型的表示方法(第2部分) 动态数据类型的表示方法(第3部分) ABI编码外部方法调用的方式(第4部分) 我们目前所见的EVM字节码都是比较清晰明朗的,就是EVM从上往下的执行指令,没有什么隐藏的魔法.合约创建的过程更有意思一些,它将数据和代码之间的界限模糊化. 在学习合约

谈一谈以太坊虚拟机EVM的缺陷与不足

首先,EVM的设计初衷是什么?它为什么被设计成目前我们看的样子呢?根据以太坊官方提供的设计原理说明,EVM的设计目标主要针对以下方面: 简单性(Simplicity) 确定性(Determinism) 节省空间的bytecode 专为区块链设计 更加简单的安全性保证 容易优化 如果读者浏览一下这个文档,会发现EVM的设计看上去都非常的合理.那么问题在哪里呢?问题就出在它和目前主流的技术以及设计范例都格格不入.EVM如果作为一个毫无限制的非现实世界中的设计确实很不错.接下来笔者会围绕EVM各个方面

深入了解以太坊虚拟机第4部分——ABI编码外部方法调用的方式

在本系列的上一篇文章中我们看到了Solidity是如何在EVM存储器中表示复杂数据结构的.但是如果无法交互,数据就是没有意义的.智能合约就是数据和外界的中间体. 在这篇文章中我们将会看到Solidity和EVM可以让外部程序来调用合约的方法并改变它的状态. "外部程序"不限于DApp/JavaScript.任何可以使用HTTP RPC与以太坊节点通信的程序,都可以通过创建一个交易与部署在区块链上的任何合约进行交互. 创建一个交易就像发送一个HTTP请求.Web的服务器会接收你的HTTP

以太坊Go、Java、Python、Ruby、JS客户端介绍

作者:HPB_汪晓明(HPB Team) Go Ethereum 简介 go-ethereum客户端通常被称为geth,它是个命令行界面,执行在Go上实现的完整以太坊节点.通过安装和运行geth,可以参与到以太坊前台实时网络并进行以下操作: 挖掘真的以太币 在不同地址间转移资金 创建合约,发送交易 探索区块历史 及很多其他 Go Ethereum 链接: 网站: http://ethereum.github.io/go-ethereum/ Github: https://github.com/e

以太坊白皮书解析

目录 导读概念 历史沿革 中本聪的理念 作为状态转换系统的比特币 挖矿 默克尔树 其它的区块链应用 脚本 以太坊 以太坊账户 消息和交易 以太坊状态转换函数 代码执行(EVM层) 区块链和挖矿 以太坊应用举例 令牌系统 金融衍生品和价值稳定的货币 身份和信誉系统 去中心化存储 去中心化自治组织( DAO) 进一步的应用 相关杂项 改进版幽灵协议的实施 费用 计算和图灵完备 货币和发行 发行分解 挖矿的中心化 扩展性 综述与结论 综述 结论 导读概念 以太坊中常见的概念: 块:块是存储在区块链中的