EVM (Ethereum Virtual Machine)

Table of Contents

1. EVM

EVM (Ethereum Virtual Machine) 是基于栈的虚拟机。在 EVM 虚拟环境中没有寄存器。比如,指令 ADD,它会从栈上弹出两个元素作为参数,计算完它们的和后把结果保存到栈顶中。

2. 虚拟机指令

EVM 中所有指令都是一个字节,所以最多有 256 个指令。目前,已经定义了约 140 多个指令,如图 1(摘自:The Ethereum Virtual Machine — How does it work?)所示。

evm_opcode.gif

Figure 1: EVM Opcodes

2.1. 指令一览

为了防止 DoS 攻击,几乎所有指令都会消耗 Gas,指令及相关说明如表 1 所示。

Table 1: EVM Opcodes
Opcode Mnemonic Description Ins Outs Gas Extra Info
0x00 STOP Halts execution 0 0 0 -
0x01 ADD Addition operation 2 1 3 -
0x02 MUL Multiplication operation 2 1 5 -
0x03 SUB Subtraction operation 2 1 3 -
0x04 DIV Integer division operation 2 1 5 -
0x05 SDIV Signed integer division operation (truncated) 2 1 5 -
0x06 MOD Modulo remainder operation 2 1 5 -
0x07 SMOD Signed modulo remainder operation 2 1 5 -
0x08 ADDMOD Modulo addition operation 3 1 8 -
0x09 MULMOD Modulo multiplication operation 3 1 8 -
0x0a EXP Exponential operation 2 1 10* -
0x0b SIGNEXTEND Extend length of two's complement signed integer 2 1 5 -
0x0c - 0x0f Unused Unused       -
0x10 LT Less-than comparison 2 1 3 -
0x11 GT Greater-than comparison 2 1 3 -
0x12 SLT Signed less-than comparison 2 1 3 -
0x13 SGT Signed greater-than comparison 2 1 3 -
0x14 EQ Equality comparison 2 1 3 -
0x15 ISZERO Simple not operator 2 1 3 -
0x16 AND Bitwise AND operation 2 1 3 -
0x17 OR Bitwise OR operation 2 1 3 -
0x18 XOR Bitwise XOR operation 2 1 3 -
0x19 NOT Bitwise NOT operation 2 1 3 -
0x1a BYTE Retrieve single byte from word 2 1 3 -
0x1b SHL Shift Left     3 EIP145
0x1c SHR Logical Shift Right     3 EIP145
0x1d SAR Arithmetic Shift Right     3 EIP145
0x20 SHA3 Compute Keccak-256 hash 2 1 30* -
0x21 - 0x2f Unused Unused        
0x30 ADDRESS Get address of currently executing account 0 1 2 -
0x31 BALANCE Get balance of the given account 1 1 400 -
0x32 ORIGIN Get execution origination address 0 1 2 -
0x33 CALLER Get caller address 0 1 2 -
0x34 CALLVALUE Get deposited value by the instruction/transaction responsible for this execution 0 1 2 -
0x35 CALLDATALOAD Get input data of current environment 1 1 3 -
0x36 CALLDATASIZE Get size of input data in current environment 0 1 2* -
0x37 CALLDATACOPY Copy input data in current environment to memory 3 0 3 -
0x38 CODESIZE Get size of code running in current environment 0 1 2 -
0x39 CODECOPY Copy code running in current environment to memory 3 0 3* -
0x3a GASPRICE Get price of gas in current environment 0 1 2 -
0x3b EXTCODESIZE Get size of an account's code 1 1 700 -
0x3c EXTCODECOPY Copy an account's code to memory 4 0 700* -
0x3d RETURNDATASIZE Pushes the size of the return data buffer onto the stack 0 1 2 EIP211
0x3e RETURNDATACOPY Copies data from the return data buffer to memory 3 0 3 EIP211
0x3f Unused -        
0x40 BLOCKHASH Get the hash of one of the 256 most recent complete blocks 1 1 20 -
0x41 COINBASE Get the block's beneficiary address 0 1 2 -
0x42 TIMESTAMP Get the block's timestamp 0 1 2 -
0x43 NUMBER Get the block's number 0 1 2 -
0x44 DIFFICULTY Get the block's difficulty 0 1 2 -
0x45 GASLIMIT Get the block's gas limit 0 1 2 -
0x46 - 0x4f Unused -        
0x50 POP Remove word from stack 1 0 2 -
0x51 MLOAD Load word from memory 1 1 3* -
0x52 MSTORE Save word to memory 2 0 3* -
0x53 MSTORE8 Save byte to memory 2 0 3 -
0x54 SLOAD Load word from storage 1 1 200 -
0x55 SSTORE Save word to storage 2 0 20000* -
0x56 JUMP Alter the program counter 1 0 8 -
0x57 JUMPI Conditionally alter the program counter 2 0 10 -
0x58 GETPC Get the value of the program counter prior to the increment 0 1 2 -
0x59 MSIZE Get the size of active memory in bytes 0 1 2 -
0x5a GAS Get the amount of available gas, including the corresponding reduction the amount of available gas 0 1 2 -
0x5b JUMPDEST Mark a valid destination for jumps 0 0 1 -
0x5c - 0x5f Unused -        
0x60 PUSH1 Place 1 byte item on stack 0 1 3 -
0x61 PUSH2 Place 2-byte item on stack 0 1 3 -
0x62 PUSH3 Place 3-byte item on stack 0 1 3 -
0x63 PUSH4 Place 4-byte item on stack 0 1 3 -
0x64 PUSH5 Place 5-byte item on stack 0 1 3 -
0x65 PUSH6 Place 6-byte item on stack 0 1 3 -
0x66 PUSH7 Place 7-byte item on stack 0 1 3 -
0x67 PUSH8 Place 8-byte item on stack 0 1 3 -
0x68 PUSH9 Place 9-byte item on stack 0 1 3 -
0x69 PUSH10 Place 10-byte item on stack 0 1 3 -
0x6a PUSH11 Place 11-byte item on stack 0 1 3 -
0x6b PUSH12 Place 12-byte item on stack 0 1 3 -
0x6c PUSH13 Place 13-byte item on stack 0 1 3 -
0x6d PUSH14 Place 14-byte item on stack 0 1 3 -
0x6e PUSH15 Place 15-byte item on stack 0 1 3 -
0x6f PUSH16 Place 16-byte item on stack 0 1 3 -
0x70 PUSH17 Place 17-byte item on stack 0 1 3 -
0x71 PUSH18 Place 18-byte item on stack 0 1 3 -
0x72 PUSH19 Place 19-byte item on stack 0 1 3 -
0x73 PUSH20 Place 20-byte item on stack 0 1 3 -
0x74 PUSH21 Place 21-byte item on stack 0 1 3 -
0x75 PUSH22 Place 22-byte item on stack 0 1 3 -
0x76 PUSH23 Place 23-byte item on stack 0 1 3 -
0x77 PUSH24 Place 24-byte item on stack 0 1 3 -
0x78 PUSH25 Place 25-byte item on stack 0 1 3 -
0x79 PUSH26 Place 26-byte item on stack 0 1 3 -
0x7a PUSH27 Place 27-byte item on stack 0 1 3 -
0x7b PUSH28 Place 28-byte item on stack 0 1 3 -
0x7c PUSH29 Place 29-byte item on stack 0 1 3 -
0x7d PUSH30 Place 30-byte item on stack 0 1 3 -
0x7e PUSH31 Place 31-byte item on stack 0 1 3 -
0x7f PUSH32 Place 32-byte (full word) item on stack 0 1 3 -
0x80 DUP1 Duplicate 1st stack item 1 2 3 -
0x81 DUP2 Duplicate 2nd stack item 2 3 3 -
0x82 DUP3 Duplicate 3rd stack item 3 4 3 -
0x83 DUP4 Duplicate 4th stack item 4 5 3 -
0x84 DUP5 Duplicate 5th stack item 5 6 3 -
0x85 DUP6 Duplicate 6th stack item 6 7 3 -
0x86 DUP7 Duplicate 7th stack item 7 8 3 -
0x87 DUP8 Duplicate 8th stack item 8 9 3 -
0x88 DUP9 Duplicate 9th stack item 9 10 3 -
0x89 DUP10 Duplicate 10th stack item 10 11 3 -
0x8a DUP11 Duplicate 11th stack item 11 12 3 -
0x8b DUP12 Duplicate 12th stack item 12 13 3 -
0x8c DUP13 Duplicate 13th stack item 13 14 3 -
0x8d DUP14 Duplicate 14th stack item 14 15 3 -
0x8e DUP15 Duplicate 15th stack item 15 16 3 -
0x8f DUP16 Duplicate 16th stack item 16 17 3 -
0x90 SWAP1 Exchange 1st and 2nd stack items 2 2 3 -
0x91 SWAP2 Exchange 1st and 3rd stack items 3 3 3 -
0x92 SWAP3 Exchange 1st and 4th stack items 4 4 3 -
0x93 SWAP4 Exchange 1st and 5th stack items 5 5 3 -
0x94 SWAP5 Exchange 1st and 6th stack items 6 6 3 -
0x95 SWAP6 Exchange 1st and 7th stack items 7 7 3 -
0x96 SWAP7 Exchange 1st and 8th stack items 8 8 3 -
0x97 SWAP8 Exchange 1st and 9th stack items 9 9 3 -
0x98 SWAP9 Exchange 1st and 10th stack items 10 10 3 -
0x99 SWAP10 Exchange 1st and 11th stack items 11 11 3 -
0x9a SWAP11 Exchange 1st and 12th stack items 12 12 3 -
0x9b SWAP12 Exchange 1st and 13th stack items 13 13 3 -
0x9c SWAP13 Exchange 1st and 14th stack items 14 14 3 -
0x9d SWAP14 Exchange 1st and 15th stack items 15 15 3 -
0x9e SWAP15 Exchange 1st and 16th stack items 16 16 3 -
0x9f SWAP16 Exchange 1st and 17th stack items 17 17 3 -
0xa0 LOG0 Append log record with no topics 2 0 375 -
0xa1 LOG1 Append log record with one topic 3 0 750 -
0xa2 LOG2 Append log record with two topics 4 0 1125 -
0xa3 LOG3 Append log record with three topics 5 0 1500 -
0xa4 LOG4 Append log record with four topics 6 0 1875 -
0xa5 - 0xaf Unused -        
0xb0 JUMPTO Tentative libevmasm has different numbers       EIP615
0xb1 JUMPIF Tentative       EIP615
0xb2 JUMPSUB Tentative       EIP615
0xb4 JUMPSUBV Tentative       EIP615
0xb5 BEGINSUB Tentative       EIP615
0xb6 BEGINDATA Tentative       EIP615
0xb8 RETURNSUB Tentative       EIP615
0xb9 PUTLOCAL Tentative       EIP615
0xba GETLOCAL Tentative       EIP615
0xbb - 0xe0 Unused -        
0xe1 SLOADBYTES Only referenced in pyethereum 3 0 - -
0xe2 SSTOREBYTES Only referenced in pyethereum 3 0 - -
0xe3 SSIZE Only referenced in pyethereum 1 1 - -
0xe4 - 0xef Unused -        
0xf0 CREATE Create a new account with associated code 3 1 32000 -
0xf1 CALL Message-call into an account 7 1 Complicated -
0xf2 CALLCODE Message-call into this account with alternative account's code 7 1 Complicated -
0xf3 RETURN Halt execution returning output data 2 0 0 -
0xf4 DELEGATECALL Message-call into this account with an alternative account's code, but persisting into this account with an alternative account's code 6 1 Complicated -
0xf5 CREATE2 Create a new account and set creation address to sha3(sender + sha3(init code)) % 2**160       -
0xf6 - 0xf9 Unused -       -
0xfa STATICCALL Similar to CALL, but does not modify state 6 1 40 -
0xfb - 0xfc Unused -     - -
0xfd REVERT Stop execution and revert state changes, without consuming all provided gas and providing a reason 2 0 0 -
0xfe INVALID Designated invalid instruction     0 -
0xff SELFDESTRUCT Halt execution and register account for later deletion 1 0 5000* -

1 中,Ins 列表示当前指令会从栈中读取多少个参数;Outs 列表示当前指令会向栈中写入多少个参数;Gas 列表示其消耗的 Gas,如果 Gas 数旁边标记有星号则表示 Gas 消耗根据参数的不同而不同。

2.2. 退还 Gas 的操作

下面两个操作会“退还” Gas:

  1. 把 storage 的值从“非零值”设置为“零”(SSTORE 指令);
  2. 销毁合约的 SELFDESTRUCT 指令(注:在伦敦硬分叉之后,SELFDESTRUCT 指令不再退还 Gas,详情可参考 EIP-3529)。

2.3. 反编译实例

使用 evmdisasm 子命令可以反编译二进制文件,如:

$ echo "6005600401" > code.txt
$ evm disasm code.txt
6005600401
00000: PUSH1 0x05
00002: PUSH1 0x04
00004: ADD

使用 evm 的 run 子命令可以执行二进制,指定 --debug 选项的话会输出栈中的内容:

$ evm --code 6005600401 --debug run
0x
#### TRACE ####
PUSH1           pc=00000000 gas=10000000000 cost=3

PUSH1           pc=00000002 gas=9999999997 cost=3
Stack:
00000000  0000000000000000000000000000000000000000000000000000000000000005

ADD             pc=00000004 gas=9999999994 cost=3
Stack:
00000000  0000000000000000000000000000000000000000000000000000000000000004
00000001  0000000000000000000000000000000000000000000000000000000000000005

STOP            pc=00000005 gas=9999999991 cost=0
Stack:
00000000  0000000000000000000000000000000000000000000000000000000000000009

#### LOGS ####

从上面输出中,可以看到栈顶内容为 9 。

3. 参考

https://ethervm.io/ (形象地介绍了每个指令的含义)
https://github.com/ethereumbook/ethereumbook/blob/develop/13evm.asciidoc (《精通以太坊》一书中关于虚拟机的章节)

Author: cig01

Created: <2019-02-24 Sun>

Last updated: <2021-06-25 Fri>

Creator: Emacs 27.1 (Org mode 9.4)