EVM(以太坊虚拟机)的堆栈指令是智能合约操作的基础,使用这些指令可以对堆栈中的数据进行各种操作。
EVM(以太坊虚拟机)的堆栈指令是智能合约操作的基础,使用这些指令可以对堆栈中的数据进行各种操作。
💡PUSH1, PUSH2, ..., PUSH32: 将 1 至 32 字节的常量值推送到堆栈顶端。 💡💡操作码: 0x60(PUSH1)到 0x7F(PUSH32) 💡💡气体费用: 3 gas
💡POP: 从堆栈中弹出最顶端的一个值。 💡💡操作码: 0x50 💡💡气体费用: 2 gas
💡DUP1, DUP2, ..., DUP16: 复制堆栈顶端第 1 至 16 个值并将其推送到堆栈顶端。 💡💡操作码: 0x80(DUP1)到 0x8F(DUP16) 💡💡气体费用: 3 gas
💡SWAP1, SWAP2, ..., SWAP16: 交换堆栈顶端的值与第 1 至 16 个值。 💡💡操作码: 0x90(SWAP1)到 0x9F(SWAP16) 💡💡气体费用: 3 gas
在 EVM(以太坊虚拟机)中,PUSH 指令用于将常量值推送到堆栈顶端。PUSH 指令有 32 种变体,从 PUSH1 到 PUSH32,分别用于推送 1 到 32 字节的常量值。以下是 PUSH 指令的详细解释:
1.1.操作码
💡名称: PUSH1, PUSH2, ..., PUSH32
💡十六进制表示: 💡💡PUSH1: 0x60 💡💡PUSH2: 0x61 💡💡... 💡💡PUSH32: 0x7F
💡气体费用: 3 gas
1.2.功能
PUSH 指令将指定字节长度的常量值推送到堆栈顶端。例如,PUSH1 将 1 字节的常量值推送到堆栈顶端,而 PUSH32 将 32 字节的常量值推送到堆栈顶端。
1.3.操作步骤
1.4.示例
例 1:
60 0A // PUSH1 0A
执行这段字节码的过程如下:
执行后,堆栈状态如下:
堆栈顶端 -> 0A
例 2:
61 0102 // PUSH2 0102
执行这段字节码的过程如下:
执行后,堆栈状态如下:
堆栈顶端 -> 0102
1.5.使用场景
PUSH 指令在智能合约开发中广泛使用,尤其是在需要将常量值加载到堆栈的场景中。以下是一些常见使用场景:
1.6.复杂示例
假设我们有以下字节码段:
60 0A // PUSH1 0A
60 14 // PUSH1 14
01 // ADD
执行流程如下:
执行完成后,堆栈状态如下:
堆栈顶端 -> 1E
1.7.执行示例
pragma solidity ^0.8.0;
contract Example {
function pushValue() public pure returns (uint256) {
assembly {
let value := 10
mstore(0x80, value)
return(0x80, 32)
}
}
}
上述合约的 pushValue 函数使用内联汇编(assembly)将常量值 10 推送到堆栈,并存储在内存地址 0x80 处,然后返回该值。在 EVM 字节码中,这个过程涉及 PUSH1 指令将 0A 推送到堆栈。
1.8.注意事项
在以太坊虚拟机(EVM)中,POP 指令用于移除堆栈顶端的一个元素。这是一种清理堆栈或丢弃不再需要的值的操作。
2.1.操作码和气体费用
2.2.功能
POP 指令从堆栈顶端移除一个元素,并不将其保存或处理。这对于清理不再需要的临时值或保持堆栈的整洁非常有用。
2.3.操作步骤
2.4.示例
假设当前堆栈状态如下:
堆栈顶端 -> 0x03
0x02
0x01
执行 POP 指令后,堆栈状态将变为:
堆栈顶端 -> 0x02
0x01
2.5.详细操作步骤
初始堆栈状态:
堆栈顶端 -> 0x03
0x02
0x01
执行 POP 指令:
最终堆栈状态:
堆栈顶端 -> 0x02
0x01
2.6.代码示例
以下是一个包含 POP 指令的智能合约示例,使用 Solidity 编写,并使用 EVM 字节码来演示 POP 指令的执行:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract PopExample {
function example() public pure returns (uint256) {
uint256 a = 3;
uint256 b = 2;
uint256 c = 1;
assembly {
pop(a) // This will pop the value of a from the stack
}
return b; // Returning b to verify the result
}
}
对应的 EVM 字节码:
60 03 // PUSH1 03
60 02 // PUSH1 02
60 01 // PUSH1 01
50 // POP
2.7.执行流程
60 03:将 0x03 推送到堆栈。
堆栈顶端 -> 0x03
60 02:将 0x02 推送到堆栈。
堆栈顶端 -> 0x02
0x03
60 01:将 0x01 推送到堆栈。
堆栈顶端 -> 0x01
0x02
0x03
50:弹出堆栈顶端的 0x01,堆栈顶端现在是 0x02。
堆栈顶端 -> 0x02
0x03
2.8.注意事项
通过理解 POP 指令的工作原理和使用场景,开发者可以更有效地管理堆栈,确保智能合约的高效和可靠运行。
在以太坊虚拟机(EVM)中,DUP 指令用于复制堆栈中的某个元素,并将其推送到堆栈顶端。DUP 指令有多个变种,从 DUP1 到 DUP16,它们分别用于复制堆栈顶端至第十六个元素中的某个元素。
3.1.操作码和气体费用
💡DUP1 💡💡操作码: 0x80 💡💡气体费用: 3 gas
💡DUP2 💡💡操作码: 0x81 💡💡气体费用: 3 gas
💡DUP3 💡💡操作码: 0x82 💡💡气体费用: 3 gas
💡DUP4 💡💡操作码: 0x83 💡💡气体费用: 3 gas
💡DUP5 💡💡操作码: 0x84 💡💡气体费用: 3 gas
💡DUP6 💡💡操作码: 0x85 💡💡气体费用: 3 gas
💡DUP7 💡💡操作码: 0x86 💡💡气体费用: 3 gas
💡DUP8 💡💡操作码: 0x87 💡💡气体费用: 3 gas
💡DUP9 💡💡操作码: 0x88 💡💡气体费用: 3 gas
💡DUP10 💡💡操作码: 0x89 💡💡气体费用: 3 gas
💡DUP11 💡💡操作码: 0x8a 💡💡气体费用: 3 gas
💡DUP12 💡💡操作码: 0x8b 💡💡气体费用: 3 gas
💡DUP13 💡💡操作码: 0x8c 💡💡气体费用: 3 gas
💡DUP14 💡💡操作码: 0x8d 💡💡气体费用: 3 gas
💡DUP15 💡💡操作码: 0x8e 💡💡气体费用: 3 gas
💡DUP16 💡💡操作码: 0x8f 💡💡气体费用: 3 gas
3.2.功能
每个 DUP 指令从堆栈中复制特定位置的元素,并将其推送到堆栈顶端。例如,DUP1 复制堆栈顶端的元素,DUP2 复制堆栈第二个位置的元素,依此类推,直到 DUP16。
3.3.操作步骤
3.4.示例
假设当前堆栈状态如下:
堆栈顶端 -> 0x04
0x03
0x02
0x01
执行 DUP2 指令后,堆栈状态将变为:
堆栈顶端 -> 0x03
0x04
0x03
0x02
0x01
3.5.详细操作步骤
初始堆栈状态:
堆栈顶端 -> 0x04
0x03
0x02
0x01
执行 DUP2 指令:
最终堆栈状态:
堆栈顶端 -> 0x03
0x04
0x03
0x02
0x01
3.7.代码示例
以下是一个包含 DUP 指令的智能合约示例,使用 Solidity 编写,并使用 EVM 字节码来演示 DUP 指令的执行:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract DupExample {
function duplicate() public pure returns (uint256, uint256) {
uint256 a = 4;
uint256 b = 3;
uint256 c = 2;
uint256 d = 1;
assembly {
dup2 // This will duplicate the value of b
}
return (a, b); // Returning a and b to verify the result
}
}
对应的 EVM 字节码:
60 04 // PUSH1 04
60 03 // PUSH1 03
60 02 // PUSH1 02
60 01 // PUSH1 01
81 // DUP2
执行流程
60 04:将 0x04 推送到堆栈。
堆栈顶端 -> 0x04
60 03:将 0x03 推送到堆栈。
堆栈顶端 -> 0x03
0x04
60 02:将 0x02 推送到堆栈。
堆栈顶端 -> 0x02
0x03
0x04
60 01:将 0x01 推送到堆栈。
堆栈顶端 -> 0x01
0x02
0x03
0x04
81:将堆栈第二个位置的值 0x03 复制一份,推送到堆栈顶端。
堆栈顶端 -> 0x03
0x01
0x02
0x03
0x04
3.8.注意事项
通过理解 DUP 指令的工作原理和使用场景,开发者可以更高效地管理堆栈中的数据,确保智能合约的高效和可靠运行。
在以太坊虚拟机(EVM)中,SWAP 指令用于交换堆栈顶端的两个元素的位置。
4.1.操作码和气体费用
4.2.功能
SWAP 指令将堆栈顶端的第一个元素与第二个元素进行位置交换。不同的 SWAP 指令(SWAP1 到 SWAP16)用于不同位置的元素交换。
4.3.操作步骤
4.4.示例
假设当前堆栈状态如下:
堆栈顶端 -> 0x03
0x02
0x01
执行 SWAP2 指令后,堆栈状态将变为:
堆栈顶端 -> 0x01
0x03
0x02
4.5.详细操作步骤
初始堆栈状态:
堆栈顶端 -> 0x03
0x02
0x01
执行 SWAP2 指令:交换堆栈顶端的第一个元素 0x02 和第二个元素 0x01 的位置。
堆栈顶端 -> 0x01
0x03
0x02
最终堆栈状态:
堆栈顶端 -> 0x01
0x03
0x02
4.6.代码示例
以下是一个包含 SWAP 指令的智能合约示例,使用 Solidity 编写,并使用 EVM 字节码来演示 SWAP 指令的执行:
SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract SwapExample {
function swap() public pure returns (uint256, uint256, uint256) {
uint256 a = 1;
uint256 b = 2;
uint256 c = 3;
assembly {
swap2 // This will swap the second and third elements on the stack
}
return (a, b, c); // Returning a, b, and c to verify the result
}
}
对应的 EVM 字节码:
60 01 // PUSH1 01
60 02 // PUSH1 02
60 03 // PUSH1 03
92 // SWAP2
执行流程
堆栈顶端 -> 0x01
堆栈顶端 -> 0x02
0x01
堆栈顶端 -> 0x03
0x02
0x01
堆栈顶端 -> 0x01
0x03
0x02
4.7.注意事项
通过理解 SWAP 指令的工作原理和使用场景,开发者可以更灵活地管理堆栈中的数据,确保智能合约的高效和可靠运行。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!