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

Are rdi and rsi caller saved or callee saved registers?

来自维基百科 x86 调用约定,它说对于 Microsoft x64 调用约定:

The registers RBX, RBP, RDI, RSI, RSP, R12, R13, R14, and R15 are considered nonvolatile (callee-saved).

但对于 System V AMD64 ABI:

If the callee wishes to use registers RBX, RBP, and R12–R15, it must restore their original values before returning control to the caller.

它没有提到任何关于 rdi 和 rsi 的事情。

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

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

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

是的,在我所知道的所有函数调用约定中,arg 传递寄存器都被调用破坏了。(除了系统调用约定,通常情况下除 return 值外,所有 regs 都被保留,包括 arg-passing。除了 x86-64 syscall 破坏 RCX 和 R11...)

特别是在 x86-64 系统 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 文档 中的 table。


调用约定/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 个参数保存的指令(在构建 SPECint 时使用gcc 的早期 x86-64 端口)。可能是因为当时的 gcc 喜欢使用 rep stosd 内联 memsetmemcpy,或者库实现使用它。

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


术语:

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

"preserved" 或 "clobbered" 很棒;他们从任何一个角度工作。 (被调用者将对您的注册做些什么,或者您可以对调用者的注册做些什么。)此外,它们是不言自明的。