Solidity

我們使用 CALL 操作碼時如何確定返回地址?

  • August 7, 2020

我試圖理解乙太坊虛擬機中定義的每個操作碼。至於操作碼“CALL”,我發現它需要堆棧中的 7 個參數:gas、addr、value、argument addr、argument offset、return addr 和 return offset。我的問題是,evm 如何確定 CALL 操作碼的返回地址和偏移量。當我在 Remix 上嘗試自己的合約時,我發現返回地址始終與 CALL 操作碼之前的參數地址相同。總是這樣嗎?或者這只是某種巧合?

// this is my contract code:
contract Demo1{
   uint public goal = 2000;
   function getGoal() public returns(uint){
       return goal;
   }
}
contract Demo2{
   function test2(Demo1 demo1, uint b) public returns (uint){
       uint goal_ = demo1.getGoal();
       if(b < goal_){
           b += goal_;
       }
       return b;
   }
}

當我使用 Reimx 調試函式 test2 時,我在 CALL 操作碼之前停止,堆棧如下所示:

0: 0x00000000000000000000000000000000000000000000000000000000002d6963
1: 0x0000000000000000000000000de37dce8154ce54d895bd16942c86d568ddb5fc
2: 0x0000000000000000000000000000000000000000000000000000000000000000
3: 0x0000000000000000000000000000000000000000000000000000000000000080
4: 0x0000000000000000000000000000000000000000000000000000000000000004
5: 0x0000000000000000000000000000000000000000000000000000000000000080
6: 0x0000000000000000000000000000000000000000000000000000000000000020
...

實際上,返回地址是指向應該儲存返回值的記憶體的指針,而返回偏移量是可以寫入的最大記憶體大小。

在範例中,函式getGoal返回一個uint,因此合約必須為返回值(0x20)保留 32 個字節,並且看起來 0x80 是未使用記憶體的第一個地址。編譯器似乎生成了這樣的程式碼,使得在 CALL 之後不會使用輸入,並且可以重用相同的地址來儲存返回的值。

當返回的數據是可變大小時,您可以為返回地址和返回大小都傳遞 0。然後您可以使用 RETURNDATASIZE 和 RETURNDATACOPY 訪問返回的數據。

引用自:https://ethereum.stackexchange.com/questions/86521