Linux kernel __init
,core_initcall
分析
下面内容都是以kernel 4.14版本分析;通常linux驱动定义为如下:
static int __init gpiolib_dev_init(void)
{
...
}
core_initcall(gpiolib_dev_init);
1. __init
分析
__init
是个宏,定义为 define __init __section(.init.text) __cold __inittrace __latent_entropy __noinitretpoline __nocfi
通常编译器把把代码放在.text
段,全局初始化的变量放在.data
段,全局未初始化的变量放在.bss
段。而使用session属性,连接器(vmlinux.lds)可以把需要的内容,放在指定的段中。
上面的__init
被放在.init.text
中,因此所有的_init
都放入到’.init.text’中,初始化完后就可以把该内存删除掉。
2. core_initcall
分析
路径为include/linux/init.h
#define pure_initcall(fn) __define_initcall(fn, 0)
#define core_initcall(fn) __define_initcall(fn, 1)
#define core_initcall_sync(fn) __define_initcall(fn, 1s)
#define postcore_initcall(fn) __define_initcall(fn, 2)
#define postcore_initcall_sync(fn) __define_initcall(fn, 2s)
#define arch_initcall(fn) __define_initcall(fn, 3)
#define arch_initcall_sync(fn) __define_initcall(fn, 3s)
#define subsys_initcall(fn) __define_initcall(fn, 4)
#define subsys_initcall_sync(fn) __define_initcall(fn, 4s)
#define fs_initcall(fn) __define_initcall(fn, 5)
#define fs_initcall_sync(fn) __define_initcall(fn, 5s)
#define rootfs_initcall(fn) __define_initcall(fn, rootfs)
#define device_initcall(fn) __define_initcall(fn, 6)
#define device_initcall_sync(fn) __define_initcall(fn, 6s)
#define late_initcall(fn) __define_initcall(fn, 7)
#define late_initcall_sync(fn) __define_initcall(fn, 7s)
#define __initcall_name(fn, id) __initcall_##fn##id
#define __define_initcall(fn, id) \
static initcall_t __initcall_name(fn, id) __used \
__attribute__((__section__(".initcall" #id ".init"))) = fn;
typedef int (*initcall_t)(void)
声明一个函数指针
core_initcall(gpiolib_dev_init) =
__define_initcall(gpiolib_dev_init, 1) =
static initcall_t __initcall_gpiolib_dev_init_1 __used __attribute__((__section__(.initcall.1.init))) = gpiolib_dev_init;
上面宏展开的意思为声明了一个函数__initcall_gpiolib_dev_init_1
,该函数指向了gpiolib_dev_init。同时__initcall_gpiolib_dev_init_1
是储存在__section__(.initcall.1.init)
,储存方式通过lds连接如下(查看out目录下的vmlinux.lds)
initcall_start = .;
KEEP(*(.initcallearly.init))
__initcall0_start = .;
KEEP(*(.initcall0.init)) KEEP(*(.initcall0s