我正在阅读Randal E. Bryant 和 David R. O'Hallaron 撰写的《计算机系统:程序员的视角》第三版。
在第3章和第7.5节中,有图演示了堆栈帧是如何分配的,如下所示:
我不明白为什么需要第 4 行和第 12 行。似乎不需要这些行,因为堆栈内存的剩余 8 个字节根本没有被使用。
正如评论所示,恕我直言,它似乎不可避免地被分配为按 24 字节对齐堆栈帧:
pushq %rbp和附加 16 个字节pushq %rbxsubq $8, %rsp所以,我的问题可以概括为“为什么堆栈帧按 24 字节对齐? ”
24 字节不是 2 的幂,因此不能对齐。真正的对齐是 16 字节,而您忘记了将call8 字节压入堆栈的指令。因此,堆栈指针总共移动了 32 个字节,保持与 16 个字节的对齐。
这与 x64 ABI(Microsoft 和 SystemV)一致。在调用函数之前,堆栈必须在 16 字节边界上对齐(在示例中为“call Q”)。我们假设堆栈最初位于 16 字节边界。当程序到达“P”标签时(由于“call P”指令),RSP 指向下方 8 个字节,因为“call”将 RSP 减去 8,并将 RIP(8 个字节)保存在 *RSP 处。然后,有两个“pushq”(第2行和第3行),每个都将RSP减少8,因此RSP仍然未对齐。这就是为什么编译器必须在第 8 行和第 10 行执行“call Q”之前减去 8 来对齐 RSP。
本文很好地描述了 x86/x64 ABI: https: //en.wikipedia.org/wiki/X86_calling_conventions