是否保存了rdi和rsi呼叫者或被呼叫者保存的寄存器?

时间:2019-03-27 22:39:45

标签: assembly x86-64 nasm calling-convention

从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函数)

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

1 个答案:

答案 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内联memcpyrep stosd,或者库实现使用了它。

(说RDI本质上是呼叫对象,x86-64 ISA并没有定义它。这取决于每个平台来选择。)


术语:

我讨厌“保存呼叫者”与“保存被呼叫者”这两个术语:从两种不同的角度(呼叫者和被呼叫者)思考是令人困惑的,并且错误地暗示每个寄存器都被保存每个call。此外,名称之间仅相差1个字母,因此阅读时在视觉上并没有很大区别。

“保留”或“断断续续”很棒;他们从任何一个角度工作。 (被呼叫者将对您的规则执行什么操作,或者您被允许对呼叫者的规则进行操作。)此外,它们是不言自明的。