rdi 和 rsi 调用者保存还是被调用者保存的寄存器?

Posted

技术标签:

【中文标题】rdi 和 rsi 调用者保存还是被调用者保存的寄存器?【英文标题】:Are rdi and rsi caller saved or callee saved registers? 【发布时间】:2019-08-18 15:09:14 【问题描述】:

从*** x86 调用约定,它说对于 Microsoft x64 调用约定:

寄存器 RBX、RBP、RDI、RSI、RSP、R12、R13、R14 和 R15 被视为非易失性(被调用方保存)。

但对于 System V AMD64 ABI:

如果被调用者希望使用寄存器 RBX、RBP 和 R12-R15,则必须在将控制权返回给调用者之前恢复它们的原始值。

它没有提到任何关于 rdi 和 rsi 的内容。

我还了解到 %rax、%rcx、%rdx、%rdi、%rsi、%rsp 和 %r8-r11 被认为是调用者保存寄存器 (来自pdf)

我的问题是,不同平台的调用约定是否不同?(我尝试在 asm 中为 unix 环境编写一些 libc 函数)

我找不到任何讨论该主题的文章,该主题的资源也会有所帮助。我想知道这些约定的优缺点。

【问题讨论】:

【参考方案1】:

是的,在我知道的所有函数调用约定中,传递参数的寄存器都是调用破坏的。(除了系统调用调用约定,通常所有 regs 都会保留,除了一个返回值,包括参数传递。除了 x86-64 syscall 破坏 RCX 和 R11...)

特别是在 x86-64 System V 中,除 RBX、RBP、RSP 和 R12-R15 之外的所有寄存器都被调用破坏。 (包括 xmm0-15、x87/mmx 寄存器,以及 AVX512 zmm0-31 和 k0-k7 掩码寄存器。)

What registers are preserved through a linux x86-64 function call 显示 ABI 文档中的表格


调用约定/ABI 将寄存器的状态定义为调用保留或调用破坏。不同的约定可以做出不同的选择。

是的,Microsoft Windows 选择了与其他所有人不同的调用约定:Why does Windows64 use a different calling convention from all other OSes on x86-64? 在 Windows x64 中,RDI 是保留调用的,就像在大多数 32 位调用约定中一样。

但在 x86-64 System V 中,设计人员从头开始选择寄存器,并且(正如我对该链接问题的回答所示)发现将 RDI 和 RSI 用于前 2 个参数可以节省指令(使用早期 x86 构建 SPECint 时) gcc 的 -64 端口)。可能是因为当时 gcc 喜欢使用 rep stosd 内联 memsetmemcpy,或者库实现使用了它。

(说 RDI本质上被调用破坏是没有意义的,x86-64 ISA 没有定义它。这取决于每个平台来选择。)


术语:

我讨厌“调用者保存”与“被调用者保存”的术语:从 2 个不同的角度(调用者和被调用者)思考会令人困惑,并且错误地暗示每个寄存器确实都保存在某处每个call。此外,名称仅相差 1 个字母,因此在阅读时在视觉上不是很明显。

“preserved”或“clobbered”很棒;他们从任何一个角度工作。 (被调用者会对你的 regs 做什么,或者你可以对调用者的 regs 做什么。)此外,它们是不言自明的。

【讨论】:

所以如果我在 unix 环境中覆盖 rdi 并且不恢复它,可以吗? 哦,我刚刚阅读了您的更新答案,保留和破坏的术语听起来很棒,谢谢。 @Sayakura:是的,再次更新了 SysV ABI pdf 中的表格链接,该表格明确记录 RDI 和 RSI 为 call-clobbered。我之前很着急,没有看到你的问题部分,你只发现它们被用于参数传递,但没有确认这意味着它们被调用破坏了。它们本质上不是一回事,但在我见过的所有调用约定中,它们都是。 是的。这里的操作系统不同。 RSI 和 RDI 在 Unix x64 中被破坏,但在 Windows 中没有。有关完整概述,请参阅agner.org/optimize/calling_conventions.pdf

以上是关于rdi 和 rsi 调用者保存还是被调用者保存的寄存器?的主要内容,如果未能解决你的问题,请参考以下文章

被调用者分配被调用者释放

汇编笔记

调用者和被调用者中数组元素的值不同

使用rpcgen时,调用者如何找到被调用者?

GNU gcc/ld - 使用在同一个目标文件中定义的调用者和被调用者包装对符号的调用

使用引用调用时被调用者和调用者的值