'asmlinkage'修饰符的用途是什么?

53

我读到过它被用于在Linux中实现系统调用的函数。

asmlinkage long sys_getjiffies( void )
{
  return (long)get_jiffies_64();
}

它告诉编译器将所有函数参数传递到堆栈上。但这不是已经这种情况了吗?函数参数通常是通过将它们推送到堆栈上来传递的。或者是指在这里提到通过寄存器传递函数参数吗?


5
请注意,Linux内核函数的第一个参数默认情况下会在x86上通过寄存器传递。在x86-32上,前三个参数依次在 %eax%edx%ecx 中传递,其余部分则在堆栈中传递。具有可变参数列表的函数是一个例外,在x86-32上它们所有的参数都在堆栈中传递。在x86-64上,前6个参数依次在 %rdi%rsi%rdx%rcx%r8%r9 中传递(即使对于具有可变参数的函数也是如此),其余部分在堆栈中传递。然而,系统调用遵循不同的规定。 - Eugene
正如@dirkgently所指出的那样,asmlinkage是一种覆盖参数传递默认约定的方法。还可以在Agner Fog的手册中找到各种调用约定的详细描述。 - Eugene
1
在Quora上有一个很好的解释:https://www.quora.com/Linux-Kernel/What-does-asmlinkage-mean-in-the-definition-of-system-calls。 - Nan Xiao
1个回答

48

这里有一个常见问题

“asmlinkage”标记是我们需要注意的另一件事。这是一种针对gcc的魔法# define,告诉编译器该函数不应期望在寄存器中找到其任何参数(常见优化),而只能在CPU的堆栈上找到。回想一下我们之前的断言:system_call消耗其第一个参数(系统调用号),并允许最多四个传递给真实系统调用的参数。system_call通过将其它参数(已在寄存器中传递给它的参数)保留在堆栈中来实现这一点。所有系统调用都带有asmlinkage标记,因此它们都会在堆栈中查找参数。当然,在sys_ni_syscall的情况下,这没有任何影响,因为sys_ni_syscall不需要任何参数,但对于大多数其他系统调用而言,这是一个问题。而且,由于你将在许多其他函数前面看到asmlinkage,所以我认为你应该知道它是什么。同时,它也用于允许从汇编文件中调用函数。

16
原文:The reason is that anyhow the kernel needs to save all the registers onto stack (in order to restore the environment before returning to the userspace) when handling the system call requests from userspace, so after that the parameters are available on stack. I.e., it doesn't need extra effort.翻译:原因在于内核无论如何都需要将所有寄存器保存到堆栈中(以便在返回用户空间之前还原环境)处理来自用户空间的系统调用请求,因此参数在堆栈上可用。也就是说,这不需要额外的努力。 - kumar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接