0

我在这本教科书上,Randal E. Bryant, David R. O'Hallaron - Computer Systems。A Programmer's Perspective [3rd ed.] (2016, Pearson)
我一直在搞不清楚作者是如何计算出 switch 表的案例编号的,如下所示~

我不确定的是他们如何获得案例编号,例如Case Ais Case 5: 以及如何Case 2/7Case Cand Case D,等等对于本示例中的其余案例

任何帮助表示感谢谢谢!

切换语句

汇编代码

给出的答案

4

1 回答 1

11

首先,你的书有一个错误——它说“ ain %rsi, bin %rdi”——但这不是标准的 x64 调用约定,它与程序集的其余部分不一致。

这本书的意思

  • %rdi-> a%rsi-> b%rdx->c%rcx->dest

继续,让我们了解会发生什么:


默认代码块

前两个操作码是:

cmpq $7, %rdi
ja .L2

ja如果高于则跳转,即如果a > 7然后转到.L2- 这是在程序集的末尾。我们可以推断这是default代码块(它立即继续到函数的末尾) - 在下面.L2我们有:

movq %rsi, %rdi
movq %rdi, %(rcx) ; this corresponds to *dest = val in C

因此我们可以得出结论,在这种情况下, %(rcx)gets%rsi的值 - 换句话说,在默认代码块中,val = b.


切换代码块

如果我们ja上面的第一个没有执行,那么我们jmp *.L4(,%rdi,8). 由于a不高于 7,我们有八种可能性 - 我们可以在.L4表中看到:

  • 如果a == 0然后我们跳转到.L3
  • 如果a == 1, a == 3, 或a == 6, 我们跳转到.L2我们的默认代码块,如上所述)
  • 如果a == 2a == 7我们跳转到.L5
  • 如果a == 4我们跳到.L6
  • 如果a == 5我们跳到.L7

.L3,或案例 0

这个块运行leaq 112(%rdx), %rdi,它只是具有设置%rdi%rdx + 112- 这是的效果c + 112。然后我们跳到函数的末尾——我们可以val = c + 112case 0代码块中得出结论。


.L7,或案例 5

这个块运行leaq (%rdx, %rsi), %rdi,它设置%rdi%rdx + %rsi(它是c + b)-然后调用salq $2, %rdi,它只是将此值左移 2 位-总值为(c + b) << 2. 然后我们跳到函数的末尾——我们可以val = (c + b) << 2case 5代码块中得出结论。


.L6,或案例 4

在这里,我们立即跳到了函数的末尾,只调用了movq %rdi, (%rcx)操作码——这实际上等同于设置*dest = a。我们可以得出结论,在这种情况下,val = a


.L7,或案例 5

此块运行xorq $15, %rsi- 相当于b ^= 15. 然后它运行movq %rsi, %rdx- 设置c为这个值。然后我们继续直接进入.L3上面描述的 - 设置val = c + 112。我们可以得出结论,这.L7是我们的故障开关盒。


一般来说,反转开关情况可能非常简单——它主要涉及理解跳转表如何对应于比较寄存器中的不同值(注意这里有几个可能的值如何a映射到表中的同一个跳转)——以及理解下降——不同开关盒之间的通道。

于 2021-09-20T06:20:02.573 回答