当前位置: 首页 > 知识库问答 >
问题:

rdi和rsi是呼叫方保存的寄存器还是被叫方保存的寄存器?

戚勇
2023-03-14

在wikipedia x86调用约定中,它说对于Microsoft x64调用约定:

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

但对于System V AMD64 ABI:

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

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

我找不到任何关于这个话题的文章,关于这个话题的资源也会有帮助。我想知道这些惯例的优点和缺点。

共有1个答案

陶飞英
2023-03-14

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

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

通过Linux86-64函数调用保留的寄存器显示了ABI文档中的表。

是的,Microsoft Windows选择了与其他操作系统不同的调用约定:为什么Windows64在x86-64上使用了与所有其他操作系统不同的调用约定?在Windowsx64中,与大多数32位调用约定一样,RDI被调用保留。

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

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

我讨厌“呼叫方保存”与“被呼叫方保存”的术语:从两个不同的角度(呼叫方和被呼叫方)来思考会让人困惑,并且错误地暗示每个呼叫上的每个寄存器都保存在某个地方。而且,名字只相差一个字母,所以在阅读时视觉上不是很明显。

“保存”或“重击”是伟大的;它们从两个角度都起作用。(被呼叫者将对您的regs做什么,或者允许您对呼叫者的regs做什么。)而且,它们是不言自明的。

 类似资料:
  • 我正在为一个操作系统分配编写内联汇编代码。我有一些关于内联汇编和gcc编译器将其转换为机器代码的问题。 null

  • 7.5.6 寄存器的保护和恢复 保护寄存器说明子句的说明格式: USES 寄存器列表 该说明子句要求汇编程序为其生成保护和恢复寄存器的指令序列,即:在进入子程序执行指令之前,把寄存器列表中的寄存器压进堆栈,在结束子程序执行时,把先前压进堆栈的寄存器弹出,以达到保护寄存器的目的。 寄存器列表:列举出在子程序中需要保护的寄存器名,即:在子程序开始时需要把内容进栈的寄存器名。若有多个寄存器名,则在寄存器

  • 7.4 寄存器的保护与恢复 由于计算机的硬件资源只有一套,当子程序修改了寄存器的内容后,返回到调用它的程序时,这些寄存器的内容也就不会是调用子程序前的内容。这样,子程序修改寄存器内容就可能变成了调用它的副作用,这种副作用常常会导致调用程序的出错。为此,在编写子程序时,除了能对作为入口和出口参数的寄存器进行修改外,对其它寄存器的修改对调用程序来说都要是透明的,也就是说,在调用子程序指令的前后,除了作

  • 问题:执行相应行后,用保存在相应寄存器中的值填充间隙。以十六进制和32位输入所有值。 我的想法是:我是大会新手。我知道EAX、EBX、ECX、EDX、ESI、EDI、ESP或EBP等值适用于任何32位寄存器。或AX、BX、CX或DX等值适用于任何16位寄存器。我读过xor eax,eax-将eax的内容设置为零。这意味着第一个间隙是0x00000000,对吗?第二个gap将0x12345678复制

  • Vim提供了许多寄存器。可以将这些寄存器用作多个剪贴板。使用多个文件时,此功能非常有用。在本章中,将讨论以下主题内容 - 复制寄存器中的文本 粘贴寄存器中的文本 列出可用的寄存器 寄存器类型 1. 复制寄存器中的文本 对于复制,可以使用普通的命令,即并将其存储在寄存器中,可以使用以下语法 - 例如,要复制寄存器中的文本,请使用以下命令 - 2. 粘贴寄存器中的文本 从寄存器粘贴文本 - 例如,下面

  • 当前的Perl 5虚拟机是一台堆栈机器。 它通过将操作保持在堆栈上来传递操作之间的值。 操作将值加载到堆栈上,执行他们需要执行的操作并将结果放回堆栈。 这很容易使用,但速度很慢。 要将两个数字相加,您需要执行三次堆栈推送和两次堆栈弹出。 更糟糕的是,堆栈必须在运行时增长,这意味着在您不想分配内存时分配内存。 因此,Parrot将打破虚拟机的既定传统,并使用寄存器架构,更类似于真实硬件CPU的架构。