从Wikipedia 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)
我的问题是,在不同平台上调用约定是否不同?(我尝试在unix环境下的asm中编写一些libc函数)
我找不到任何讨论此主题的文章,该主题的资源也将有所帮助。我想知道这些约定的优点和缺点。
答案 0 :(得分:2)
是的,在我所知道的所有函数调用约定中,传递arg的寄存器都被调用了。(系统调用调用约定除外,通常所有的reg都保留下来,返回值,包括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文档中的表格。
调用约定/ ABI将寄存器的状态定义为保留呼叫或保留呼叫的状态。不同的约定可以做出不同的选择。
是的,Microsoft Windows选择了与其他所有人不同的调用约定:Why does Windows64 use a different calling convention from all other OSes on x86-64?在Windows x64中,就像大多数32位调用约定一样,RDI被保留了呼叫。
但是在x86-64 System V中,设计人员从头开始选择寄存器,并且(如我对这个链接问题的回答所示)发现,对于前2个args使用RDI和RSI可以节省指令(在使用早期x86构建SPECint时) -64 gcc端口)。可能是因为当时的gcc喜欢使用memset
内联memcpy
或rep stosd
,或者库实现使用了它。
(说RDI本质上是呼叫对象,x86-64 ISA并没有定义它。这取决于每个平台来选择。)
术语:
我讨厌“保存呼叫者”与“保存被呼叫者”这两个术语:从两种不同的角度(呼叫者和被呼叫者)思考是令人困惑的,并且错误地暗示每个寄存器都被保存每个call
。此外,名称之间仅相差1个字母,因此阅读时在视觉上并没有很大区别。
“保留”或“断断续续”很棒;他们从任何一个角度工作。 (被呼叫者将对您的规则执行什么操作,或者您被允许对呼叫者的规则进行操作。)此外,它们是不言自明的。