相信大家在看linux的source code的时候,都会注意到asmlinkage这个宏,linux内核中所有的系统调用的实现都使用了asmlinkage修饰符,它是用来做什么的呢?
The asmlinkage tag is one other thing that we should observe about this simple function. This is a #define for some gcc magic that tells the compiler that the function should not expect to find any of its arguments in registers (a common optimization), but only on the CPU's stack. Recall our earlier assertion that system_call consumes its first argument, the system call number, and allows up to four more arguments that are passed along to the real system call. system_call achieves this feat simply by leaving its other arguments (which were passed to it in registers) on the stack. All system calls are marked with the asmlinkage tag, so they all look to the stack for arguments. Of course, in sys_ni_syscall's case, this doesn't make any difference, because sys_ni_syscall doesn't take any arguments, but it's an issue for most other system calls.
linux i386 kernel中:
看一下/usr/include/asm/linkage.h里面的定义:
#define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0)))
__attribute__是关键字,是gcc的C语言扩展,regparm(0)表示不从寄存器传递参数
如果是__attribute__((regparm(3))),那么调用函数的时候参数不是通过栈传递,而是直接放到寄存器里,被调用函数直接从寄存器取参数。
gcc编译器在汇编过程中调用c语言函数时传递参数有两种方法:一种是通过堆栈,另一种是通过寄存器。缺省时采用寄存器,假如你要在你的汇编过程中调用c语言函数,并且想通过堆栈传递参数,你定义的c函数时要在函数前加上宏asmlinkage。
------------------------------------------------------------------------------------------------------
Linux i386+源码中常见宏标识tag的定义
这些宏包括 __init、__initdata、__initfunc()、asmlinkage、ENTRY()、FASTCALL()等等。它们的定义主要位于Include\linux\linkage.h和 include\asm-i386\Init.h以及其他一些.h文件中。
1) __init位置:include\asm-i386\Init.h
定义:#define __init __attribute__ ((__section__ (".text.init")))
注释:这个标志符和函数声明放在一起,表示gcc编译器在编译的时候需要把这个函数放.text.init section中,而这个section在内核完成初始化之后,会被释放掉。
举例:asmlinkage void __init start_kernel(void){...}
2) __initdata
位置:include\asm-i386\Init.h
定义:#define __initdata __attribute__ ((__section__ (".data.init")))
注释:这个标志符和变量声明放在一起,表示gcc编译器在编译的时候需要把这个变量放在.data.init section中,而这个section在内核完成初始化之后,会被释放掉。
举例:static struct kernel_param raw_params[] __initdata = {....}
3) __initfunc()
位置:include\asm-i386\Init.h
定义: #define __initfunc(__arginit) \
__arginit __init; \
__arginit
注释: 这个宏用来定义一个 __init 函数。
举例: __initfunc(void mem_init(unsigned long start_mem, unsigned long e
nd_mem)) {....}
4) asmlinkage
位置:Include\linux\linkage.h
定义:#define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0)))
注释:这个标志符和函数声明放在一起,告诉gcc编译器该函数不需要通过任何寄存器来传递参数,参数只是通过堆栈来传递。
举例:asmlinkage void __init start_kernel(void){...}
5) ENTRY()
位置:Include\linux\linkage.h
定义: #define ENTRY(name) \
.globl SYMBOL_NAME(name); \
ALIGN; \
SYMBOL_NAME_LABEL(name)
注释: 将name声明为全局,对齐,并定义为标号。
举例: ENTRY(swapper_pg_dir)
.long 0x00102007
.fill __USER_PGD_PTRS-1,4,0
/* default: 767 entries */
.long 0x00102007
/* default: 255 entries */
.fill __KERNEL_PGD_PTRS-1,4,0
等价于
.globl swapper_pg_dir
.align 16,0x90
/* if i486+ */
swapper_pg_dir:
.long 0x00102007
.fill __USER_PGD_PTRS-1,4,0
/* default: 767 entries */
.long 0x00102007
/* default: 255 entries */
.fill __KERNEL_PGD_PTRS-1,4,0
6) FASTCALL()
位置:Include\linux\kernel.h
定义:#define FASTCALL(x) x __attribute__((regparm(3)))
注释:这个标志符和函数声明放在一起,带regparm(3)的属性声明告诉gcc编译器这个函数可以通过寄存器传递多达3个的参数,这3个寄存器依次为EAX、EDX 和 ECX。更多的参数才通过堆栈传递。这样可以减少一些入栈出栈操作,因此调用比较快。
举例:extern void FASTCALL(__switch_to(struct task_struct *prev, struct t
ask_struct *next));
这个例子中,prev将通过eax,next通过edx传递
文章出处: