0

在大多数语言中,C 包含的堆栈用于函数调用。这就是为什么如果您在递归中不小心会出现“堆栈溢出”错误的原因。(双关语不是故意的)。

asmlinkage如果这是真的,那么GCC 指令有什么特别之处。

它说,来自#kernelnewbies

asmlinkage 标签是关于这个简单函数的另一件事。这是一些 gcc 魔术的#define,它告诉编译器该函数不应该期望在寄存器中找到它的任何参数(一种常见的优化),而只能在 CPU 的堆栈上。

我的意思是我不认为寄存器用于正常的函数调用

更奇怪的是,当你了解到它是在 x86 上使用 GCC regparm 函数属性实现的。

regparm的文档如下:

在 x86-32 目标上,如果参数是寄存器 EAX、EDX 和 ECX 中的整数类型,而不是堆栈中的参数,则 regparm 属性会导致编译器将参数编号 1 传递给编号。

这基本上与asmlinkage正在尝试做的事情相反。

那么会发生什么?它们是在堆栈上还是在寄存器上。

我哪里错了?

信息不是很清楚。

4

1 回答 1

6

通常,为了使调用更快(取决于架构),编译器可以选择通过寄存器传递一些参数,以避免每次将它们复制到堆栈中/从堆栈中复制它们。对于未导出的私有函数尤其如此,因此不需要遵守 ABI 定义的调用约定,以便进一步优化。

一些 ABI 实际上需要在寄存器中传递参数。System V AMD64 ABI 调用约定(Linux x86-64 上的默认值)就是一个很好的例子:它规定函数参数应该通过 RDI、RSI、RDX、RCX、R8、R9、[XYZ]MM0–7、所以堆栈很少使用。

现在,当在 Linux 中进行系统调用时,内核将用户空间寄存器复制到堆栈上以保存它们,然后调用适当的系统调用函数。这些函数应直接从堆栈上已保存的用户寄存器中获取参数,因此必须编译为始终从堆栈中获取参数。

在 x86 32bit 中,asmlinkage扩展为 __attribute__((regparam(0))),这基本上告诉 GCC不应通过寄存器传递任何参数0(这是重要的部分)。在 x86 64 位上,它改为扩展为更具体的__attribute__((syscall_linkage))。最终结果是一样的:函数被迫从堆栈中获取参数。在其他总是在堆栈上传递参数的架构上,__attribute__甚至不需要特殊的。

于 2020-05-06T13:28:31.517 回答