以太坊虛擬機介紹2-棧操作指令

以太坊虛擬機棧操作指令

上一篇文章對EVM和它的指令集進行了簡單介紹,本文將介紹POP指令、PUSHx系列指令、DUPx系列指令、SWAPx系列指令。這些指令只對EVM棧進行單純的操作,它們的操作碼分佈如下圖所示:

evm stack ops

POP指令

POP指令(操作碼0x50)從棧頂彈出一個元素。下面是POP指令的操作示意圖(白色表示元素即將發生變動):

pop

PUSHx指令

PUSH系列指令把緊跟在指令後面的N(1 ~ 32)字節元素推入棧頂。PUSH系列指令一共有32條,從PUSH1(操作碼0x60)一直到PUSH32(操作碼0x7A)。EVM是大端機器,以PUSH2指令爲例,下面是該指令的操作示意圖(不完整的灰色紙帶表示字節碼):

push2

DUPx指令

DUP系列指令複製從棧頂開始數的第N(1 ~ 16)個元素,並把複製後的元素推入棧頂。DUP系列指令一共有16條,從DUP1(操作碼0x80)一直到DUP16(操作碼0x8A)。比如PUSH1指令複製棧頂元素,如下圖所示:

dup1

下面是DUP2指令的操作示意圖:

dup2

SWAPx指令

SWAP系列指令把棧頂元素和從棧頂開始數的第N(1 ~ 16)+ 1 個元素進行交換。SWAP系列指令一共有16條,從SWAP1(操作碼0x90)一直到SWAP16(操作碼0x9A)。比如SWAP1指令交換位於棧頂的兩個元素,如下圖所示:

swap1

下面是SWAP2指令的操作示意圖:

swap2

實例分析

我們用Solidity語言編寫一個簡單的智能合約,看看以上這些指令是如何應用的:

// stack_demo.sol
pragma solidity ^0.4.24;

contract C {
    function foo() public view {
        uint32 x = 3;
        uint32 y = 4;
        uint32 z = x + y;
    }
}

solc --asm stack_demo.sol命令編譯上面的智能合約,觀察編譯器生產的彙編代碼(下面僅給出部分輸出):

ASM

    tag_5:
        /* "stack_demo.sol":80:88  uint32 x */
      0x0
        /* "stack_demo.sol":102:110  uint32 y */
      dup1
        /* "stack_demo.sol":124:132  uint32 z */
      0x0
        /* "stack_demo.sol":91:92  3 */
      0x3
        /* "stack_demo.sol":80:92  uint32 x = 3 */
      swap3
      pop
        /* "stack_demo.sol":113:114  4 */
      0x4
        /* "stack_demo.sol":102:114  uint32 y = 4 */
      swap2
      pop
        /* "stack_demo.sol":139:140  y */
      dup2
        /* "stack_demo.sol":135:136  x */
      dup4
        /* "stack_demo.sol":135:140  x + y */
      add
        /* "stack_demo.sol":124:140  uint32 z = x + y */
      swap1
      pop
        /* "stack_demo.sol":43:147  function foo() public view {... */
      pop
      pop
      pop
      jump  // out

我們暫時忽略ADD指令和JUMP指令,下面是指令操作示意圖(指令從左到右執行,指令上面是指令操作之後的棧狀態):

stack ops

總結

本文介紹了EVM棧操作指令,下一篇文章將介紹EVM算術運算指令。如果大家對編程語言虛擬機有更多的興趣,請關注我寫的《自己動手寫Java虛擬機》,以及馬上將要出版的《自己動手實現Lua:虛擬機、編譯器、標準庫》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章