【问题标题】:how to get case number for jump table from a switch statement如何从 switch 语句中获取跳转表的案例编号
【发布时间】:2021-11-13 21:06:12
【问题描述】:

我在这本教科书上,Randal E. Bryant, David R. O'Hallaron - Computer Systems。程序员的视角 [第 3 版](2016 年,Pearson)
我一直在搞不清楚作者是如何计算出switch table的case number的,如下图~

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

感谢您的帮助!

【问题讨论】:

  • 在跳转表中,cases从0开始,所以case 0跳转到.L3。案例 2 和 7 跳转到.L5。案例 4 跳转到.L6。案例 5 跳转到.L7。案例 1、3、6 和任何大于 7 或小于 0 的数字,跳转到default 标签,即.L2
  • 您发布的第三张图片包含对他们如何计算案件编号的解释。所以我不确定我是否理解你的问题。您对解释有什么不清楚的地方?
  • 这可能是 CS:APP 3e 全球版吗?如果是这样,那将解释实践问题中的错误,例如丹尼尔回答中提到的混合调用约定。有关详细信息,请参阅CS:APP example uses idivq with two operands?。如果没有,那么它有望列在非全球版本的勘误表中。 csapp.cs.cmu.edu/3e/errata.html。哦,是的,那里列出了那个问题,所以可能你有一个很好的版本,这是那个版本中少数勘误表之一。
  • 请勿发布代码、数据、错误消息等的图片 - 将文本复制或输入到问题中。 How to Ask

标签: c assembly x86 switch-statement jump-table


【解决方案1】:

首先,你的书有一个错误 - 它说“a in %rsi, b in %rdi” - 但这是not the standard x64 calling convention与程序集的其余部分不一致。

这本书的意思

  • %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) 获得了%rsi 的值——换句话说,在默认代码块中,val = b


切换代码块

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

  • 如果a == 0 那么我们跳转到.L3
  • 如果a == 1a == 3a == 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 位-总值为@ 987654374@。然后我们跳到函数的末尾——我们可以得出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 是我们的直通开关盒。


一般来说,反转 switch case 可以非常简单 - 它主要涉及了解跳转表如何对应于比较寄存器中的不同值(注意这里a 的几个可能值如何映射到表中的同一个跳转) - 并了解不同 switch 案例之间的失败。

【讨论】:

  • 在勘误表csapp.cs.cmu.edu/3e/errata.html 中列出了这一问题中的调用约定寄存器混淆。所以希望这不是 CS:APP 3e 全球版 a disaster 的标志
  • 我们还要提醒读者,ja 是一个无符号比较,因此负长值将“高于”7 并采用默认值。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-24
  • 2014-08-30
  • 2016-01-17
  • 2017-03-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多