在Linux内核源码中多处会看到诸如__init,__initdata,__exitdata的关键字,
大部分这样的关键字定义在include/linux/init.h头文件中,它们都会在编译连接阶段被实现处理。
#define __init __section(.init.text) __cold notrace __init标记的数据被存储在.init.text节
#define __initdata __section(.init.data) __initdata标记的数据被存储在.init.data节
#define __initconst __section(.init.rodata) __initconst标记的数据被存储在.init.rodata节
#define __exitdata __section(.exit.data) __exitdata标记的数据被存储在.exit.data节
#define __exit_call __used __section(.exitcall.exit) __exit__call__used标记的数据被存储在.exitcall.exit节
我们也经常看到许多诸如subsystem_initcall(fn)的语句,fn为某个函数的名称,也可以在init.h中找到它的踪影。
#define __define_initcall(level,fn,id) \
static initcall_t __initcall_##fn##id __used \
__attribute__((__section__(".initcall" level ".init"))) = fn
#define early_initcall(fn) __define_initcall("early",fn,early)
#define pure_initcall(fn) __define_initcall("0",fn,0)
#define core_initcall(fn) __define_initcall("1",fn,1)
#define subsys_initcall(fn) __define_initcall("4",fn,4)
#define core_initcall_sync(fn) __define_initcall("1s",fn,1s)
......
#define late_initcall_sync(fn) __define_initcall("7s",fn,7s)
#define __initcall(fn) device_initcall(fn)
#define __exitcall(fn) \
static exitcall_t __exitcall_##fn __exit_call = fn
可以看出每个与__define_initcall相关的注册函数都被解释为 :
static initcall_t __initcall_fn_id, 入口地址将被存储在.initcall"level".init节中。
我们常在Linux模块中用到的module_init和module_exit的真身也可以看到:
#define module_init(x) __initcall(x);
#define module_exit(x) __exitcall(x);
init.h中还有一些代码设计boot与kernel的参数交换例如:
#define __setup_param(str, unique_id, fn, early) \
static const char __setup_str_##unique_id[] __initconst \
__aligned(1) = str; \
static struct obs_kernel_param __setup_##unique_id \
__used __section(.init.setup) \
__attribute__((aligned((sizeof(long))))) \
= { __setup_str_##unique_id, fn, early }
#define __setup(str, fn) \
__setup_param(str, fn, fn, 0)
/* NOTE: fn is as per module_param, not __setup! Emits warning if fn
* returns non-zero. */
#define early_param(str, fn) \
__setup_param(str, fn, fn, 1)
/* Relies on boot_command_line being set */
void __init parse_early_param(void);
void __init parse_early_options(char *cmdline);
我们经常用到的early_param,__setup用于处理boot传递过来的参数