参数如何传递给 Linux 系统调用?通过寄存器或堆栈?

How are parameters passed to Linux system call ? Via register or stack?

我试图通过阅读 Robert Love's Linux Kernel Development 来了解 Linux 内核的内部结构。

在第 74 页上,他说将参数传递给 syscall 的最简单方法是通过 :

Somehow, user-space must relay the parameters to the kernel during the trap.The easiest way to do this is via the same means that the syscall number is passed: The parameters are stored in registers. On x86-32, the registers ebx, ecx, edx, esi, and edi contain, in order, the first five arguments.

现在这让我很困扰,原因有很多:

  1. 所有系统调用都使用 asmlinkage 选项定义。这意味着参数是 。那么寄存器的所有这些业务是什么?
  2. 在执行系统调用之前,可能会将值复制到内核堆栈中。我不知道为什么这样会有效,但它可能是一种可能性。

(此答案适用于 32 位 x86 Linux 以匹配您的问题;64 位 x86 和其他架构的情况略有不同。)

正如 Love 所说,参数是从用户空间在寄存器中传递的。

当用户空间使用 int [=10=]x80 调用系统调用时,内核系统调用入口代码获得控制权。这是用汇编语言写的,可以看here,例如。这段代码所做的其中一件事是从寄存器中获取参数并将它们压入堆栈,然后调用适当的内核 sys_XXX() 函数(这是用 C 语言编写的)。所以这些函数确实期望它们的参数在堆栈上。

尝试将参数从用户空间传递到堆栈上的内核不会很好。当进行系统调用时,CPU 切换到一个单独的内核堆栈,因此必须将参数从用户空间堆栈复制到内核堆栈,这有点复杂。即使是非常简单的系统调用也必须这样做,这些系统调用只需要几个数字参数,否则根本不需要访问用户空间内存(例如考虑 close())。