第一次看到这个宏的时候是在
__setup("root=", root_dev_setup);
这个宏是在内核挂载根文件系统的时候调用的
先看__setup的定义:
#define __setup(str, fn) __setup_param(str, fn, fn, 0)
然后是__setup_param的定义:
#define __setup_param(str, unique_id, fn, early) \
static char __setup_str_##unique_id[] __initdata = str; \
static struct obs_kernel_param __setup_##unique_id \
__attribute_used__ \
__attribute__((__section__(".init.setup"))) \
__attribute__((aligned((sizeof(long))))) \
= { __setup_str_##unique_id, fn, early }
我们把__setup("root=", root_dev_setup);展开来看:
__setup_param("root=", root_dev_setup, root_dev_setup, 0)
static char __setup_str_root_dev_setup[] __initdata = "root=";
static struct obs_kernel_param __setup_root_dev_setup \
__attribute_used__ \
__attribute__((__section__(".init.setup"))) \
__attribute__((aligned((sizeof(long))))) \
= { __setup_str_root_dev_setup, root_dev_setup, 0}
从结果看来这个宏到最后定义了两个东西,一个是char型的字符数组,里面的值是 "root".另外一个是定义了一个结构体对象,
这个结构体的类型是:
struct obs_kernel_param {
const char *str;
int (*setup_func)(char *);
int early;
};
所以第二个是在填充这个结构体,并且把他放在.init.setup段中
__setup的第二个参数是一个函数指针,返回值是int,参数是char *,用来填充上面结构体中的setup_func这个成员变量
联想给数据分段的作用就是为了把同类的数据放在一起便于内核使用和查找
①在do_early_param中被调用,但是这里的被调用必须要求early参数是1,所以__setup("root=", root_dev_setup);并不是在这个函数中
②在obsolete_checksetup中被调用,如果early被设置成0就会调用上面设置的函数