91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Solidity內聯匯編怎么使用

發布時間:2021-12-07 15:14:07 來源:億速云 閱讀:238 作者:iii 欄目:互聯網科技

本篇內容主要講解“Solidity內聯匯編怎么使用”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Solidity內聯匯編怎么使用”吧!

在用Solidity開發以太坊智能合約時,使用匯編可以直接與EVM交互,降低gas開銷成本,更精細的控制智能合約的行為,因此值得Solidity開發者學習并加以利用。

2、以太坊虛擬機和堆棧結構機器

以太坊虛擬機EVM有自己的指令集,該指令集中目前包含了144個操作碼,詳情參考Geth源代碼

這些指令是Solidity抽象出來的,可以在Solidity內聯使用。例如:

contract Assembler {    
  function do_something_cpu() public {
    assembly {
      // start writing evm assembler language
    }
  }
}

EVM是一個棧虛擬機,棧這種數據結構只允許兩個操作:壓入(PUSH)或彈出(POP)數據。最后壓入的數據位于棧頂,因此將被第一個彈出,這被稱為后進先出(LIFO:Last In, First Out):

Solidity內聯匯編怎么使用

棧虛擬機將所有的操作數保存在棧上,關于棧虛擬機的詳細信息可以參考stack machine 基礎

3、堆棧結構機器的操作碼

為了能夠解決實際問題,棧結構機器需要實現一些額外的指令,例如ADD、SUBSTRACT等等。指令執行時通常會先從堆棧彈出一個或多個值作為參數,再將執行結果壓回堆棧。這通常被稱為逆波蘭表示法(RPN:Reverse Polish Notation):

a + b      // 標準表示法Infix
a b add    // 逆波蘭表示法RPN

4、在Solidity合約中使用內聯匯編

可以在Solidity中使用assembly{}來嵌入匯編代碼段,這被稱為內聯匯編:

assembly {
  // some assembly code here
}

assembly塊內的代碼開發語言被稱為Yul,為了簡化我們稱其為匯編或EVM匯編。

另一個需要注意的問題時,匯編代碼塊之間不能通信,也就是說在一個匯編代碼塊里定義的變量,在另一個匯編代碼塊中不可以訪問。例如:

assembly { 
    let x := 2
}        
assembly {
    let y := x          // Error
}

上面的代碼編譯時會報如下錯誤:

// DeclarationError: identifier not found
// let y := x
// ^

下面的代碼使用內聯匯編代碼計算函數的兩個參數的和并返回結果:

function addition(uint x, uint y) public pure returns (uint) {
  assembly {
    let result := add(x, y)   // x + y
    mstore(0x0, result)       // 在內存中保存結果
    return(0x0, 32)           // 從內存中返回32字節
  }
 }

讓我們重寫上面的代碼,補充一些更詳細的注釋,以便說明每個指令在EVM內部的運行原理。

function addition(uint x, uint y) public pure returns (uint) { 
  assembly {        
    // 創建一個新的變量result
    //     -> 使用add操作碼計算x+y
    //     -> 將計算結果賦值給變量result      
    let result := add(x, y)   // x + y   
    
    // 使用mstore操作碼
    //     -> 將result變量的值存入內存
    //     -> 指定內存地址 0x0      
    mstore(0x0, result)       // 將結果存入內存
    
    // 從內存地址0x返回32字節
    return(0x0, 32)          
  }
}

5、Solidity匯編中的變量定義與賦值

在Yul中,使用let關鍵字定義變量。使用:=操作符給變量賦值:

assembly {
  let x := 2
}

如果沒有使用:=操作符給變量賦值,那么該變量自動初始化為0值:

assembly {
  let x           // 自動初始化為 x = 0
  x := 5          // x 現在的值是5
}

你可以使用復雜的表達式為變量賦值,例如:

assembly {
  let x := 7 
  let y := add(x, 3)
  let z := add(keccak256(0x0, 0x20), div(slength, 32))    
  let n            
}

6、Solidity匯編中let指令的運行機制

在EVM的內部,let指令執行如下任務:

  • 創建一個新的堆棧槽位

  • 為變量保留該槽位

  • 當到達代碼塊結束時自動銷毀該槽位

因此,使用let指令在匯編代碼塊中定義的變量,在該代碼塊外部是無法訪問的。

7、Solidity匯編中的注釋

在Yul匯編中注釋的寫法和Solidity一樣,可以使用單行注釋//或多行注釋/* */。例如:

assembly {     
  // single line comment

  /*
    Multi
    line
    comment
  */
}

8、Solidity匯編中的字面量

在Solidity匯編中字面量的寫法與Solidity一致。不過,字符串字面量最多可以包含32個字符。

assembly {    
  let a := 0x123             // 16進制
  let b := 42                // 10進制
  let c := "hello world"     // 字符串

  let d := "very long string more than 32 bytes" // 超長字符串,錯誤!
}

9、Solidity匯編中的塊和作用范圍

在Solidity匯編中,變量的作用范圍遵循標準規則。一個塊的范圍使用一對大括號標識。

在下面的示例中,y和z僅在定義所在塊范圍內有效。因此y變量的作用范圍是scope 1,z變量的作用范圍是scope 2。

assembly {     
  let x := 3          // x在各處可見
    
  // Scope 1           
  {         
    let y := x     // ok    
  }  // 到此處會銷毀y

  // Scope 2    
  {        
    let z := y     // Error    
  } // 到此處會銷毀z
}

// DeclarationError: identifier not found
// let z := y
// ^

作用范圍的唯一例外是函數和for循環,我們將在下面解釋。

10、在Solidity匯編中使用函數的局部變量

在Solidity匯編中,只需要使用變量名就可以訪問局部變量,無論該變量是定義在匯編塊中,還是Solidity代碼中,不過變量必須是函數的局部變量:

function assembly_local_var_access() public pure {    
  uint b = 5;    
  assembly {                // defined inside  an assembly block
      let x := add(2, 3)  
      let y := 10  
      z := add(x, y)
  }    
  assembly {               // defined outside an assembly block
      let x := add(2, 3)
      let y := mul(x, b)
  }
}

11、在Solidity匯編中使用for循環

先看一下Solidity中循環的使用。下面的Solidity函數代碼中計算變量的倍數n次,其中value和n是函數的參數:

function for_loop_solidity(uint n, uint value) public pure returns(uint) {         
  for ( uint i = 0; i < n; i++ ) {
    value = 2 * value;
  }    
  return value;
}

等效的Solidity匯編代碼如下:

function for_loop_assembly(uint n, uint value) public pure returns (uint) {   
  assembly {         
    for { let i := 0 } lt(i, n) { i := add(i, 1) } { 
      value := mul(2, value) 
    }  
    mstore(0x0, value)
    return(0x0, 32)
  }   
}

類似于其他開發語言中的for循環,在Solidity匯編中,for循環也包含3個元素:

  • 初始化:let i := 0

  • 執行條件:lt(i, n) ,必須是函數風格表達式

  • 迭代后續步驟:add(i, 1)

注意:for循環中變量的作用范圍略有不同。在初始化部分定義的變量在循環的其他部分都有效。

12、在Solidity匯編中使用while循環

在Solidity匯編中實際上是沒有while循環關鍵字的,但是可以使用for循環實現同樣的功能:只要留空for循環的初始化部分和迭代后續步驟即可。

assembly {
  let x := 0
  let i := 0
  for { } lt(i, 0x100) { } {     // 等價于:while(i < 0x100)
    x := add(x, mload(i))
    i := add(i, 0x20)
  }
}

13、在Solidity匯編中使用if語句

Solidity內聯匯編支持使用if語句來設置代碼執行的條件,但是沒有其他語言中的else部分。

assembly {    
  if slt(x, 0) { x := sub(0, x) }  // Ok
  if eq(value, 0) revert(0, 0)     // Error, 需要大括號
}

if語句強制要求代碼塊使用大括號,即使需要保護的代碼只有一行,也需要使用大括號。這和solidity不同。

如果需要在Solidity內聯匯編中檢查多種條件,可以考慮使用switch語句。

14、在Solidity匯編中使用switch語句

EVM匯編中也有switch語句,它將一個表達式的值于多個常量進行對比,并選擇相應的代碼分支來執行。switch語句支持一個默認分支default,當表達式的值不匹配任何其他分支條件時,將執行默認分支的代碼。

assembly {
  let x := 0
  switch calldataload(4)
  case 0 {
    x := calldataload(0x24)
  }
  default {
    x := calldataload(0x44)
  }
  sstore(0, div(x, 2))
}

switch語句有一些限制:

  • 分支列表不需要大括號,但是分支的代碼塊需要大括號- 所有的分支條件值必須:1)具有相同的類型 2)具有不同的值- 如果分支條件已經涵蓋所有可能的值,那么不允許再出現default條件

assembly {            
  let x := 34
           
  switch lt(x, 30)
  case true {
      // do something
  }
  case false {
      // do something els
  }
  default {
      // 不允許
  }             
}

15、在Solidity匯編中使用函數

也可以在Solidity內聯匯編中定義底層函數。調用這些自定義的函數和使用內置的操作碼一樣。

下面的匯編函數用來分配指定長度的內存,并返回內存指針pos:

assembly {    
  function allocate(length) -> pos {
    pos := mload(0x40)
    mstore(0x40, add(pos, length))
  }    
  let free_memory_pointer := allocate(64)
}

匯編函數的運行機制如下:

  • 從堆棧提取參數

  • 將結果壓入堆棧

和Solidity函數不同,不需要指定匯編函數的可見性,例如public或private,因為匯編函數僅在定義所在的匯編代碼塊內有效。

16、Solidity匯編中的操作碼

EVM操作碼可以分為以下幾類:

  • 算數和比較操作

  • 位操作

  • 密碼學操作,目前僅包含keccak256

  • 環境操作,主要指與區塊鏈相關的全局信息,例如blockhashcoinbase收款賬號

  • 存儲、內存和棧操作

  • 交易與合約調用操作

  • 停機操作

  • 日志操作

到此,相信大家對“Solidity內聯匯編怎么使用”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

沐川县| 怀安县| 刚察县| 丰台区| 玛纳斯县| 龙州县| 普陀区| 昭苏县| 普定县| 肇州县| 芒康县| 临城县| 雷州市| 岳普湖县| 无锡市| 昌邑市| 大庆市| 靖江市| 丰顺县| 年辖:市辖区| 神木县| 九龙城区| 赞皇县| 景泰县| 梁河县| 德保县| 申扎县| 厦门市| 石嘴山市| 海丰县| 巴彦县| 改则县| 淮阳县| 镇江市| 镇安县| 太仆寺旗| 米泉市| 汤原县| 比如县| 运城市| 瑞金市|