本文介绍了在以太坊虚拟机(EVM)中引入三条新的指令 SWAPN、DUPN 和 EXCHANGE 以提升栈操作的灵活性,这三条指令允许访问深达256个项的栈,简化了编译器的设计,并支持更复杂的函数调用。文章详细阐述了这些新指令的规范、执行规则、兼容性及安全性考虑。
目前,SWAP* 和 DUP* 指令的堆栈深度限制为 16。引入三条新指令,SWAPN、DUPN 和 EXCHANGE,以消除此限制并允许在更高的深度访问堆栈。
虽然堆栈深度为 1024 项,但只能轻松访问顶部 16 项。通过手动将更多局部变量保留在内存中或通过编译器的“堆栈到内存提升”功能,可以支持更多局部变量。这可能导致复杂且低效的代码。
此外,在 EVM 上实现更高级的构造(例如函数)将导致输入和输出参数列表,以及返回的指令偏移量。
这些参数(或堆栈项)的数量可能轻易超过 16,因此可能需要编译器额外小心以确保它们都能被访问。
最后,交换堆栈中除第一个和第 N 项以外的项对实施堆栈调度算法的编译器非常重要(堆栈机器的寄存器分配类比),该算法在给定变量和使用分析的情况下试图最小化堆栈流量。
引入 SWAPN、DUPN 和 EXCHANGE 将为编译器提供简化访问深层堆栈项的选项。
我们引入三条新指令:
DUPN (0xe6)SWAPN (0xe7)EXCHANGE (0xe8)如果代码是遗留字节码,这些指令中的任何一条都会导致 异常中止。 (注意:这意味着行为不变。)
如果代码是有效的 EOF1,适用以下规则:
imm,其值可以为 0 到 255。
DUPN 和 SWAPN 的情况下,引入变量 n 等于 imm + 1。EXCHANGE 的情况下,引入变量 n 等于 imm >> 4 + 1,以及变量 m 等于 imm & 0x0F + 1(即 imm 的前两个半字节,转换为一索引)。RJUMP/RJUMPI/RJUMPV) 指向 DUPN、SWAPN 或 EXCHANGE 的立即数值。DUPN 前,如果当前堆栈高度小于 n,则代码无效。在 DUPN 后,堆栈高度增加。SWAPN 前,如果当前堆栈高度小于 n + 1,则代码无效。在 SWAPN 后,堆栈高度不变。EXCHANGE 前,如果当前堆栈高度小于 n + m + 1,则代码无效。在 EXCHANGE 后,堆栈高度不变。DUPN:第 n 项堆栈项被复制到堆栈顶部。(注意:这里使用的是 1 基索引。)SWAPN:第 n + 1 项堆栈项与堆栈顶部交换。EXCHANGE:第 n + 1 项堆栈项与第 n + m + 1 项堆栈项交换。所有三条指令的 gas 成本设定为 3。
允许动态选择要交换、复制或交换的参数可能会阻止对堆栈内容的静态分析。由于静态分析是安全审计人员的重要工具,我们希望尽可能简化他们的工作。因此,操作数需要一个不是动态性质的立即数参数。
由于该指令依赖于立即数参数编码,因此只能在 EOF 内启用。在遗留字节码中,该编码可能会与跳转目标分析相矛盾。
对于 DUPN 和 SWAPN,考虑使用 16 位大小以适应堆栈空间的 1024 项,但是:
n < 1024)。对 EXCHANGE 同样,提议的方案允许寻址 32 项。
这些操作的 gas 成本与现有的 DUP* 和 SWAP* 指令相同,因为它们仅作为指针交换实现。
EXCHANGE 与 SWAPN如前所述,EXCHANGE 对实现堆栈调度算法的编译器非常重要。具体而言,在堆栈项计划在堆栈更深处被消耗的情况下(例如,堆栈中的第 3 项需要移至第 2 个位置以供下一个操作使用),目前需要三条指令 SWAP2 SWAP3 SWAP2。然而,在 EVM 实现中,该实现仅是一个指针交换,因此可以在没有额外运行时成本的情况下以一条指令实现。
这对向后兼容性没有影响,因为操作码之前未被分配,并且该功能仅在 EOF 中启用。
给定 stack[] 是一个以 0 为基础的数据结构,n、m 和 imm 根据规范定义:
DUPN imm 在 stack_height < n 的情况下验证失败。SWAPN imm 在 stack_height < n + 1 的情况下验证失败。EXCHANGE imm 在 stack_height < n + m + 1 的情况下验证失败。DUPN imm 应增加函数的最大堆栈高度。如果最大堆栈高度超过 1023 的限制,则验证失败。DUPN imm、SWAPN imm 和 EXCHANGE imm 在运行时如果可用的 gas 少于 3 则失败。DUPN imm 应复制 stack[n - 1] 项并将其推送到堆栈SWAPN imm 应交换 stack[n] 与 stack[stack.top()]EXCHANGE imm 应交换 stack[n] 与 stack[n + m]。作者未发现此处引入的任何附加风险。EVM 堆栈固定为 1024 项,大多数实现始终将其保存在内存中。这一变化将增加通过单一指令可访问的堆栈项数量。
由于 CC0,版权和相关权利已放弃。
- 原文链接: github.com/ethereum/EIPs...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!