以太坊虚拟机算术运算指令
EVM总共定义了11条算术运算指令,见下表:
这些指令从栈顶弹出两到三个元素,进行相应计算,然后把结果推入栈顶。参与计算的元素和结果均被解释为按二的补码编码的整数。如果计算结果(假设为x)溢出(超出2^256),则最终的结果x’取值x % 2^256(%表示取模运算,^表示指数运算)。
下面是算术运算指令的操作码分布图:
ADD、MUL、SUB、DIV、SDIV、MOD、SMOD、EXP
这8条指令操作方式比较类似,从栈顶弹出两个元素,进行计算,然后把计算结果推入栈顶。由于采用二的补码表示整数时,加法、减法和乘法运算不用考虑符号位,所以加法、减法和乘法运算都只有一条指令。整除和取模运算需要考虑符号位,所以各有两条指令。指数运算只操作无符号整数。以ADD指令为例,下面是它的操作示意图:
ADDMOD和MULMOD
MULMOD指令依次从栈顶弹出x、y、z三个数,先计算x和y的乘积(不受溢出限制),再计算乘积和z的模,最后把结果推入栈顶。假定乘积不会溢出,那么MULMOD(x, y, z)等价于x * y % z,下面是MULMOD指令的操作示意图:
ADDMOD指令和MULMOD指令类似,只不过把乘法换成了加法。下面是ADDMOD指令的操作示意图:
SIGNEXTEND
SIGNEXTEND指令从栈顶依次弹出k和x,并把x解释为k+1(0 <= k <= 31)字节有符号整数,然后把x符号扩展至32字节。比如x是二进制10000000,k是0,则符号扩展之后,结果为二进制1111…10000000(共249个1)。下面是SIGNEXTEND指令的操作示意图:
实例分析
ADD、MUL、SUB、DIV、SDIV、MOD、SMOD、EXP指令与Solidity语言里的+、*、-、/、%、** 运算符直接对应。ADDMOD指令对应addmod()函数,MULMOD指令对应mulmod()函数。暂时还没有搞清楚SIGNEXTEND指令的用法,等以后再补充。下面的Solidity代码演示了EVM算术运算指令的具体应用:
// arith_demo.sol
pragma solidity ^0.4.24;
contract C {
function test() public view {
int s1; int s2; int s3;
uint u1; uint u2; uint u3;
uint k;
u3 = u1 + u2; // ADD
u3 = u1 * u2; // MUL
u3 = u1 - u2; // SUB
u3 = u1 / u2; // DIV
s3 = s1 / s2; // SDIV
u3 = u1 % u2; // MOD
s3 = s1 % s2; // SMOD
u3 = u1 ** u2; // EXP
u3 = addmod(u1, u2, k); // ADDMOD
u3 = mulmod(u1, u2, k); // MULMOD
}
}
读者可以运行solc --asm --opcodes arith_demo.sol命令观察编译器生成的字节码。
总结
本文介绍了EVM算术运算指令,下一篇文章将介绍EVM按位运算指令。
原文地址:https://www.cnblogs.com/405845829qq/p/9998226.html