![](/img/trans.png)
[英]Linux x64: why does r10 come before r8 and r9 in syscalls?
[英]When does Linux x86-64 syscall clobber %r8, %r9 and %r10?
我刚刚浏览了 Linux 内核源代码树并阅读了文件tools/include/nolibc/nolibc.h 。
我看到这个文件中的syscall
在 clobber 列表中使用了%r8
、 %r9
和%r10
。
还有一条评论说:
rcx 和 r8..r11 可能会被破坏,其他的会被保留。
据我所知, syscall
只破坏%rax
、 %rcx
和%r11
(和内存)。
是否有一个真实的syscall
示例来破坏%r8
、 %r9
和%r10
?
只有 64 位模式下的 32 位系统调用(例如通过int 0x80
)和 R11 一起在这些寄存器上执行。 ( 如果您在 64 位代码中使用 32 位 int 0x80 Linux ABI,会发生什么? )。
syscall
正确保存/恢复所有 regs,包括 R8、R9 和 R10,因此使用它的用户空间可以假设它们保留它们的值,除了 RAX 返回值。 (内核的系统调用入口点甚至保存了 RCX 和 R11,但此时它们已经被syscall
指令本身用原始 RIP 和屏蔽前的 RFLAGS 值覆盖了。)
那些带有 R11 的寄存器是在函数调用约定中被调用破坏的非遗留寄存器,因此内核中 C 函数的编译器生成的代码自然会保留 R12-R15,即使 asm 入口点没有保存他们。
目前,64 位int 0x80
入口点只是为进程状态结构中的调用破坏的 R8-R11 寄存器推送0
,它将在返回用户空间之前从中恢复,而不是原始寄存器值。 也许早些时候有信息泄漏,在内核代码返回后它们没有受到影响?
根据 x86-64 ABI 关于系统调用部分 A.2 AMD64 Linux 内核约定,A.2.1 调用约定 [1]:
用户级应用程序使用整数寄存器来传递序列
%rdi
、%rsi
、%rdx
、%rcx
、%r8
和%r9
。 内核接口使用%rdi
、%rsi
、%rdx
、%r10
、%r8
和%r9
。系统调用是通过
syscall
指令完成的。 内核销毁寄存器%rcx
和%r11
。
syscall
的编号必须在寄存器%rax
传递。系统调用仅限于六个参数,没有参数直接在堆栈上传递。
从
syscall
返回,寄存器%rax
包含系统调用的结果。 -4095 和 -1 之间范围内的值表示错误,它是 -errno。只有类 INTEGER 或类 MEMORY 的值被传递给内核。
从 (2)、(5) 和 (6),我们可以得出结论,Linux x86-64 系统调用 clobbers %rax
、 %rcx
和%r11
(以及"memory"
)。
链接: https : //gitlab.com/x86-psABI/x86-64-ABI/-/wikis/x86-64-psABI [1]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.