全部博文(685)
分类: 嵌入式
2014-08-19 17:17:07
内核又是如何调用到这些__init修饰的初始化函数?要回答这个问题,还需要回顾一下subsys_initcall宏,它也在include/linux/init.h里定义
125 #define subsys_initcall(fn) __define_initcall("4",fn,4)
这里又出现了一个宏__define_initcall,它用于将指定的函数指针fn放到initcall.init节里 而对于具体的subsys_initcall宏,则是把fn放到.initcall.init的子节.initcall4.init里。要弄清楚.initcall.init、.init.text和.initcall4.init这样的东东,我们还需要了解一点内核可执行文件相关的概念。
内核可执行文件由许多链接在一起的对象文件组成。对象文件有许多节,如文本、数据、init数据、bass等等。这些对象文件都是__________由一个称为链接器 脚本的文件链接并装入的。这个链接器脚本的功能是将输入对象文件的各节映射到输出文件中;换句话说,它将所有输入对象文件都链接到单一的可执行文件中,将 该可执行文件的各节装入到指定地址处。 vmlinux.lds是存在于arch// 目录中的内核链接器脚本,它负责链接内核的各个节并将它们装入中特定偏移量处。
我可以负责任的告诉你,要看懂vmlinux.lds这个文件是需要一番功夫的,不过大家都是聪明人,聪明人做聪明事,所以你需要做的只是搜索initcall.init,然后便会看到似曾相识的内容
这里的__initcall_start指向.initcall.init节的开始,__initcall_end指向它的结尾。而.initcall.init节又被分为了7个子节,分别是
我们的subsys_initcall宏便是将指定的函数指针放在了.initcall4.init子节。其它的比如core_initcall将函数指针放在.initcall1.init子节,device_initcall将函数指针放在了.initcall6.init子节等等,都可以从 include/linux/init.h文件找到它们的定义。各个字节的顺序是确定的,即先调用.initcall1.init中的函数指针再调 用.initcall2.init中的函数指针,等等。__init修饰的初始化函数在内核初始化过程中调用的顺序和.initcall.init节里函 数指针的顺序有关,不同的初始化函数被放在不同的子节中,因此也就决定了它们的调用顺序。
至于实际执行函数调用的地方,就在/init/main.c文件里,内核的初始化么,不在那里还能在哪里,里面的do_initcalls函数会直接用到这里的__initcall_start、__initcall_end来进行判断。