gpt4 book ai didi

assembly - x86_64 Linux 函数和系统调用之间的 ABI 差异

转载 作者:行者123 更新时间:2023-12-02 00:16:36 25 4
gpt4 key购买 nike

x86_64 SysV ABI的函数调用约定定义了要在 rcx 寄存器中传递的整数参数 #4。另一方面,Linux 内核系统调用 ABI 使用 r10 来实现相同的目的。所有其他参数都在函数和系统调用的相同寄存器中传递。

这会导致一些奇怪的事情。例如,查看 x32 平台上 glibc 中 mmap 的实现(存在相同的差异):

00432ce0 <__mmap>:
432ce0: 49 89 ca mov %rcx,%r10
432ce3: b8 09 00 00 40 mov $0x40000009,%eax
432ce8: 0f 05 syscall

所以所有寄存器都已经就位,除了我们将 rcx 移动到 r10

我想知道为什么不将系统调用 ABI 定义为与函数调用 ABI 相同,因为它们已经如此相似。

最佳答案

syscall instruction旨在提供一种更快的方法进入 Ring-0 以执行系统调用。这是对旧方法的改进,旧方法是引发软件中断(Linux 上的 int 0x80)。

该指令速度更快的部分原因是它不会更改内存,甚至不会更改 rsp 来指向内核堆栈。与软件中断不同,在软件中断中,CPU 被迫允许操作系统在不破坏任何内容的情况下恢复运行,对于此命令,CPU 可以假设软件知道此处正在发生某些事情。

特别是,syscall 将用户空间状态的两部分存储在寄存器中。调用后返回的 RIP 存储在 rcx 中,标志存储在 R11 ( because RFLAGS is masked with a kernel-supplied value before entry to the kernel ) 中。这意味着这两个寄存器都被指令破坏了。

由于它们被破坏,系统调用 ABI 使用另一个寄存器而不是 rcx,因此使用 r10 作为第四个参数。

r10 是一个自然的选择,因为 in the x86-64 SystemV ABI它不用于传递函数参数,并且函数不需要保留其调用者的 r10 值。因此,系统调用包装函数可以mov %rcx, %r10而无需任何保存/恢复。对于 6-arg 系统调用和 SysV ABI 的函数调用约定,这对于任何其他寄存器都是不可能的。

<小时/>

顺便说一句,32位系统调用ABI也可以通过sysenter访问,这需要用户空间和内核空间之间的合作,以允许在sysenter<之后返回到用户空间。 (即在运行 sysenter 之前在用户空间中存储某些状态)。这比 int 0x80 性能更高,但很尴尬。尽管如此,glibc 仍然使用它(通过跳转到 vdso 页面中的用户空间代码,内核将其映射到每个进程的地址空间)。

AMD 的 syscall 是另一种与 Intel 的 sysenter 理念相同的方法:通过不保留所有内容来降低进入/退出内核的成本。

关于assembly - x86_64 Linux 函数和系统调用之间的 ABI 差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38577609/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com