为什么这个 Cairo 程序会在内存中放入 2 的幂?

Why does this Cairo program put powers of 2 in the memory?

我正在尝试根据“开罗的工作原理”教程解决 this bonus question。我运行以下函数,打开Cairo tracer,发现内存已满2的幂。这是为什么?

func main():
    [fp + 1] = 2; ap++
    [fp] = 5201798304953761792; ap++
    jmp rel -1
end

以下是一些可以帮助您找到答案的引导性问题。休息后回答问题:

  1. jmp rel -1指令跳转到哪里?
  2. 目标指令的作用是什么?之后会发生什么?
  3. 这条指令是怎么进入内存的程序段的?

  1. jmp rel -1 在内存中的地址 5-6 处进行编码。当它执行时,我们有pc = 5,因此跳转后我们将执行pc = 4处的指令,即0x48307fff7fff8000
  2. 此字节码对指令 [ap] = [ap - 1] + [ap - 1]; ap++ 进行编码(要检查,您可以手动解码标志和偏移量,或者简单地使用此指令编写一个 cairo 程序并查看它编译成什么)。执行完后,pc加1,我们又执行jmp rel -1,如此循环往复。应该清楚为什么这会用 2 的幂填充内存(第一个 2,地址 10,由 [fp + 1] = 2; ap++ 指令写入)。
  3. 指令[fp] = 5201798304953761792; ap++有一个直接参数(右侧,5201798304953761792)。带有直接参数的指令在内存中被编码为两个字段元素,第一个编码通用指令(例如 [fp] = imm; ap++),第二个是立即值本身。这个立即数就这样写在了地址4,5201798304953761792确实和0x48307fff7fff8000是一样的。同理,地址2的2是指令[fp + 1] = 2的立即数,地址6的-1jmp rel -1.
  4. 的立即数

总而言之,这种奇怪的行为是由于相对跳转移动到立即值的地址并将其解析为独立指令造成的。通常这不会发生,因为 pc 在执行带有立即数的指令后增加 2,而在执行没有立即数的指令时增加 1,所以它总是继续到下一条编译指令。此处需要未标记的跳转才能到达这个意外的程序计数器。