前言
阅读 Linux
驱动源码时,我们发现驱动的 初始化函数
和 逆初始化函数
总会被一个宏
进行修饰,这个宏就决定了驱动在启动时的那个阶段执行。
示例1:
#define __init \
__section(".init.text") \
__cold __latent_entropy __noinitretpoline __nocfi
#define __exit __section(".exit.text") __exitused __cold notrace
#define module_init(x) __initcall(x);
#define module_exit(x) __exitcall(x);
示例2:
#define module_platform_driver(__platform_driver) \
module_driver(__platform_driver, platform_driver_register, \
platform_driver_unregister)
// Expands to
static int __attribute__((__section__(".init.text"))) __attribute__((__cold__))
__attribute__((__no_sanitize__("cfi")))
rockchip_canfd_driver_init(void)
{
return __platform_driver_register(&(rockchip_canfd_driver),
((struct module *)0));
}
static void *__attribute__((__section__(".discard.addressable")))
__attribute__((
__used__)) __UNIQUE_ID___addressable_rockchip_canfd_driver_init13 =
(void *)&rockchip_canfd_driver_init;
asm(".section \""
".initcall6"
".init"
"\", \"a\" \n"
"__initcall__kmod_Space__12_1222_rockchip_canfd_driver_init6"
": \n"
".long "
"rockchip_canfd_driver_init"
" - . \n"
".previous \n");
;
;
static void __attribute__((__section__(".exit.text"))) __attribute__((__used__))
__attribute__((__cold__)) __attribute__((patchable_function_entry(0, 0)))
rockchip_canfd_driver_exit(void)
{
platform_driver_unregister(&(rockchip_canfd_driver));
}
static exitcall_t __exitcall_rockchip_canfd_driver_exit
__attribute__((__used__))
__attribute__((__section__(".exitcall.exit"))) =
rockchip_canfd_driver_exit;
;
这段代码是 Linux 内核模块加载和卸载机制的一部分。它使用了一些宏和属性来确保模块在特定的阶段被正确加载和卸载。让我们逐步解析这段代码:
#define module_platform_driver(__platform_driver) \
module_driver(__platform_driver, platform_driver_register, \
platform_driver_unregister)
这个宏定义了 module_platform_driver
,它实际上调用了 module_driver
宏,传入了平台驱动的注册和注销函数。该宏扩展后的代码:
static int __attribute__((__section__(".init.text"))) __attribute__((__cold__))
__attribute__((__no_sanitize__("cfi")))
rockchip_canfd_driver_init(void)
{
return __platform_driver_register(&(rockchip_canfd_driver),
((struct module *)0));
}
__attribute__((__section__(".init.text")))
:将函数放置在.init.text
段中。这个段的内容在模块加载后会被释放,以节省内存。__attribute__((__cold__))
:指示编译器优化器这个函数很少被调用。__attribute__((__no_sanitize__("cfi")))
:禁用控制流完整性(CFI)检查。rockchip_canfd_driver_init
:模块初始化函数,调用platform_driver_register
注册平台驱动。
static void *__attribute__((__section__(".discard.addressable")))
__attribute__((
__used__)) __UNIQUE_ID___addressable_rockchip_canfd_driver_init13 =
(void *)&rockchip_canfd_driver_init;
__attribute__((__section__(".discard.addressable")))
:将变量放置在.discard.addressable
段中。这个段的内容在模块加载后会被丢弃。__attribute__((__used__))
:确保编译器不会优化掉这个变量。__UNIQUE_ID___addressable_rockchip_canfd_driver_init13
:一个唯一的变量名,用于防止符号冲突。
asm(".section \""
".initcall6"
".init"
"\", \"a\" \n"
"__initcall__kmod_Space__12_1222_rockchip_canfd_driver_init6"
": \n"
".long "
"rockchip_canfd_driver_init"
" - . \n"
".previous \n");
asm
:内联汇编代码,用于在.initcall6.init
段中插入一个初始化调用。.section ".initcall6.init", "a"
:创建或切换到.initcall6.init
段。__initcall__kmod_Space__12_1222_rockchip_canfd_driver_init6
:一个唯一的标签名。.long rockchip_canfd_driver_init - .
:插入初始化函数的地址。.previous
:返回到前一个段。
static void __attribute__((__section__(".exit.text"))) __attribute__((__used__))
__attribute__((__cold__)) __attribute__((patchable_function_entry(0, 0)))
rockchip_canfd_driver_exit(void)
{
platform_driver_unregister(&(rockchip_canfd_driver));
}
__attribute__((__section__(".exit.text")))
:将函数放置在.exit.text
段中。这个段的内容在模块卸载时会被调用。__attribute__((__used__))
:确保编译器不会优化掉这个函数。__attribute__((__cold__))
:指示编译器优化器这个函数很少被调用。__attribute__((patchable_function_entry(0, 0)))
:允许在运行时修改这个函数的入口点。rockchip_canfd_driver_exit
:模块卸载函数,调用platform_driver_unregister
注销平台驱动。
static exitcall_t __exitcall_rockchip_canfd_driver_exit
__attribute__((__used__))
__attribute__((__section__(".exitcall.exit"))) =
rockchip_canfd_driver_exit;
exitcall_t
:通常是一个函数指针类型。__attribute__((__used__))
:确保编译器不会优化掉这个变量。__attribute__((__section__(".exitcall.exit")))
:将变量放置在.exitcall.exit
段中,这个段的内容在模块卸载时会被调用。__exitcall_rockchip_canfd_driver_exit
:一个变量,其值为rockchip_canfd_driver_exit
函数的地址。
这段代码的主要功能是:
- 注册平台驱动:在模块加载时,
rockchip_canfd_driver_init
函数会被调用,注册rockchip_canfd_driver
。 - 注销平台驱动:在模块卸载时,
rockchip_canfd_driver_exit
函数会被调用,注销rockchip_canfd_driver
。 - 段管理:使用各种段属性和内联汇编,确保初始化和卸载代码在适当的时间被调用,并且不会占用不必要的内存。
通过这些机制,Linux 内核模块可以优雅地管理和加载/卸载平台驱动程序。
上述提及的宏都定义在include/linux/init.h
文件中,接下来我们一块学习下这个文件的内容。
一、include/linux/init.h
1. __initxx宏
#define __init __section(".init.text") __cold __laten