文章旨在记录过去所学知识,若文章内容存在不当,欢迎指出。EVM详解之memory
文章旨在记录过去所学知识,若文章内容存在不当,欢迎指出。若对文章内容感兴趣,也欢迎评论区留言讨论!文章部分图片来自他人博客!
EVM中的主要数据存储结构包括Storage、Memeory、Stack、Calldata。本章主要介绍Memory数据结构。Memory可以看作是一个非常长的数组,其最低长度为0,最长长度为2**64字节,而每个存储块都是32字节。其结构如下图所示: <!--StartFragment-->
<!--EndFragment-->
通常Memory的前四个存储块(4×32字节)用作保留空间,用于不同的用途,而不用作一般局部变量的存储。从0x80开始以后的空间采用做一般局部变量的存储。
<!--EndFragment-->
EVM内存有4个主要特点:
EVM的内存也是易失的。存储在内存中的值在外部调用之间不会持续存在。当一个合约调用另一个合约时,会获得一个新的内存实例。内存并没有被擦除和清空。EVM内存的每个新实例都是特定于一个执行环境,即当前的合约执行。因此,我们应该记住,EVM内存是特定于1)消息调用和2)被调用合约的执行环境的。
memory是用来存储局部变量的。主要存储的有两种数据: 1.复杂类型的函数参数 2.复杂类型的局部变量。solidity中复杂类型主要是指:指的是诸如结构体、数组、bytes和strings等变量。 一旦函数调用结束,这些用关键字memory定义的变量将消失。这就是我们之前所说的 不持久化 的意思。原因是,memory告诉Solidity在运行时为该变量创建一块空间,保证其大小和结构,以便在函数执行过程中将来用于该函数。
要想清楚memory的工作方式,首先要清楚memory中的空闲内存指针。空闲内存指针存放在memory中的第三个存储块(0x40),它指向下一个存放在memory中的变量应该存放的位置(存储块的序号offset),你可以发现对于任何一段合约字节码,都是以0x6080604052开始,它代表的含义是: <!--StartFragment-->
<!--EndFragment-->
现在我们一步步对其进行解释,第一个push操作将80推入栈中,第二个push将40推入栈中,Mstore()从栈中弹出两个操作数,由于栈的先进后出的特点,所以进行的操作是Mstore(40,80),也就是将0x80存放到memory中0x40的位置,刚才我们介绍了0x40是空闲内存指针,他其中存放的值即为下一个要存放进memory中的值存放的位置,所以如果EVM要存放下一个值进memory就应该存放在0x80的位置。(为什么第一个就存放在0x80的位置呢,因为刚才已经介绍过了memory的前四个存储块用作特殊用途!)
而且EVM规定,在每次使用空闲内存指针存储的数之前,都会先更新其中的值,拿下面的合约函数为例: <!--StartFragment-->
<!--EndFragment-->
在执行完212号指令之后,test变量的信息已经被全部存放到memory中了,string类型有两个信息会被存放在memory中,一是字符串长度0x13,二是字符串本身:
1.存储字符串长度19=0x13 <!--StartFragment-->
<!--EndFragment-->
<!--StartFragment-->
<!--EndFragment-->
2.更新空闲内存指针
<!--StartFragment-->
<!--EndFragment-->
进行完这一步之后,空闲内存指针的值被更新为100。
3.存储字符串本身 <!--StartFragment-->
<!--EndFragment-->
MSTORE、MSTORE8、MLOAD这三个操作码,对memory的工作至关重要。
1.MSTORE(arg0,arg1):该操作码的作用是从栈顶弹出两个元素,第一个为arg0,第二个为arg1,将arg1作为值存放到memory以arg0为序号的内存块。下面的图片描述了MSTORE的工作流程。 <!--StartFragment-->
<!--EndFragment-->
<!--StartFragment-->
<!--EndFragment-->
<!--StartFragment-->
<!--EndFragment-->
2.MLOAD(arg):该操作码的作用是从栈顶弹出一个元素作为arg,然后从memory中存储块为arg的位置取出其中的值返回栈中。下面的图片描述了MLOAD的工作流程。
<!--StartFragment-->
<!--EndFragment-->
<!--StartFragment-->
<!--EndFragment-->
<!--StartFragment-->
<!--EndFragment-->
3.MSTORE8(arg0,arg1):该操作码的作用和MSTORE操作码几乎一样,只是MSTORE操作码的存储的值以32字节为单位,即使你的值没有32字节,EVM也会自动为你填充至32字节。而MSTORE8操作码存储的值以1字节为单位。其他工作原理都一样。并且一般来说只有在代码中使用了汇编去指定,字节码中才会出现MSTORE8,否则都是MSTORE。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!