1

我一直在寻找有关以太坊如何处理跳转和跳转目的地的信息。从各种博客和黄皮书我发现如下:

所采用的操作数JUMP和所采用的两个操作数中的第一个是设置为JUMPI的值PC(假设第一个堆栈值!= 0 在的情况下JUMPI)。

但是,查看合约的创建代码(作为操作码),前几个操作码/值是:

PUSH1 0x60 PUSH1 0x40 MSTORE CALLDATASIZE ISZERO PUSH2 0x00f8 JUMPI

据我了解,这意味着如果将值推入堆栈ISZERO!= 0 然后PC将更改为0x00f8asJUMPI从堆栈中获取两个,检查第二个是否为 0,如果不是,则设置PC为其第一个操作数的值。

我遇到的问题是0x00f8十进制是248. 合同中的第 248 位似乎是MSTORE而不是 a JUMPDEST,这将导致合同无法执行,因为JUMP*只能指向有效的JUMPDEST.

大概合同不会故意跳转到无效的目的地?

如果有人能解释如何解决跳转和跳转目的地,我将不胜感激。

4

2 回答 2

2

如果它帮助别人:

混淆是由 EVM 逐字节而不是逐字读取引起的。

从问题中的示例来看,0x00f8将是第 248 个字节,而不是第 248 个字。

由于每个操作码都是 1 字节长PC,因此在读取操作码时通常会加 1。

但是,在PUSH指令的情况下,还包括有关将以下字节中的多少作为其操作数的信息。

例如PUSH2取其后的 2 个字节,PUSH6取其后的 6 个字节,依此类推。对于 使用的数据的每个字节,此处PC将分别增加 1,PUSH然后分别增加 2 或 6 PUSH

于 2017-11-29T17:50:53.667 回答
1

只想指出JUMPJUMPI是有区别的。

JUMP只从堆栈中获取 1 个元素,即目标。这通常是推送到堆栈的十六进制偏移量。

JUMPI是一个条件跳转,它从堆栈中获取前 2 个元素,即目标和条件。

在您给出的示例中,条件是ISZERO(检查堆栈的最顶部元素是否为 0)。
因此,如果返回 true,它将跳转到偏移量 0x00f8(十进制为 248)的目标。

如果条件为 False,它只会将程序计数器增加 1。

在您提到的合同中,它是(程序计数器)248 处的 JUMPDEST 操作码。

程序计数器取决于操作码。操作码将多少字节推入堆栈等。例如

PUSH1 0x60  - PC[0]
PUSH1 0x40  - PC[2]
MSTORE      - PC[4]
CALLDATASIZE- PC[5]
ISZERO      - PC[6]
PUSH2 0x00f8- PC[7]
JUMPI       - PC[10]

也许这个网站会让你更好地理解操作码https://ethervm.io/

于 2018-08-17T09:34:45.957 回答