/src/solidity/libevmasm/Instruction.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | This file is part of solidity. |
3 | | |
4 | | solidity is free software: you can redistribute it and/or modify |
5 | | it under the terms of the GNU General Public License as published by |
6 | | the Free Software Foundation, either version 3 of the License, or |
7 | | (at your option) any later version. |
8 | | |
9 | | solidity is distributed in the hope that it will be useful, |
10 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | | GNU General Public License for more details. |
13 | | |
14 | | You should have received a copy of the GNU General Public License |
15 | | along with solidity. If not, see <http://www.gnu.org/licenses/>. |
16 | | */ |
17 | | // SPDX-License-Identifier: GPL-3.0 |
18 | | /** @file Instruction.h |
19 | | * @author Gav Wood <i@gavwood.com> |
20 | | * @date 2014 |
21 | | */ |
22 | | |
23 | | #pragma once |
24 | | |
25 | | #include <libevmasm/Exceptions.h> |
26 | | #include <libsolutil/Common.h> |
27 | | #include <libsolutil/Assertions.h> |
28 | | #include <liblangutil/EVMVersion.h> |
29 | | #include <liblangutil/Exceptions.h> |
30 | | |
31 | | namespace solidity::evmasm |
32 | | { |
33 | | |
34 | | /// Virtual machine bytecode instruction. |
35 | | enum class Instruction: uint8_t |
36 | | { |
37 | | STOP = 0x00, ///< halts execution |
38 | | ADD, ///< addition operation |
39 | | MUL, ///< multiplication operation |
40 | | SUB, ///< subtraction operation |
41 | | DIV, ///< integer division operation |
42 | | SDIV, ///< signed integer division operation |
43 | | MOD, ///< modulo remainder operation |
44 | | SMOD, ///< signed modulo remainder operation |
45 | | ADDMOD, ///< unsigned modular addition |
46 | | MULMOD, ///< unsigned modular multiplication |
47 | | EXP, ///< exponential operation |
48 | | SIGNEXTEND, ///< extend length of signed integer |
49 | | |
50 | | LT = 0x10, ///< less-than comparison |
51 | | GT, ///< greater-than comparison |
52 | | SLT, ///< signed less-than comparison |
53 | | SGT, ///< signed greater-than comparison |
54 | | EQ, ///< equality comparison |
55 | | ISZERO, ///< simple not operator |
56 | | AND, ///< bitwise AND operation |
57 | | OR, ///< bitwise OR operation |
58 | | XOR, ///< bitwise XOR operation |
59 | | NOT, ///< bitwise NOT operation |
60 | | BYTE, ///< retrieve single byte from word |
61 | | SHL, ///< bitwise SHL operation |
62 | | SHR, ///< bitwise SHR operation |
63 | | SAR, ///< bitwise SAR operation |
64 | | |
65 | | KECCAK256 = 0x20, ///< compute KECCAK-256 hash |
66 | | |
67 | | ADDRESS = 0x30, ///< get address of currently executing account |
68 | | BALANCE, ///< get balance of the given account |
69 | | ORIGIN, ///< get execution origination address |
70 | | CALLER, ///< get caller address |
71 | | CALLVALUE, ///< get deposited value by the instruction/transaction responsible for this execution |
72 | | CALLDATALOAD, ///< get input data of current environment |
73 | | CALLDATASIZE, ///< get size of input data in current environment |
74 | | CALLDATACOPY, ///< copy input data in current environment to memory |
75 | | CODESIZE, ///< get size of code running in current environment |
76 | | CODECOPY, ///< copy code running in current environment to memory |
77 | | GASPRICE, ///< get price of gas in current environment |
78 | | EXTCODESIZE, ///< get external code size (from another contract) |
79 | | EXTCODECOPY, ///< copy external code (from another contract) |
80 | | RETURNDATASIZE = 0x3d, ///< get size of return data buffer |
81 | | RETURNDATACOPY = 0x3e, ///< copy return data in current environment to memory |
82 | | EXTCODEHASH = 0x3f, ///< get external code hash (from another contract) |
83 | | |
84 | | BLOCKHASH = 0x40, ///< get hash of most recent complete block |
85 | | COINBASE, ///< get the block's coinbase address |
86 | | TIMESTAMP, ///< get the block's timestamp |
87 | | NUMBER, ///< get the block's number |
88 | | PREVRANDAO, ///< get randomness provided by the beacon chain |
89 | | GASLIMIT, ///< get the block's gas limit |
90 | | CHAINID, ///< get the config's chainid param |
91 | | SELFBALANCE, ///< get balance of the current account |
92 | | BASEFEE, ///< get the block's basefee |
93 | | BLOBHASH = 0x49, ///< get a versioned hash of one of the blobs associated with the transaction |
94 | | BLOBBASEFEE = 0x4a, ///< get the block's blob basefee |
95 | | |
96 | | POP = 0x50, ///< remove item from stack |
97 | | MLOAD, ///< load word from memory |
98 | | MSTORE, ///< save word to memory |
99 | | MSTORE8, ///< save byte to memory |
100 | | SLOAD, ///< load word from storage |
101 | | SSTORE, ///< save word to storage |
102 | | JUMP, ///< alter the program counter |
103 | | JUMPI, ///< conditionally alter the program counter |
104 | | PC, ///< get the program counter |
105 | | MSIZE, ///< get the size of active memory |
106 | | GAS, ///< get the amount of available gas |
107 | | JUMPDEST, ///< set a potential jump destination |
108 | | TLOAD = 0x5c, ///< load word from transient storage |
109 | | TSTORE = 0x5d, ///< save word to transient storage |
110 | | MCOPY = 0x5e, ///< copy between memory areas |
111 | | |
112 | | PUSH0 = 0x5f, ///< place the value 0 on stack |
113 | | PUSH1 = 0x60, ///< place 1 byte item on stack |
114 | | PUSH2, ///< place 2 byte item on stack |
115 | | PUSH3, ///< place 3 byte item on stack |
116 | | PUSH4, ///< place 4 byte item on stack |
117 | | PUSH5, ///< place 5 byte item on stack |
118 | | PUSH6, ///< place 6 byte item on stack |
119 | | PUSH7, ///< place 7 byte item on stack |
120 | | PUSH8, ///< place 8 byte item on stack |
121 | | PUSH9, ///< place 9 byte item on stack |
122 | | PUSH10, ///< place 10 byte item on stack |
123 | | PUSH11, ///< place 11 byte item on stack |
124 | | PUSH12, ///< place 12 byte item on stack |
125 | | PUSH13, ///< place 13 byte item on stack |
126 | | PUSH14, ///< place 14 byte item on stack |
127 | | PUSH15, ///< place 15 byte item on stack |
128 | | PUSH16, ///< place 16 byte item on stack |
129 | | PUSH17, ///< place 17 byte item on stack |
130 | | PUSH18, ///< place 18 byte item on stack |
131 | | PUSH19, ///< place 19 byte item on stack |
132 | | PUSH20, ///< place 20 byte item on stack |
133 | | PUSH21, ///< place 21 byte item on stack |
134 | | PUSH22, ///< place 22 byte item on stack |
135 | | PUSH23, ///< place 23 byte item on stack |
136 | | PUSH24, ///< place 24 byte item on stack |
137 | | PUSH25, ///< place 25 byte item on stack |
138 | | PUSH26, ///< place 26 byte item on stack |
139 | | PUSH27, ///< place 27 byte item on stack |
140 | | PUSH28, ///< place 28 byte item on stack |
141 | | PUSH29, ///< place 29 byte item on stack |
142 | | PUSH30, ///< place 30 byte item on stack |
143 | | PUSH31, ///< place 31 byte item on stack |
144 | | PUSH32, ///< place 32 byte item on stack |
145 | | |
146 | | DUP1 = 0x80, ///< copies the highest item in the stack to the top of the stack |
147 | | DUP2, ///< copies the second highest item in the stack to the top of the stack |
148 | | DUP3, ///< copies the third highest item in the stack to the top of the stack |
149 | | DUP4, ///< copies the 4th highest item in the stack to the top of the stack |
150 | | DUP5, ///< copies the 5th highest item in the stack to the top of the stack |
151 | | DUP6, ///< copies the 6th highest item in the stack to the top of the stack |
152 | | DUP7, ///< copies the 7th highest item in the stack to the top of the stack |
153 | | DUP8, ///< copies the 8th highest item in the stack to the top of the stack |
154 | | DUP9, ///< copies the 9th highest item in the stack to the top of the stack |
155 | | DUP10, ///< copies the 10th highest item in the stack to the top of the stack |
156 | | DUP11, ///< copies the 11th highest item in the stack to the top of the stack |
157 | | DUP12, ///< copies the 12th highest item in the stack to the top of the stack |
158 | | DUP13, ///< copies the 13th highest item in the stack to the top of the stack |
159 | | DUP14, ///< copies the 14th highest item in the stack to the top of the stack |
160 | | DUP15, ///< copies the 15th highest item in the stack to the top of the stack |
161 | | DUP16, ///< copies the 16th highest item in the stack to the top of the stack |
162 | | |
163 | | SWAP1 = 0x90, ///< swaps the highest and second highest value on the stack |
164 | | SWAP2, ///< swaps the highest and third highest value on the stack |
165 | | SWAP3, ///< swaps the highest and 4th highest value on the stack |
166 | | SWAP4, ///< swaps the highest and 5th highest value on the stack |
167 | | SWAP5, ///< swaps the highest and 6th highest value on the stack |
168 | | SWAP6, ///< swaps the highest and 7th highest value on the stack |
169 | | SWAP7, ///< swaps the highest and 8th highest value on the stack |
170 | | SWAP8, ///< swaps the highest and 9th highest value on the stack |
171 | | SWAP9, ///< swaps the highest and 10th highest value on the stack |
172 | | SWAP10, ///< swaps the highest and 11th highest value on the stack |
173 | | SWAP11, ///< swaps the highest and 12th highest value on the stack |
174 | | SWAP12, ///< swaps the highest and 13th highest value on the stack |
175 | | SWAP13, ///< swaps the highest and 14th highest value on the stack |
176 | | SWAP14, ///< swaps the highest and 15th highest value on the stack |
177 | | SWAP15, ///< swaps the highest and 16th highest value on the stack |
178 | | SWAP16, ///< swaps the highest and 17th highest value on the stack |
179 | | |
180 | | LOG0 = 0xa0, ///< Makes a log entry; no topics. |
181 | | LOG1, ///< Makes a log entry; 1 topic. |
182 | | LOG2, ///< Makes a log entry; 2 topics. |
183 | | LOG3, ///< Makes a log entry; 3 topics. |
184 | | LOG4, ///< Makes a log entry; 4 topics. |
185 | | |
186 | | DATALOADN = 0xd1, ///< load data from EOF data section |
187 | | |
188 | | RJUMP = 0xe0, ///< relative jump |
189 | | RJUMPI = 0xe1, ///< conditional relative jump |
190 | | CALLF = 0xe3, ///< call function in a EOF code section |
191 | | RETF = 0xe4, ///< return to caller from the code section of EOF container |
192 | | JUMPF = 0xe5, ///< jump to a code section of EOF container without adding a new return stack frame. |
193 | | DUPN = 0xe6, ///< copies a value at the stack depth given as immediate argument to the top of the stack |
194 | | SWAPN = 0xe7, ///< swaps the highest value with a value at a stack depth given as immediate argument |
195 | | EOFCREATE = 0xec, ///< create a new account with associated container code. |
196 | | RETURNCONTRACT = 0xee, ///< return container to be deployed with axiliary data filled in. |
197 | | CREATE = 0xf0, ///< create a new account with associated code |
198 | | CALL, ///< message-call into an account |
199 | | CALLCODE, ///< message-call with another account's code only |
200 | | RETURN, ///< halt execution returning output data |
201 | | DELEGATECALL, ///< like CALLCODE but keeps caller's value and sender |
202 | | CREATE2 = 0xf5, ///< create new account with associated code at address `sha3(0xff + sender + salt + init code) % 2**160` |
203 | | EXTCALL = 0xf8, ///< EOF message-call into an account |
204 | | EXTDELEGATECALL = 0xf9, ///< EOF delegate call |
205 | | STATICCALL = 0xfa, ///< like CALL but disallow state modifications |
206 | | EXTSTATICCALL = 0xfb, ///< like EXTCALL but disallow state modifications |
207 | | |
208 | | REVERT = 0xfd, ///< halt execution, revert state and return output data |
209 | | INVALID = 0xfe, ///< invalid instruction for expressing runtime errors (e.g., division-by-zero) |
210 | | SELFDESTRUCT = 0xff ///< halt execution and register account for later deletion |
211 | | }; |
212 | | |
213 | | /// @returns true if the instruction is of the CALL opcode family |
214 | | constexpr bool isCallInstruction(Instruction _inst) noexcept |
215 | 0 | { |
216 | 0 | switch (_inst) |
217 | 0 | { |
218 | 0 | case Instruction::CALL: |
219 | 0 | case Instruction::CALLCODE: |
220 | 0 | case Instruction::DELEGATECALL: |
221 | 0 | case Instruction::STATICCALL: |
222 | 0 | case Instruction::EXTCALL: |
223 | 0 | case Instruction::EXTSTATICCALL: |
224 | 0 | case Instruction::EXTDELEGATECALL: |
225 | 0 | return true; |
226 | 0 | default: |
227 | 0 | return false; |
228 | 0 | } |
229 | 0 | } |
230 | | |
231 | | /// @returns true if the instruction is a PUSH |
232 | | inline bool isPushInstruction(Instruction _inst) |
233 | 31.5M | { |
234 | 31.5M | return Instruction::PUSH0 <= _inst && _inst <= Instruction::PUSH32; |
235 | 31.5M | } |
236 | | |
237 | | /// @returns true if the instruction is a LOG |
238 | | inline bool isLogInstruction(Instruction _inst) |
239 | 0 | { |
240 | 0 | return Instruction::LOG0 <= _inst && _inst <= Instruction::LOG4; |
241 | 0 | } |
242 | | |
243 | | /// @returns the number of PUSH Instruction _inst |
244 | | inline unsigned getPushNumber(Instruction _inst) |
245 | 0 | { |
246 | 0 | return static_cast<uint8_t>(_inst) - unsigned(Instruction::PUSH0); |
247 | 0 | } |
248 | | |
249 | | /// @returns the number of LOG Instruction _inst |
250 | | inline unsigned getLogNumber(Instruction _inst) |
251 | 0 | { |
252 | 0 | return static_cast<uint8_t>(_inst) - unsigned(Instruction::LOG0); |
253 | 0 | } |
254 | | |
255 | | /// @returns the PUSH<_number> instruction |
256 | | inline Instruction pushInstruction(unsigned _number) |
257 | 15.4M | { |
258 | 15.4M | solAssert(_number <= 32); |
259 | 15.4M | return Instruction(unsigned(Instruction::PUSH0) + _number); |
260 | 15.4M | } |
261 | | |
262 | | /// @returns the DUP<_number> instruction |
263 | | inline Instruction dupInstruction(unsigned _number) |
264 | 5.14M | { |
265 | 5.14M | solAssert(1 <= _number && _number <= 16); |
266 | 5.14M | return Instruction(unsigned(Instruction::DUP1) + _number - 1); |
267 | 5.14M | } |
268 | | |
269 | | /// @returns the SWAP<_number> instruction |
270 | | inline Instruction swapInstruction(unsigned _number) |
271 | 16.1M | { |
272 | 16.1M | solAssert(1 <= _number && _number <= 16); |
273 | 16.1M | return Instruction(unsigned(Instruction::SWAP1) + _number - 1); |
274 | 16.1M | } |
275 | | |
276 | | /// @returns the LOG<_number> instruction |
277 | | inline Instruction logInstruction(unsigned _number) |
278 | 422 | { |
279 | 422 | solAssert(_number <= 4); |
280 | 422 | return Instruction(unsigned(Instruction::LOG0) + _number); |
281 | 422 | } |
282 | | |
283 | | /// Gas price tiers representing static cost of an instruction. |
284 | | /// Opcodes whose cost is dynamic or depends on EVM version should use the `Special` tier and need |
285 | | /// dedicated logic in GasMeter (especially in estimateMax()). |
286 | | /// The tiers loosely follow opcode groups originally defined in the Yellow Paper. |
287 | | enum class Tier |
288 | | { |
289 | | // NOTE: Tiers should be ordered by cost, since we sometimes perform comparisons between them. |
290 | | Zero = 0, // 0, Zero |
291 | | Base, // 2, Quick |
292 | | RJump, // 2, RJump |
293 | | VeryLow, // 3, Fastest |
294 | | RetF, // 3, |
295 | | RJumpI, // 4, |
296 | | Low, // 5, Fast |
297 | | CallF, // 5, |
298 | | JumpF, // 5, |
299 | | Mid, // 8, Mid |
300 | | High, // 10, Slow |
301 | | BlockHash, // 20 |
302 | | WarmAccess, // 100, Warm Access |
303 | | Special, // multiparam or otherwise special |
304 | | Invalid, // Invalid. |
305 | | }; |
306 | | |
307 | | /// Information structure for a particular instruction. |
308 | | struct InstructionInfo |
309 | | { |
310 | | std::string name; ///< The name of the instruction. |
311 | | int additional; ///< Additional items required in memory for this instructions (only for PUSH). |
312 | | int args; ///< Number of items required on the stack for this instruction (and, for the purposes of ret, the number taken from the stack). |
313 | | int ret; ///< Number of items placed (back) on the stack by this instruction, assuming args items were removed. |
314 | | bool sideEffects; ///< false if the only effect on the execution environment (apart from gas usage) is a change to a topmost segment of the stack |
315 | | Tier gasPriceTier; ///< Tier for gas pricing. |
316 | | }; |
317 | | |
318 | | /// Information on all the instructions. |
319 | | InstructionInfo instructionInfo(Instruction _inst, langutil::EVMVersion _evmVersion); |
320 | | |
321 | | /// check whether instructions exists. |
322 | | bool isValidInstruction(Instruction _inst); |
323 | | |
324 | | /// Convert from string mnemonic to Instruction type. |
325 | | extern const std::map<std::string, Instruction, std::less<>> c_instructions; |
326 | | |
327 | | } |