EVM操作码速查表【以太坊虚拟机】

以太坊EVM是栈式虚拟机,字长为256位,用于在以太坊区块链上运行智能合约。 EVM采用单字节操作码(Opcode),因此全部操作码定义在00~ff区间。本文 提供EVM操作码的速查简表和详表,方便以太坊智能合约开发人员、安全研究人员 在开发、优化或分析以太坊智能合约的漏洞时作为指令手册使用。

用自己熟悉的语言学习 以太坊DApp开发Java | Php | Python | .Net / C# | Golang | Node.JS | Flutter / Dart

1、EVM操作码简表

000102030405060708090A0B
101112131415161718岁191A1B1C一维
20
303132333435363738393A3B3C3D3E3楼
404142434445
505152535455565758595A5B
606162636465666768696A6B6C6D6E6楼
707172737475767778797A7B7C7D7E7楼
808182838485868788898A8B8C8D8E8楼
909192939495969798999A9B9C9D9E9楼
A0A1A2A3A4
B0B1B2
F0F1F2F3F4F5F AFDFF

2、EVM总览

以太坊虚拟机(EVM)是一个基于栈的big-endian虚拟机,字长为256位,用于在以太坊区块链上运行智能合约。 智能合约就像普通账户一样,不同之处在于它们在接收交易时运行EVM字节码,从而使其能够执行 计算和进一步交易。交易可以携带0或更多字节数据的有效负载,该有效负载用于指定与以太坊合约 的交互类型以及任何其他信息。

合约执行从字节码的开头开始。 除PUSH操作码采用立即数外,每个操作码均编码为一个字节。 所有操作码都从堆栈顶部弹出其操作数,然后推入其结果。

3、合约创建

创建智能合约的交易的数据有效载荷本身就是字节码,它运行合约构造函数, 设置初始合约状态并返回最终合约字节码。

一旦部署完成,构造函数就不会出现在部署后的合约中。

4、合约交互

通常,合约提供公开的ABI,这是用户可以与以太坊智能合约进行交互的可支持方法的列表。 为了与合约进行交互,用户需要提交一笔交易,该交易携带任何数量的wei(包括0) 以及根据ABI格式化的数据有效负载,并指定交互的类型和任何其他参数。

合约运行时,有四种主要的数据处理方式:

调用数据/Call Data

这是与智能合约交易相关的数据。它通常包含一个4字节的方法标识符然后是序列化参数。

请参阅:CALLDATALOADCALLDATASIZECALLDATACOPY

栈 / Stack

EVM维护一个uint256栈,用于保存局部变量、函数调用参数和返回地址。 在返回地址和其他变量之间进行区分是比较困难的。

在此页面上,栈顶表示为stack [-1],后跟stack [-2],…:

stack[-1] stack[-2]

请参阅:PUSH1DUP1SWAP1POP

内存 / Memory

内存是uint8的数组,用于在执行合约时保存暂态数据。

它不会在不同交易之间持久化。

请参阅:MLOAD,MSTORE,MSTORE8

存储 / Storage

存储是一个持久的关联映射,以uint256为键、uint256为值。

所有的合约字段和映射都保存在存储器中。

可以使用web3.eth.getStorageAt(address,key)查看合约的存储字段。

请参阅:SLOADSSTORE

5、EVM操作码详表

uint8 助记符 栈输入 栈输出 表达式 备注说明
00 STOP - - STOP() 停止合约执行
01 ADD
ab
a + b
a + b (u)int256加法取模2256
02 MUL
ab
a b
a b (u)int256乘法取模2256
03 SUB
ab
a - b
a - b (u)int256减法取模2256
04 DIV
ab
a // b
a // b uint256除法
05 SDIV
ab
a // b
a // b int256除法
06 MOD
ab
a % b
a % b uint256取模
07 SMOD
ab
a % b
a % b int256取模
08 ADDMOD
abN
(a + b) % N
(a + b) % N (u)int256加法取模N
09 MULMOD
abN
(a b) % N
(a b) % N (u)int256乘法取模N
0A EXP
ab
a b
a b uint256指数结果取模2256
0B SIGNEXTEND
bx
y
y = SIGNEXTEND(x, b) 将x从 (b + 1) 8 位有符号扩展为 256位
0C Invalid - - - -
0D Invalid - - - -
0E Invalid - - - -
0F Invalid - - - -
10 LT
ab
a < b
a < b uint256比较
11 GT
ab
a > b
a > b uint256比较
12 SLT
ab
a < b
a < b int256比较
13 SGT
ab
a > b
a > b int256比较
14 EQ
ab
a == b
a == b (u)int256相等比较
15 ISZERO
a
a == 0
a == 0 (u)int256零比较
16 AND
ab
a & b
a & b 256位的位与计算
17 OR
ab
a | b
a | b 256位的位或计算
18 XOR
ab
a ^ b
a ^ b 256位的异或计算
19 NOT
a
~a
~a 256位的位取反计算
1A BYTE
ix
y
y = (x >> (248 - i 8)) & 0xFF 返回(u)int256 x从最高字节开始的第i字节
1B SHL
shiftvalue
value << shift
value << shift 256位左移
1C SHR
shiftvalue
value >> shift
value >> shift 256位右移
1D SAR
shiftvalue
value >> shift
value >> shift int256右移位
1E Invalid - - - -
1F Invalid - - - -
20 SHA3
offsetlength
hash
hash = keccak256(memory[offset:offset+length]) keccak256哈希
21 Invalid - - - -
22 Invalid - - - -
23 Invalid - - - -
24 Invalid - - - -
25 Invalid - - - -
26 Invalid - - - -
27 Invalid - - - -
28 Invalid - - - -
29 Invalid - - - -
2A Invalid - - - -
2B Invalid - - - -
2C Invalid - - - -
2D Invalid - - - -
2E Invalid - - - -
2F Invalid - - - -
30 ADDRESS -
address(this)
address(this) 当前执行合约的地址
31 BALANCE
addr
address(addr).balance
address(addr).balance 指定地址的余额,单位wei
32 ORIGIN -
tx.origin
tx.origin 交易发起方地址
33 CALLER -
msg.caller
msg.caller 消息调用方地址
34 CALLVALUE -
msg.value
msg.value 以wei为单位的消息携带金额
35 CALLDATALOAD
i
msg.data[i:i+32]
msg.data[i:i+32] 从消息数据读取一个(u)int256
36 CALLDATASIZE -
msg.data.size
msg.data.size 以字节为单位的消息数据长度
37 CALLDATACOPY
destOffsetoffsetlength
- memory[destOffset:destOffset+length] = msg.data[offset:offset+length] 拷贝消息数据
38 CODESIZE -
address(this).code.size
address(this).code.size 以字节为单位的当前执行合约的长度
39 CODECOPY
destOffsetoffsetlength
- memory[destOffset:destOffset+length] = address(this).code[offset:offset+length] 拷贝当前执行合约的字节码
3A GASPRICE -
tx.gasprice
tx.gasprice 当前执行交易的单位gas价格,以wei为单位
3B EXTCODESIZE
addr
address(addr).code.size
address(addr).code.size 指定地址处的合约字节码长度,以字节为单位
3C EXTCODECOPY
addrdestOffsetoffsetlength
- memory[destOffset:destOffset+length] = address(addr).code[offset:offset+length] 拷贝合约字节码
3D RETURNDATASIZE -
size
size = RETURNDATASIZE() 最后一个外部调用的返回数据的长度,以字节为单位
3E RETURNDATACOPY
destOffsetoffsetlength
- memory[destOffset:destOffset+length] = RETURNDATA[offset:offset+length] 拷贝返回的数据
3F EXTCODEHASH
addr
hash
hash = address(addr).exists ? keccak256(address(addr).code) : 0 指定地址的合约字节码的哈希,请参考EIP-1052事件
40 BLOCKHASH
blockNumber
hash
hash = block.blockHash(blockNumber) 指定区块的哈希,仅适用于最近的256个区块,不包括当前区块
41 COINBASE -
block.coinbase
block.coinbase 当前区块矿工的地址
42 TIMESTAMP -
block.timestamp
block.timestamp 当前区块的UNIX时间戳,以秒为单位
43 NUMBER -
block.number
block.number 当前区块号
44 DIFFICULTY -
block.difficulty
block.difficulty 当前区块难度
45 GASLIMIT -
block.gaslimit
block.gaslimit 当前区块GAS上限
46 Invalid - - - -
47 Invalid - - - -
48 Invalid - - - -
49 Invalid - - - -
4A Invalid - - - -
4B Invalid - - - -
4C Invalid - - - -
4D Invalid - - - -
4E Invalid - - - -
4F Invalid - - - -
50 POP
- POP() 弹出栈顶(u)int256 并丢弃
51 MLOAD
offset
value
value = memory[offset:offset+32] 从内存读取一个(u)int256
52 MSTORE
offsetvalue
- memory[offset:offset+32] = value 向内存写入一个(u)int256
53 MSTORE8
offsetvalue
- memory[offset] = value & 0xFF 向内存写入一个uint8
54 SLOAD
key
value
value = storage[key] 从存储读取一个(u)int256
55 SSTORE
keyvalue
- storage[key] = value 向存储写入一个(u)int256
56 JUMP
destination
- $pc = destination 无条件跳转
57 JUMPI
destinationcondition
- $pc = cond ? destination : $pc + 1 条件为真时跳转
58 PC -
$pc
$pc 程序计数器
59 MSIZE -
size
size = MSIZE() 当前合约执行的内存大小,以字节为单位
5A GAS -
gasRemaining
gasRemaining = GAS() 剩余的GAS
5B JUMPDEST - - 用于注解可能的跳转目标的元数据
5C Invalid - - - -
5D Invalid - - - -
5E Invalid - - - -
5F Invalid - - - -
60 PUSH1 -
uint8
PUSH(uint8) 将1字节数值压入栈
61 PUSH2 -
uint16
PUSH(uint16) 将2字节数值压入栈
62 PUSH3 -
uint24
PUSH(uint24) 将3字节数值压入栈
63 PUSH4 -
uint32
PUSH(uint32) 将4字节数值压入栈
64 PUSH5 -
uint40
PUSH(uint40) 将5字节数值压入栈
65 PUSH6 -
uint48
PUSH(uint48) 将6字节数值压入栈
66 PUSH7 -
uint56
PUSH(uint56) 将7字节数值压入栈
67 PUSH8 -
uint64
PUSH(uint64) 将8字节数值压入栈
68 PUSH9 -
uint72
PUSH(uint72) 将9字节数值压入栈
69 PUSH10 -
uint80
PUSH(uint80) 将10字节数值压入栈
6A PUSH11 -
uint88
PUSH(uint88) 将11字节数值压入栈
6B PUSH12 -
uint96
PUSH(uint96) 将12字节数值压入栈
6C PUSH13 -
uint104
PUSH(uint104) 将13字节数值压入栈
6D PUSH14 -
uint112
PUSH(uint112) 将14字节数值压入栈
6E PUSH15 -
uint120
PUSH(uint120) 将15字节数值压入栈
6F PUSH16 -
uint128
PUSH(uint128) 将16字节数值压入栈
70 PUSH17 -
uint136
PUSH(uint136) 将17字节数值压入栈
71 PUSH18 -
uint144
PUSH(uint144) 将18字节数值压入栈
72 PUSH19 -
uint152
PUSH(uint152) 将19字节数值压入栈
73 PUSH20 -
uint160
PUSH(uint160) 将20字节数值压入栈
74 PUSH21 -
uint168
PUSH(uint168) 将21字节数值压入栈
75 PUSH22 -
uint176
PUSH(uint176) 将22字节数值压入栈
76 PUSH23 -
uint184
PUSH(uint184) 将23字节数值压入栈
77 PUSH24 -
uint192
PUSH(uint192) 将24字节数值压入栈
78 PUSH25 -
uint200
PUSH(uint200) 将25字节数值压入栈
79 PUSH26 -
uint208
PUSH(uint208) 将26字节数值压入栈
7A PUSH27 -
uint216
PUSH(uint216) 将27字节数值压入栈
7B PUSH28 -
uint224
PUSH(uint224) 将28字节数值压入栈
7C PUSH29 -
uint232
PUSH(uint232) 将29字节数值压入栈
7D PUSH30 -
uint240
PUSH(uint240) 将30字节数值压入栈
7E PUSH31 -
uint248
PUSH(uint248) 将31字节数值压入栈
7F PUSH32 -
uint256
PUSH(uint256) 将32字节数值压入栈
80 DUP1
value
valuevalue
PUSH(value) 克隆栈上最后一个值
81 DUP2
value
valuevalue
PUSH(value) 克隆栈上倒数第二个值
82 DUP3
value
valuevalue
PUSH(value) 克隆栈上倒数第三个值
83 DUP4
value
valuevalue
PUSH(value) 克隆栈上倒数第四个值
84 DUP5
value
valuevalue
PUSH(value) 克隆栈上倒数第五个值
85 DUP6
value
valuevalue
PUSH(value) 克隆栈上倒数第六个值
86 DUP7
value
valuevalue
PUSH(value) 克隆栈上倒数第七个值
87 DUP8
value
valuevalue
PUSH(value) 克隆栈上倒数第八个值
88 DUP9
value
valuevalue
PUSH(value) 克隆栈上倒数第九个值
89 DUP10
value
valuevalue
PUSH(value) 克隆栈上倒数第10个值
8A DUP11
value
valuevalue
PUSH(value) 克隆栈上倒数第11个值
8B DUP12
value
valuevalue
PUSH(value) 克隆栈上倒数第12个值
8C DUP13
value
valuevalue
PUSH(value) 克隆栈上倒数第13个值
8D DUP14
value
valuevalue
PUSH(value) 克隆栈上倒数第14个值
8E DUP15
value
valuevalue
PUSH(value) 克隆栈上倒数第15个值
8F DUP16
value
valuevalue
PUSH(value) 克隆栈上倒数第16个值
90 SWAP1
ab
ba
a, b = b, a 交换栈顶两个成员
91 SWAP2
ab
ba
a, b = b, a 交换栈顶与倒数第3个成员
92 SWAP3
ab
b_a
a, b = b, a 交换栈顶与倒数第4个成员
93 SWAP4
ab
ba
a, b = b, a 交换栈顶与倒数第5个成员
94 SWAP5
ab
ba
a, b = b, a 交换栈顶与倒数第6个成员
95 SWAP6
ab
ba
a, b = b, a 交换栈顶与倒数第7个成员
96 SWAP7
ab
ba
a, b = b, a 交换栈顶与倒数第8个成员
97 SWAP8
ab
ba
a, b = b, a 交换栈顶与倒数第9个成员
98 SWAP9
ab
ba
a, b = b, a 交换栈顶与倒数第10个成员
99 SWAP10
ab
ba
a, b = b, a 交换栈顶与倒数第11个成员
9A SWAP11
ab
ba
a, b = b, a 交换栈顶与倒数第12个成员
9B SWAP12
ab
ba
a, b = b, a 交换栈顶与倒数第13个成员
9C SWAP13
ab
ba
a, b = b, a 交换栈顶与倒数第14个成员
9D SWAP14
ab
ba
a, b = b, a 交换栈顶与倒数第15个成员
9E SWAP15
ab
ba
a, b = b, a 交换栈顶与倒数第16个成员
9F SWAP16
ab
ba
a, b = b, a 交换栈顶与倒数第17个成员
A0 LOG0
offsetlength
- LOG0(memory[offset:offset+length]) 触发事件
A1 LOG1
offsetlengthtopic0
- LOG1(memory[offset:offset+length], topic0) 触发事件
A2 LOG2
offsetlengthtopic0topic1
- LOG2(memory[offset:offset+length], topic0, topic1) 触发事件
A3 LOG3
offsetlengthtopic0topic1topic2
- LOG3(memory[offset:offset+length], topic0, topic1, topic2) 触发事件
A4 LOG4
offsetlengthtopic0topic1topic2topic3
- LOG4(memory[offset:offset+length], topic0, topic1, topic2, topic3) 触发事件
A5 Invalid - - - -
A6 Invalid - - - -
A7 Invalid - - - -
A8 Invalid - - - -
A9 Invalid - - - -
AA Invalid - - - -
AB Invalid - - - -
AC Invalid - - - -
AD Invalid - - - -
AE Invalid - - - -
AF Invalid - - - -
B0 PUSH - - ??? ???
B1 DUP - - ??? ???
B2 SWAP - - ??? ???
B3 Invalid - - - -
B4 Invalid - - - -
B5 Invalid - - - -
B6 Invalid - - - -
B7 Invalid - - - -
B8 Invalid - - - -
B9 Invalid - - - -
BA Invalid - - - -
BB Invalid - - - -
BC Invalid - - - -
BD Invalid - - - -
BE Invalid - - - -
BF Invalid - - - -
C0 Invalid - - - -
C1 Invalid - - - -
C2 Invalid - - - -
C3 Invalid - - - -
C4 Invalid - - - -
C5 Invalid - - - -
C6 Invalid - - - -
C7 Invalid - - - -
C8 Invalid - - - -
C9 Invalid - - - -
CA Invalid - - - -
CB Invalid - - - -
CC Invalid - - - -
CD Invalid - - - -
CE Invalid - - - -
CF Invalid - - - -
D0 Invalid - - - -
D1 Invalid - - - -
D2 Invalid - - - -
D3 Invalid - - - -
D4 Invalid - - - -
D5 Invalid - - - -
D6 Invalid - - - -
D7 Invalid - - - -
D8 Invalid - - - -
D9 Invalid - - - -
DA Invalid - - - -
DB Invalid - - - -
DC Invalid - - - -
DD Invalid - - - -
DE Invalid - - - -
DF Invalid - - - -
E0 Invalid - - - -
E1 Invalid - - - -
E2 Invalid - - - -
E3 Invalid - - - -
E4 Invalid - - - -
E5 Invalid - - - -
E6 Invalid - - - -
E7 Invalid - - - -
E8 Invalid - - - -
E9 Invalid - - - -
EA Invalid - - - -
EB Invalid - - - -
EC Invalid - - - -
ED Invalid - - - -
EE Invalid - - - -
EF Invalid - - - -
F0 CREATE
valueoffsetlength
addr
addr = new memory[offset:offset+length].value(value) 创建子合约
F1 CALL
gasaddrvalueargsOffsetargsLengthretOffsetretLength
success
success, memory[retOffset:retOffset+retLength] = address(addr).call.gas(gas).value(value) (memory[argsOffset:argsOffset+argsLength]) 调用另一个合约中的方法
F2 CALLCODE
gasaddrvalueargsOffsetargsLengthretOffsetretLength
success
success, memory[retOffset:retOffset+retLength] = address(addr).callcode.gas(gas).value(value) (memory[argsOffset:argsOffset+argsLength]) ???
F3 RETURN
offsetlength
- return memory[offset:offset+length] 从这个合约调用返回
F4 DELEGATECALL
gasaddrargsOffsetargsLengthretOffsetretLength
success
success, memory[retOffset:retOffset+retLength] = address(addr).delegatecall.gas(gas) (memory[argsOffset:argsOffset+argsLength]) 使用当前合约的存储调用另一个合约的方法
F5 CREATE2
valueoffsetlengthsalt
addr
addr = new memory[offset:offset+length].value(value) 使用确定的地址创建子合约,参见see EIP-1014
F6 Invalid - - - -
F7 Invalid - - - -
F8 Invalid - - - -
F9 Invalid - - - -
FA STATICCALL
gasaddrargsOffsetargsLengthretOffsetretLength
success
success, memory[retOffset:retOffset+retLength] = address(addr).staticcall.gas(gas) (memory[argsOffset:argsOffset+argsLength]) 调用另一个合约的方法,不允许合约创建、事件发送、存储修改和合约销毁等引起状态改变的方法,参见EIP-214
FB Invalid - - - -
FC Invalid - - - -
FD REVERT
offsetlength
- revert(memory[offset:offset+length]) 回滚交易并返回数据
FE Invalid - - - -
FF SELFDESTRUCT
addr
- selfdestruct(address(addr)) 销毁合约并将所有资金发送给addr地址

原文链接:Ethereum Virtual Machine Opcodes

汇智网翻译整理,转载请标明出处