/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 | | |
29 | | namespace solidity::evmasm |
30 | | { |
31 | | |
32 | | /// Virtual machine bytecode instruction. |
33 | | enum class Instruction: uint8_t |
34 | | { |
35 | | STOP = 0x00, ///< halts execution |
36 | | ADD, ///< addition operation |
37 | | MUL, ///< multiplication operation |
38 | | SUB, ///< subtraction operation |
39 | | DIV, ///< integer division operation |
40 | | SDIV, ///< signed integer division operation |
41 | | MOD, ///< modulo remainder operation |
42 | | SMOD, ///< signed modulo remainder operation |
43 | | ADDMOD, ///< unsigned modular addition |
44 | | MULMOD, ///< unsigned modular multiplication |
45 | | EXP, ///< exponential operation |
46 | | SIGNEXTEND, ///< extend length of signed integer |
47 | | |
48 | | LT = 0x10, ///< less-than comparison |
49 | | GT, ///< greater-than comparison |
50 | | SLT, ///< signed less-than comparison |
51 | | SGT, ///< signed greater-than comparison |
52 | | EQ, ///< equality comparison |
53 | | ISZERO, ///< simple not operator |
54 | | AND, ///< bitwise AND operation |
55 | | OR, ///< bitwise OR operation |
56 | | XOR, ///< bitwise XOR operation |
57 | | NOT, ///< bitwise NOT operation |
58 | | BYTE, ///< retrieve single byte from word |
59 | | SHL, ///< bitwise SHL operation |
60 | | SHR, ///< bitwise SHR operation |
61 | | SAR, ///< bitwise SAR operation |
62 | | |
63 | | KECCAK256 = 0x20, ///< compute KECCAK-256 hash |
64 | | |
65 | | ADDRESS = 0x30, ///< get address of currently executing account |
66 | | BALANCE, ///< get balance of the given account |
67 | | ORIGIN, ///< get execution origination address |
68 | | CALLER, ///< get caller address |
69 | | CALLVALUE, ///< get deposited value by the instruction/transaction responsible for this execution |
70 | | CALLDATALOAD, ///< get input data of current environment |
71 | | CALLDATASIZE, ///< get size of input data in current environment |
72 | | CALLDATACOPY, ///< copy input data in current environment to memory |
73 | | CODESIZE, ///< get size of code running in current environment |
74 | | CODECOPY, ///< copy code running in current environment to memory |
75 | | GASPRICE, ///< get price of gas in current environment |
76 | | EXTCODESIZE, ///< get external code size (from another contract) |
77 | | EXTCODECOPY, ///< copy external code (from another contract) |
78 | | RETURNDATASIZE = 0x3d, ///< get size of return data buffer |
79 | | RETURNDATACOPY = 0x3e, ///< copy return data in current environment to memory |
80 | | EXTCODEHASH = 0x3f, ///< get external code hash (from another contract) |
81 | | |
82 | | BLOCKHASH = 0x40, ///< get hash of most recent complete block |
83 | | COINBASE, ///< get the block's coinbase address |
84 | | TIMESTAMP, ///< get the block's timestamp |
85 | | NUMBER, ///< get the block's number |
86 | | DIFFICULTY, ///< get the block's difficulty |
87 | | GASLIMIT, ///< get the block's gas limit |
88 | | CHAINID, ///< get the config's chainid param |
89 | | SELFBALANCE, ///< get balance of the current account |
90 | | BASEFEE, ///< get the block's basefee |
91 | | |
92 | | POP = 0x50, ///< remove item from stack |
93 | | MLOAD, ///< load word from memory |
94 | | MSTORE, ///< save word to memory |
95 | | MSTORE8, ///< save byte to memory |
96 | | SLOAD, ///< load word from storage |
97 | | SSTORE, ///< save word to storage |
98 | | JUMP, ///< alter the program counter |
99 | | JUMPI, ///< conditionally alter the program counter |
100 | | PC, ///< get the program counter |
101 | | MSIZE, ///< get the size of active memory |
102 | | GAS, ///< get the amount of available gas |
103 | | JUMPDEST, ///< set a potential jump destination |
104 | | |
105 | | PUSH1 = 0x60, ///< place 1 byte item on stack |
106 | | PUSH2, ///< place 2 byte item on stack |
107 | | PUSH3, ///< place 3 byte item on stack |
108 | | PUSH4, ///< place 4 byte item on stack |
109 | | PUSH5, ///< place 5 byte item on stack |
110 | | PUSH6, ///< place 6 byte item on stack |
111 | | PUSH7, ///< place 7 byte item on stack |
112 | | PUSH8, ///< place 8 byte item on stack |
113 | | PUSH9, ///< place 9 byte item on stack |
114 | | PUSH10, ///< place 10 byte item on stack |
115 | | PUSH11, ///< place 11 byte item on stack |
116 | | PUSH12, ///< place 12 byte item on stack |
117 | | PUSH13, ///< place 13 byte item on stack |
118 | | PUSH14, ///< place 14 byte item on stack |
119 | | PUSH15, ///< place 15 byte item on stack |
120 | | PUSH16, ///< place 16 byte item on stack |
121 | | PUSH17, ///< place 17 byte item on stack |
122 | | PUSH18, ///< place 18 byte item on stack |
123 | | PUSH19, ///< place 19 byte item on stack |
124 | | PUSH20, ///< place 20 byte item on stack |
125 | | PUSH21, ///< place 21 byte item on stack |
126 | | PUSH22, ///< place 22 byte item on stack |
127 | | PUSH23, ///< place 23 byte item on stack |
128 | | PUSH24, ///< place 24 byte item on stack |
129 | | PUSH25, ///< place 25 byte item on stack |
130 | | PUSH26, ///< place 26 byte item on stack |
131 | | PUSH27, ///< place 27 byte item on stack |
132 | | PUSH28, ///< place 28 byte item on stack |
133 | | PUSH29, ///< place 29 byte item on stack |
134 | | PUSH30, ///< place 30 byte item on stack |
135 | | PUSH31, ///< place 31 byte item on stack |
136 | | PUSH32, ///< place 32 byte item on stack |
137 | | |
138 | | DUP1 = 0x80, ///< copies the highest item in the stack to the top of the stack |
139 | | DUP2, ///< copies the second highest item in the stack to the top of the stack |
140 | | DUP3, ///< copies the third highest item in the stack to the top of the stack |
141 | | DUP4, ///< copies the 4th highest item in the stack to the top of the stack |
142 | | DUP5, ///< copies the 5th highest item in the stack to the top of the stack |
143 | | DUP6, ///< copies the 6th highest item in the stack to the top of the stack |
144 | | DUP7, ///< copies the 7th highest item in the stack to the top of the stack |
145 | | DUP8, ///< copies the 8th highest item in the stack to the top of the stack |
146 | | DUP9, ///< copies the 9th highest item in the stack to the top of the stack |
147 | | DUP10, ///< copies the 10th highest item in the stack to the top of the stack |
148 | | DUP11, ///< copies the 11th highest item in the stack to the top of the stack |
149 | | DUP12, ///< copies the 12th highest item in the stack to the top of the stack |
150 | | DUP13, ///< copies the 13th highest item in the stack to the top of the stack |
151 | | DUP14, ///< copies the 14th highest item in the stack to the top of the stack |
152 | | DUP15, ///< copies the 15th highest item in the stack to the top of the stack |
153 | | DUP16, ///< copies the 16th highest item in the stack to the top of the stack |
154 | | |
155 | | SWAP1 = 0x90, ///< swaps the highest and second highest value on the stack |
156 | | SWAP2, ///< swaps the highest and third highest value on the stack |
157 | | SWAP3, ///< swaps the highest and 4th highest value on the stack |
158 | | SWAP4, ///< swaps the highest and 5th highest value on the stack |
159 | | SWAP5, ///< swaps the highest and 6th highest value on the stack |
160 | | SWAP6, ///< swaps the highest and 7th highest value on the stack |
161 | | SWAP7, ///< swaps the highest and 8th highest value on the stack |
162 | | SWAP8, ///< swaps the highest and 9th highest value on the stack |
163 | | SWAP9, ///< swaps the highest and 10th highest value on the stack |
164 | | SWAP10, ///< swaps the highest and 11th highest value on the stack |
165 | | SWAP11, ///< swaps the highest and 12th highest value on the stack |
166 | | SWAP12, ///< swaps the highest and 13th highest value on the stack |
167 | | SWAP13, ///< swaps the highest and 14th highest value on the stack |
168 | | SWAP14, ///< swaps the highest and 15th highest value on the stack |
169 | | SWAP15, ///< swaps the highest and 16th highest value on the stack |
170 | | SWAP16, ///< swaps the highest and 17th highest value on the stack |
171 | | |
172 | | LOG0 = 0xa0, ///< Makes a log entry; no topics. |
173 | | LOG1, ///< Makes a log entry; 1 topic. |
174 | | LOG2, ///< Makes a log entry; 2 topics. |
175 | | LOG3, ///< Makes a log entry; 3 topics. |
176 | | LOG4, ///< Makes a log entry; 4 topics. |
177 | | |
178 | | CREATE = 0xf0, ///< create a new account with associated code |
179 | | CALL, ///< message-call into an account |
180 | | CALLCODE, ///< message-call with another account's code only |
181 | | RETURN, ///< halt execution returning output data |
182 | | DELEGATECALL, ///< like CALLCODE but keeps caller's value and sender |
183 | | CREATE2 = 0xf5, ///< create new account with associated code at address `sha3(0xff + sender + salt + init code) % 2**160` |
184 | | STATICCALL = 0xfa, ///< like CALL but disallow state modifications |
185 | | |
186 | | REVERT = 0xfd, ///< halt execution, revert state and return output data |
187 | | INVALID = 0xfe, ///< invalid instruction for expressing runtime errors (e.g., division-by-zero) |
188 | | SELFDESTRUCT = 0xff ///< halt execution and register account for later deletion |
189 | | }; |
190 | | |
191 | | /// @returns true if the instruction is a PUSH |
192 | | inline bool isPushInstruction(Instruction _inst) |
193 | 4.00M | { |
194 | 4.00M | return Instruction::PUSH1 <= _inst && _inst <= Instruction::PUSH32; |
195 | 4.00M | } |
196 | | |
197 | | /// @returns true if the instruction is a DUP |
198 | | inline bool isDupInstruction(Instruction _inst) |
199 | 39.6M | { |
200 | 39.6M | return Instruction::DUP1 <= _inst && _inst <= Instruction::DUP16; |
201 | 39.6M | } |
202 | | |
203 | | /// @returns true if the instruction is a SWAP |
204 | | inline bool isSwapInstruction(Instruction _inst) |
205 | 33.9M | { |
206 | 33.9M | return Instruction::SWAP1 <= _inst && _inst <= Instruction::SWAP16; |
207 | 33.9M | } |
208 | | |
209 | | /// @returns true if the instruction is a LOG |
210 | | inline bool isLogInstruction(Instruction _inst) |
211 | 0 | { |
212 | 0 | return Instruction::LOG0 <= _inst && _inst <= Instruction::LOG4; |
213 | 0 | } |
214 | | |
215 | | /// @returns the number of PUSH Instruction _inst |
216 | | inline unsigned getPushNumber(Instruction _inst) |
217 | 0 | { |
218 | 0 | return static_cast<uint8_t>(_inst) - unsigned(Instruction::PUSH1) + 1; |
219 | 0 | } |
220 | | |
221 | | /// @returns the number of DUP Instruction _inst |
222 | | inline unsigned getDupNumber(Instruction _inst) |
223 | 324k | { |
224 | 324k | return static_cast<uint8_t>(_inst) - unsigned(Instruction::DUP1) + 1; |
225 | 324k | } |
226 | | |
227 | | /// @returns the number of SWAP Instruction _inst |
228 | | inline unsigned getSwapNumber(Instruction _inst) |
229 | 324k | { |
230 | 324k | return static_cast<uint8_t>(_inst) - unsigned(Instruction::SWAP1) + 1; |
231 | 324k | } |
232 | | |
233 | | /// @returns the number of LOG Instruction _inst |
234 | | inline unsigned getLogNumber(Instruction _inst) |
235 | 0 | { |
236 | 0 | return static_cast<uint8_t>(_inst) - unsigned(Instruction::LOG0); |
237 | 0 | } |
238 | | |
239 | | /// @returns the PUSH<_number> instruction |
240 | | inline Instruction pushInstruction(unsigned _number) |
241 | 220k | { |
242 | 220k | assertThrow(1 <= _number && _number <= 32, InvalidOpcode, std::string("Invalid PUSH instruction requested (") + std::to_string(_number) + ")."); |
243 | 220k | return Instruction(unsigned(Instruction::PUSH1) + _number - 1); |
244 | 220k | } |
245 | | |
246 | | /// @returns the DUP<_number> instruction |
247 | | inline Instruction dupInstruction(unsigned _number) |
248 | 1.65M | { |
249 | 1.65M | assertThrow(1 <= _number && _number <= 16, InvalidOpcode, std::string("Invalid DUP instruction requested (") + std::to_string(_number) + ")."); |
250 | 1.65M | return Instruction(unsigned(Instruction::DUP1) + _number - 1); |
251 | 1.65M | } |
252 | | |
253 | | /// @returns the SWAP<_number> instruction |
254 | | inline Instruction swapInstruction(unsigned _number) |
255 | 2.36M | { |
256 | 2.36M | assertThrow(1 <= _number && _number <= 16, InvalidOpcode, std::string("Invalid SWAP instruction requested (") + std::to_string(_number) + ")."); |
257 | 2.36M | return Instruction(unsigned(Instruction::SWAP1) + _number - 1); |
258 | 2.36M | } |
259 | | |
260 | | /// @returns the LOG<_number> instruction |
261 | | inline Instruction logInstruction(unsigned _number) |
262 | 0 | { |
263 | 0 | assertThrow(_number <= 4, InvalidOpcode, std::string("Invalid LOG instruction requested (") + std::to_string(_number) + ")."); |
264 | 0 | return Instruction(unsigned(Instruction::LOG0) + _number); |
265 | 0 | } |
266 | | |
267 | | enum class Tier |
268 | | { |
269 | | Zero = 0, // 0, Zero |
270 | | Base, // 2, Quick |
271 | | VeryLow, // 3, Fastest |
272 | | Low, // 5, Fast |
273 | | Mid, // 8, Mid |
274 | | High, // 10, Slow |
275 | | Ext, // 20, Ext |
276 | | ExtCode, // 700, Extcode |
277 | | Balance, // 400, Balance |
278 | | Special, // multiparam or otherwise special |
279 | | Invalid // Invalid. |
280 | | }; |
281 | | |
282 | | /// Information structure for a particular instruction. |
283 | | struct InstructionInfo |
284 | | { |
285 | | std::string name; ///< The name of the instruction. |
286 | | int additional; ///< Additional items required in memory for this instructions (only for PUSH). |
287 | | int args; ///< Number of items required on the stack for this instruction (and, for the purposes of ret, the number taken from the stack). |
288 | | int ret; ///< Number of items placed (back) on the stack by this instruction, assuming args items were removed. |
289 | | 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 |
290 | | Tier gasPriceTier; ///< Tier for gas pricing. |
291 | | }; |
292 | | |
293 | | /// Information on all the instructions. |
294 | | InstructionInfo instructionInfo(Instruction _inst); |
295 | | |
296 | | /// check whether instructions exists. |
297 | | bool isValidInstruction(Instruction _inst); |
298 | | |
299 | | /// Convert from string mnemonic to Instruction type. |
300 | | extern const std::map<std::string, Instruction> c_instructions; |
301 | | |
302 | | } |