Linux内核-标识符

本文最后更新于:1 年前

内核驱动中的入口和出口函数:

1
2
3
4
5
6
7
8
static int __init hellowolrd_init(void) {
pr_info("Hello world!\n");
return 0;
}

static void __exit hellowolrd_exit(void) {
pr_info("End of the world\n");
}

​ 对于__init、__initdata和__exit、__exitdata的定义位于**<linux/init.h>**,这些宏定义的作用是告诉编译器将这些函数或者数据放入相应的section中,而在模块加载的阶段,.ko文件中的代码和数据的加载区域是根据section来加载的。

比如:如果函数的定义中带有__init,那么这个函数的所有代码会被放入.init.text的section中。

如果函数的定义中带有__initdata,那么这个函数的所有代码会被放入.init.data的section中。

之所以要使用这个宏定义,其中一个原因是标记为初始化的函数和数据,表明该函数和数据仅在初始化期间使用。在模块装载之后,模块装载就会将初始化函数扔掉。这样可以将该函数占用的内存释放出来。

这种释放根据是否编译进内核是有区别的:

​ (1)模块编译进内核:所有的初始化数据和函数都是在系统启动的最后阶段,在所有模块都初始化完成以后被内核统一释放的。所有你一般可以在内核启动信息的后面看到:

1
2
3
4
5
PHY: 0:01 - Link is Up - 100/Full
VFS: Mounted root (nfs filesystem) on device 0:14.
devtmpfs: mounted
Freeing init memory: 196K
INIT: version 2.86 booting

(2)独立的模块:模块是通过module-init-tool中的insmod的程序利用系统调用来挂载的,而所有的初始化数据和函数都是被这个系统调用所使用的,在模块挂载完成并初始化过后,由系统调用来完成对初始化数据和函数所占空间的释放。

对于将内核驱动代码中的函数和数据定义为“初始化”时需要注意:不要将驱动定义的文件方法(如 open、read、write、close)或者驱动在实际工作中需要使用的函数和数据定义为“初始化”属性,因为在驱动初始化后这些东东就已经被释放了,如果使用了就会Oops。