以太坊虛擬機介紹3-算術運算指令

以太坊虛擬機算術運算指令

EVM總共定義了11條算術運算指令,見下表:

算術運算指令 操作碼 說明
ADD 0x01 加法運算
MUL 0x02 乘法運算
SUB 0x03 減法運算
DIV 0x04 無符號整除運算
SDIV 0x05 有符號整除運算
MOD 0x06 無符號取模運算
SMOD 0x07 有符號取模運算
ADDMOD 0x08 後面解釋
MULMOD 0x09 後面解釋
EXP 0x0A 指數運算
SIGNEXTEND 0x0B 符號位擴展

這些指令從棧頂彈出兩到三個元素,進行相應計算,然後把結果推入棧頂。參與計算的元素和結果均被解釋爲按二的補碼編碼的整數。如果計算結果(假設爲x)溢出(超出2^256),則最終的結果x’取值x % 2^256(%表示取模運算,^表示指數運算)。

下面是算術運算指令的操作碼分佈圖:
arith opcodes

ADD、MUL、SUB、DIV、SDIV、MOD、SMOD、EXP

這8條指令操作方式比較類似,從棧頂彈出兩個元素,進行計算,然後把計算結果推入棧頂。由於採用二的補碼錶示整數時,加法、減法和乘法運算不用考慮符號位,所以加法、減法和乘法運算都只有一條指令。整除和取模運算需要考慮符號位,所以各有兩條指令。指數運算只操作無符號整數。以ADD指令爲例,下面是它的操作示意圖:
ADD

ADDMOD和MULMOD

MULMOD指令依次從棧頂彈出x、y、z三個數,先計算x和y的乘積(不受溢出限制),再計算乘積和z的模,最後把結果推入棧頂。假定乘積不會溢出,那麼MULMOD(x, y, z)等價於x * y % z,下面是MULMOD指令的操作示意圖:
MULMOD

ADDMOD指令和MULMOD指令類似,只不過把乘法換成了加法。下面是ADDMOD指令的操作示意圖:
ADDMOD

SIGNEXTEND

SIGNEXTEND指令從棧頂依次彈出k和x,並把x解釋爲k+1(0 <= k <= 31)字節有符號整數,然後把x符號擴展至32字節。比如x是二進制10000000,k是0,則符號擴展之後,結果爲二進制1111…10000000(共249個1)。下面是SIGNEXTEND指令的操作示意圖:
SIGNEXTEND

實例分析

ADD、MUL、SUB、DIV、SDIV、MOD、SMOD、EXP指令與Solidity語言裏的+*-/%** 運算符直接對應。ADDMOD指令對應addmod()函數,MULMOD指令對應mulmod()函數。暫時還沒有搞清楚SIGNEXTEND指令的用法,等以後再補充。下面的Solidity代碼演示了EVM算術運算指令的具體應用:

// arith_demo.sol
pragma solidity ^0.4.24;

contract C {

    function test() public view {
        int s1; int s2; int s3;
        uint u1; uint u2; uint u3;
        uint k;

        u3 = u1 + u2; // ADD
        u3 = u1 * u2; // MUL
        u3 = u1 - u2; // SUB
        u3 = u1 / u2; // DIV
        s3 = s1 / s2; // SDIV
        u3 = u1 % u2; // MOD
        s3 = s1 % s2; // SMOD
        u3 = u1 ** u2; // EXP
        u3 = addmod(u1, u2, k); // ADDMOD
        u3 = mulmod(u1, u2, k); // MULMOD
    }

}

讀者可以運行solc --asm --opcodes arith_demo.sol命令觀察編譯器生成的字節碼。

總結

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

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