实际上是存在于include/linux/init.h文件中的宏定义
#define __init __section(.init.text)
#define __exit __section(.exit.text)
__init关键字是与链接器相关的,它可以告诉链接器如linux下的ld,将代码放在内核对象文件中的专用部分(事先约定好的部分)。它在模块加载和init函数执行后被释放。(当然这个例子只是用于模块编译进内核的情况)
可执行可链接格式的目标文件,由不同的命名部分组成,其中一些部分是必须的,它们成为ELF标准的基础。
但也可以根据自己的需要构建任意一部分,用来给程序使用,内核就是利用了这一点。
使用objdump打印出内核模块module.ko的不同组成部分:
.text:包含程序代码,也称为代码
.data:包含初始化数据,也称为数据段
.rodata:用于只读数据
.comment:存储注释
.bss:由符号开始的块,未初始化的数据段, block started by symbol
这里比较重要的是:
.modeinfo:存储有关模块的信息
.init.text:存储以__init宏为前缀的代码
链接器负责将符号(包括了代码和数据等)放到生成的二进制文件中的适当的部分,程序执行时会被加载器处理。
二进制文件中的这些部分可以自定义,更改他们的默认位置。
链接器还有一种机制,你可以向他提供链接器脚本(链接器定义文件LDF或者链接器定义脚本LDS),来添加其他部分。
Linux内核提供了一个自定义LDS文件,它位于arch/ /kernel/vmlinux.lds.S中。对于要放置在内核LDS文件所映射的专用部分中的符号,使用__init和__exit进行标记。
总之,__init和__exit是Linux指令(实际上是宏),它们使用C编译器属性指定符号的位置。这些指令指示编译器将以它们为前缀的代码分别放在.init.text和.exit.text部分,虽然内核可以访问不同的对象部分