EVM字节码学习

EVM指令集

参考:https://ethbook.abyteahead.com/ch7/instructions.html

https://gitee.com/silent_light/mythril/blob/develop/mythril/laser/ethereum/instruction_data.py

https://ethervm.io/

谨记evm虚拟机的word(字)是256位32字节

EVM数据管理

参考:https://learnblockchain.cn/2019/10/05/evm-data/

img

可以看到code和storage里存储的数据是非易失的(non-volatile),而stack,args,memory里存储的数据是易失的(volatile),其中code的数据是智能合约的二进制源码,是非易失的很好理解,部署合约的时候data字段也就是合约内容会存储在EVM的code中。
  如果要操作这些存储结构里的数据,就需要用到EVM指令,由于EVM的操作码被限制在一个字节以内,所以EVM最多容纳256条指令,目前EVM已经定义了约142条指令,还有100多条用于以后的扩展。这142条指令包括了算法运算,密码学计算,栈操作,memory,storage操作等。

接下来看一下各个存储位置的含义

Stack(栈)

stack可以免费使用,没有gas消耗,用来保存函数的局部变量,数量被限制在了16个,当在合约里中声明的局部变量超过16个时,再编译合约就会遇到Stack too deep, try removing local variables错误。

介绍几个EVM操作栈的指令,在后面分析合约的时候会用到:

  • Pop指令(操作码0x50):用来从栈顶弹出一个元素;
  • PushX指令:用来把紧跟在后面的1-32字节元素推入栈顶
    Push指令一共32条,从Push1(0x60)到Push32(0x7f),因为栈中每个元素是一个字为256bit,一个字节8bit,所以Push指令最多可以把其后32字节的元素放入栈中而不溢出。
  • DupX指令:用来复制从栈顶开始的第1-16个元素,复制后把元素在推入栈顶
    Dup指令一共16条,从Dup1(0x80)到Dup16(0x8f)。
  • SwapX指令:把栈顶元素和从栈顶开始数的第1-16个元素进行交换,Swap指令一共16条,从Swap1(0x01)一直到Swap16(0x9f)。

Args(参数)

args也叫calldata,是一段只读的可寻址的保存函数调用参数的空间,与栈不同的地方的是,如果要使用calldata里面的数据,必须手动指定偏移量和读取的字节数。

EVM提供的用于操作calldata的指令有三个:

  • calldatasize:返回calldata的大小。
  • calldataload:从calldata中加载32bytes到stack中。
  • calldatacopy:拷贝一些字节到内存中

Memory(内存)

Memory是一个易失性的可以读写修改的空间,主要是在运行期间存储数据,将参数传递给内部函数。内存可以在字节级别寻址,一次可以读取32字节。

EVM提供的用于操作memory的指令有三个:

  • mload 加载一个字从内存到stack;
  • mstore存储一个值到指定的内存地址,格式mstore(p,v),存储v到地址p;
  • mstore8存储一个byte到指定内存地址 ;

当我们操作内存的时候,总是需要加载0x40,因为这个地址保存了空闲内存的指针,避免了覆盖已有的数据。

Storage(存储)

Storage是一个可以读写修改的持久存储的空间,也是每个合约持久化存储数据的地方。Storage是一个巨大的map,一共2^256个插槽,一个插糟有32byte。

EVM提供的用于操作storage的指令有两个:

  • sload用于加载一个字从storage到stack中;
  • sstore用于存储一个字到storage中;

solidity将定义的状态变量,映射到插糟内,对于静态大小的变量从0开始连续布局,对于动态数组和map则采用了其他方法

posted @ 2021-12-23 20:21  不加糖不加奶  阅读(646)  评论(0)    收藏  举报