Linux 内核应该将 asmlinkage 用于实现系统调用的函数吗?

问题描述

我正在尝试在 linux 内核中实现一个新的系统调用,所以我写道:

asmlinkage int my_func(void) {
    return my_func_internal();
}

我的问题,我应该将 my_func_internal 定义为 asmlinkage 还是不?

换句话说,我应该写A还是B?

A) asmlinkage int my_func_internal(void) {return 1;}

B) int my_func_internal(void) {return 1;}

我也想解释一下

注意:我已经将 my_func 添加到 syscalls.h 中,我是否也应该添加内部的(可能答案是否定的)

解决方法

对于没有被手写 asm直接调用的函数,您使用什么调用约定并不重要(为了正确性)。 (哪些系统调用实现函数可能在某些架构上,这就是为什么它们应该是 asmlinkage。)只要所有调用者都能看到与定义匹配的原型,它就会工作。

如果 asmlinkinkage 是与默认调用约定不同的调用约定(例如在 i386 上,asmlinkage 表示使用堆栈参数,覆盖使内部函数使用寄存器参数的 -mregparm=3 构建选项),编译器将不得不为 my_func 发出一个定义来处理差异,如果它调用一个不是 asmlinkage 的函数。或者简单地将 my_func_internal() 内联到其中。

如果它们使用相同的调用约定,并且编译器选择不内联,它可以只对 my_func_internal 进行优化的尾调用,例如在 x86 jmp my_func_internal 上。因此,使用相同的调用约定可能具有效率优势如果存在优化的尾调用的可能性。否则不要; asmlinkage 使 i386 上的调用约定效率较低。

(IIRC,asmlinkage 对 x86-64 和大多数其他具有 register-args 调用约定的现代 ISA 没有影响;x86 上的默认调用约定已经很好,因此内核不需要用-mregparm=3 就像在 i386 上一样。)

在没有参数的示例中,没有区别。


顺便说一句,函数名称的常用命名约定是 sys_foo 以实现名为 foo 的系统调用。即当用户空间通过 __NR_foo 作为调用号时将被调用的函数。


注意:我已经将 my_func 添加到 syscalls.h 中,我是否也应该添加内部的(可能答案是否定的)

当然不是,除非 my_func_internal 实现了一个不同的系统调用,您希望用户空间能够直接调用该系统调用。