如何将参数传递给Linux系统调用?通过寄存器还是栈?

问题描述 投票:0回答:1

我想通过阅读以下文章来了解Linux内核的内部结构。Robert Love的Linux内核开发.

在第74页,他说最简单的方法是将参数传递给一个 syscall 是通过.NET来实现的。

在陷阱期间,用户空间必须以某种方式将参数传递给内核.最简单的方法是通过传递syscall号的方式。最简单的方法是通过与传递syscall号相同的方式:参数被存储在寄存器中。在x86-32中,寄存器ebx、ecx、edx、esi和edi依次包含前五个参数。

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

  1. 所有的系统调用都是用 asmlinkage 选项。这意味着参数是 总是在堆栈中找到,而不是在寄存器中找到。. 那么这些寄存器是怎么回事呢?
  2. 有可能在系统调用执行之前,寄存器的值被复制到内核栈中。我不知道为什么这样做会很有效率,但这可能是一种可能性。
c linux linux-kernel system-calls interrupt
1个回答
3
投票

(这个答案是针对32位x86 Linux的,以符合你的问题;64位x86和其他架构的情况略有不同。)

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

当用户空间调用系统调用时,用 int $0x80,内核系统调用入口代码得到控制。 这是用汇编语言写成的,可以看出 此处比如说。 这段代码要做的事情之一是从寄存器中获取参数并将其推送到堆栈中,然后调用相应的内核的 sys_XXX() 函数(用C语言编写)。 所以这些函数的确是在堆栈上期望它们的参数。

如果想把参数从用户空间传到堆栈上的内核,效果就不太理想了。 当系统调用时,CPU会切换到一个单独的内核栈,所以必须把参数从用户空间栈复制到内核栈,这有点复杂。 而且,即使是对于那些只需要几个数字参数的非常简单的系统调用,也必须这样做,否则根本不需要访问用户空间内存(想一想 close() 例如)。)

© www.soinside.com 2019 - 2024. All rights reserved.