通过调试理解EVM 第 4 篇,了解 结束/中止执行的5种指令
在EVM中,总共有5种方式来结束智能合约的执行。我们将在这篇文章中详细研究它们。让我们现在就开始吧!
这是通过逆向和调试理解EVM系列的第4篇,在这里你可以找到之前和接下来的部分:
我们将使用EVM中最简单的操作码来开始。
这是唯一一个消耗0Gas的操作码,顾名思义,它结束智能合约的执行,不返回任何数据。
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
contract Test {
function test() external {
}
}
你可以拆解这个非常简单的智能合约来弄清楚发生了什么。(函数的执行从第45指令开始)
045 JUMPDEST |function signature discarded|
046 PUSH1 33 |0x33|
048 PUSH1 35 |0x35|0x33|
050 JUMP |0x33|053 JUMPDEST |0x33|
054 JUMP ||051 JUMPDEST ||
052 STOP ||
在结束时经过2次跳转。内存中没有任何东西。没有数据被存储,堆栈只包含函数签名,因此没有数据被返回。
就这样简单。
RETURN像STOP一样结束智能合约的执行,但与STOP不同,它也可能返回一些数据。我们将编译这个solidity代码:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
contract Test {
function test() external returns(uint) {
return(8)
}
}
并对该函数进行反汇编:
045 JUMPDEST ||
046 PUSH1 08 |0x08| the return value of test()
048 PUSH1 40 |0x40|0x08|
050 MLOAD |0x80|0x08| mload(0x40) mloads the free memory pointer
051 SWAP1 |0x08|0x80|
052 DUP2 |0x80|0x08|0x80|
053 MSTORE |0x80| mstore(0x80,0x08) store the return value in memory[0x80]
054 PUSH1 20 |0x20|0x80|
056 ADD |0xa0|
057 PUSH1 40 |0x40|0xa0|
059 MLOAD |0x80|0xa0|
060 DUP1 |0x80|0x80|0xa0|
061 SWAP2 |0xa0|0x80|0x80|
062 SUB |0x20|0x80|
063 SWAP1 |0x80|0x20|
064 RETURN ||
在指令45和50之间,EVM mload(0x40),它返回80。
备注:45 、50 表示第几个字节数上的指令,下面都使用这种简写方式。
在指令51和53之间, EVM mstore(0x80,0x08),80是空闲内存地址,8是test函数的返回值。
在指令54到56之间,EVM在之前的结果(80)上加上20,等于a0(20=十进制的32,因为这是一个内存插槽的大小,这里只有一个返回值)。
在指令57和62之间,它在40处重新加载内存(mload(0x40)),并将结果与0xa0(第56行的结果)相乘,即0x20。
这里没有非常有趣的东西。在指令64时,内存0x80槽中有0x08,栈中有80和20。这3个值是什么意思?
根据文档的内容。当被调用时:
Stack(0) = 80应包含返回数据在内存中的偏移量
Stack(1) = 20 应该包含返回数据的偏移后的大小。
这正是这个智能合约的情况,0x80和0xa0之间的内存(=80+20 的十六进制)包含函数测试的返回值(8)。
所以智能合约返回内存[Stack(0):Stack(0)+Stack(1)]。
现在,我们来修改智能合约。
pragma solidity ^0.8.0;
contract Test {
function test() external returns(uint) {
revert("eight");
}
}
你发现区别了吗?我没有使用return(),而是使用了revert(),参数是一个字符串(我不能在 "revert"中使用数字,solidity编译器不允许我编译)。
如果你调用test(),你应该看到一个错误,但调试仍然是可能的!
下面是test函数的反汇编:
069 JUMPDEST ||
070 PUSH1 40 |0x40|
072 MLOAD |0x80|
073 PUSH3 461bcd |0x461bcd|0x80|
077 PUSH1 e5 |0xe5|0x461bcd|0x80|
079 SHL |0x08c379a000...000|0x80| binary shift 197 times (e5 in hex), YES a binary shift can modify hex numbers...
080 DUP2 |0x80|0x08c379a000...000|0x80|
081 MSTORE |0x80|
082 PUSH1 20 |0x20|0x80|
084 PUSH1 04 |0x04|0x20|0x80|
086 DUP3 |0x80|0x04|0x20|0x80|
087 ADD |0x84|0x20|0x80|
088 MSTORE |0x80|
089 PUSH1 05 |0x05|0x80|
091 PUSH1 24 |0x24|0x05|0x80|
093 DUP3 |0x80|0x24|0x05|0x80|
094 A...
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!