【发布时间】:2022-11-22 03:39:46
【问题描述】:
对 this post about UB 很感兴趣,我决定开始阅读 Jonathan Bartlett's Programming from the Ground Up 以尝试使用 C++ UB 并查看程序集的外观。
但是在尝试的过程中,我在一个非常简单的案例中发现了一些奇怪的东西。考虑这段代码
int foo(int * p) {
int y = 7;
if (p)
++y;
return y;
}
它的组装是
foo(int*):
cmpq $1, %rdi
movl $7, %eax
sbbl $-1, %eax
ret
现在我明白movl $7, %eax 将值7 放入eax 寄存器,然后由ret 返回给调用者。所以我也明白 sbbl $-1, %eax 是负责从 eax 的内容中减去 -1 并将结果存储到 eax 本身的指令,并且只有当 p 不为空时才会发生此指令。这让我假设 sbbl 正在使用由前面几行计算的隐藏布尔值。唯一的候选人,即使是名字,也是cmpq $1, %rdi。
但是什么是那正在做?从前面提到的书中,我了解到函数参数是通过堆栈从调用者传递给被调用者的:调用者将参数压入堆栈,而被调用者提取这些值。但是这里没有这样的东西。
那么%rdi 是什么?函数的第一个(在本例中仅)参数的寄存器?为什么会这样?是否有其他寄存器引用进一步的参数?多少?此外,有关此主题的良好信息来源是什么?
【问题讨论】:
-
RDI 持有 x86-64 System V 调用约定中的第一个整数/指针 arg。您正在阅读的书使用 32 位 x86 程序集,其中标准调用约定更旧且效率更低,仅使用堆栈参数。
标签: c++ assembly parameter-passing x86-64 cpu-registers