linux内核经典宏定义,Linux内核常见宏定义
我们在阅读Linux内核是,常见到这些宏 __init, __initdata, __initfunc(),
asmlinkage, ENTRY(), FASTCALL()等等。它们定义在 /include/linux/init.h 和
/include/linux/linkage.h 以及其他一些.h 文件中。
1. __init
位置:/include/linux/init.h
定义: #define __init attribute ((section (".init.text")))
该标识符与函数声明并置使用,则表明编译器在构建程序时必须将此函数放置于.text.init字段中
中,而这个Section 在内核完成初始化之后,就会被释放掉。
举例:asmlinkage void __init star_kerne(void) { ... }
__init__标记用于表示内核启动时使用的初始化代码,在内核启动后将不再发挥作用,并且其修饰的内容应放置于.init.text字段中。
section中,#define __init __section(.init.text) __cold notrace
其典型用法如下:
static int __init xxx_drv_init(void)
{
return pci_register_driver(&xxx_driver);
}
根据上面的定义与用法,xxx_drv_init()函数将会被link到.init.text段。
之所以加入这样的宏,原因有2:
其中一部分内核初始化机制基于该kernel将负责实现启动所需的init函数,并将其划分为七个级别
别,core_initcall, postcore_initcall, arch_initcall, subsys_initcall,
fs_iitcall, device_initcall,
late_initcall。按照从高到低的顺序排列着这7个级别。具体而言,它们依次进行:首先是core_initcall……最后是late_initcall。
2).显著提升系统效率。初始化代码的核心特性在于其在启动过程中执行特定任务,并在任务完成之后立即释放内存资源以减少占用。
driver中的使用:
module_init,
由module_exit函数调用的一类函数应分别运用__init与__exit进行标记;而PCI Driver数据结构则无需做任何标记。
probe函数被标记为__devinit;当remove函数被标记为__devexit时,在pci_DRV结构中引用其返回值。
。
2. __initdata
位置:/include/linux/init.h
定义:#define __initdata attribute ((section
(".init.data")))
标识符与变量声明并列放置,在编译过程中意味着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
注释:__initfunc() 是一个自定义宏,用来定义一个 __init
函数,在Linux-2.4中已被__init宏所取代。
举例:__initfunc (void mem_init(unsigned long start_mem, unsigned
long end_mem)) { ... }
4. asmlinkage
位置:/include/linux/linkage.h
定义:#define asmlinkage CPP_ASMLINKAGE attribute((regparm(0)))
注释:这个符号和函数声明排列在一起,并且带regparm(0)的属性说明告诉编译器该函数无需使用寄存器传输参数
gcc编译器在汇编过程中调用c语言函数时传递参数有多种方式:其中一种是通过堆栈实现的。通常情况下,默认会采用寄存器进行参数传递。如果要在你的汇编程序中使用堆栈来传递参数,则需特别配置相应的接口或寄存器以支持这种数据传输方式。
在编写程序的过程中调用C语言函数,并希望使用堆栈来传递参数。所定义的C函数应在函数体开始前预先声明并使用该宏asmlinkage。
举例:asmlinkage void __init start_kernel(void) { ... }
5.ENTRY()
位置:/include/linux/linkage.h
定义:#define ENTRY(name) \
.globl name; \
ALIGN; \
name:
注释:将name 声明为全局,对齐,并定义为标号。
举例:
ENTRY(swapper_pg_dir)
6. FASTCALL ()
位置:/include/linux/kernel.h
定义:#define FASTCALL(x) x attribute((regparm(3)))
将该标志符与函数声明结合放置在一起,并在编译器中指定regparm(3)属性时会告知编译器该函数可通过寄存器传递最多三个参数(EAX、EDX等三个寄存器)
与 ECX 相关。只有当较多参数被传递时。从而降低了压栈弹出操作的数量。调用速度显著提高
举例:extern void FASTCALL(__switch_to(struct task_struct *prev,
struct task_struct *next))
这个例子中,prev将通过eax,next通过edx传递。
7. __sched
位置:/include/linux/sched.h
定义: #define __sched attribute((section(".sched.text")
