c语言中do函数,转载 关于do_initcalls函数的说明

本文详细介绍了Linux内核中do_initcalls函数的作用和工作原理,它是如何按照不同级别调用初始化函数的。do_initcalls遍历__initcall_start和__initcall_end之间的函数指针,执行系统初始化时所需的各种驱动和功能初始化。通过__initcall、module_init等宏定义,函数被放置在特定的节区内,便于在启动过程中按顺序调用。文章还探讨了连接器脚本和GCC扩展在这一过程中的作用。
摘要由CSDN通过智能技术生成

1.

在看linux核心代码的时候看到/init/main.c 里面的do_initcalls函数

static void(void){*call;for (call =; call

static void(fn){int=();,,;char[64];int;if () {("calling  %s/n", fn);=();}= fn();if () {=();=(,);("initcall %s", fn);(" returned %d after %Ld msecs/n",,(unsigned long long).tv64 >> 20);}[0] = 0;if (&&!= -&&)(, "error code %d ",);if (() !=) {(, "preemption imbalance ", sizeof());() =;}if (()) {(, "disabled interrupts ", sizeof());();}if ([0]) {("initcall %s", fn);(" returned with %s/n",);}}

__initcall_start是在 arch目录中的相关CPU中的vmlinux.lds文件指定,如i386中位于arch/i386/vmlinux.lds中,至于在 __initcall_start和__initcall_end之间的是由函数声明__init指定

2.

察看/arch/i386/vmlinux.lds,发现一段代码

__initcall_start = .;

.initcall.init : { *(.initcall.init) }

__initcall_end = .;

跟我找的东西相关

使用info ld,察看相关资料,(最终发现太麻烦,到网上找了一个ld.pdf).发现有这么一

段介绍关于c++地联结构造器的使用,和这段用法相同

其含义时,是让__initcall_start指向代码节.initcall.init的节首,而__initcall_end

指向.initcall.init的节尾。

那么第一段代码从程序逻辑上得到了解释。

3。因为do_initcalls所作的是系统中有关于选择的驱动部分的初始化工作,那么具体是这些

函数指针数据怎样放到了.initcall.init节。

想起来了,还没有使用grep哈哈,在

grep -rn .initcall.init *

发现在include/linux/init.h:83:有这样一个定义

#define __init_call   __attribute__ ((unused,__section__ (".initcall.init")))

娃哈哈哈

终于让我发现了

然后又发现了

#define __initcall(fn) /

static initcall_t __initcall_##fn __init_call = fn

4。问题是什么是__attribute__??,查找man gcc,找到关于__attribute__的定义

`section ("section-name")'

Normally, the compiler places the code it generates in the `text'

section. Sometimes, however, you need additional sections, or you

need certain particular functions to appear in special sections.

The `section' attribute specifies that a function lives in a

particular section. For example, the declaration:

extern void foobar (void) __attribute__ ((section ("bar")));

puts the function `foobar' in the `bar' section.

Some file formats do not support arbitrary sections so the

`section' attribute is not available on all platforms. If you

need to map the entire contents of a module to a particular

section, consider using the facilities of the linker instead.

他的意思就是使它建造一个在.initcall.init节的指向初始函数的指针

5。问题是##是什么意思?

查阅gcc的man page得知,她是用在可变参数使用宏定义的时候的

在这里也就是建立一个变量名称为所指向的函数的名称,并且前面加上

__initcall_.

6.然后看看成果

在/include/linux/init.c中有发现

#define module_init(x) __initcall(x);

看看很多驱动中都有类似

module_init(usb_init);

module_exit(usb_exit);

的代码,哈哈,这下明白了。

分析kernel的initcall函数

Author: Dongas

Data: 08-07-15

先来看看这些initcall函数的声明:

/* include/linux/init.h */

/* initcalls are now grouped by functionality into separate

* subsections. Ordering inside the subsections is determined

* by link order.

* For backwards compatibility, initcall() puts the call in

* the device init subsection.

*/

#define __define_initcall(level,fn) /

static initcall_t __initcall_##fn __attribute_used__ /

__attribute__((__section__(".initcall" level ".init"))) = fn

#define core_initcall(fn)        __define_initcall("1",fn)

#define postcore_initcall(fn)        __define_initcall("2",fn)

#define arch_initcall(fn)        __define_initcall("3",fn)

#define subsys_initcall(fn)            __define_initcall("4",fn)

#define fs_initcall(fn)                     __define_initcall("5",fn)

#define device_initcall(fn)           __define_initcall("6",fn)

#define late_initcall(fn)         __define_initcall("7",fn)

#define __initcall(fn) device_initcall(fn)

#define __exitcall(fn) /

static exitcall_t __exitcall_##fn __exit_call = fn

#define console_initcall(fn) /

static initcall_t __initcall_##fn /

__attribute_used__ __attribute__((__section__(".con_initcall.init")))=fn

#define security_initcall(fn) /

static initcall_t __initcall_##fn /

__attribute_used__ __attribute__((__section__(".security_initcall.init"))) = fn

#define module_init(x)   __initcall(x);    ß从这里知道module_init的等级为6,相对靠后

#define module_exit(x)  __exitcall(x);

可以发现这些*_initcall(fn)最终都是通过__define_initcall(level,fn)宏定义生成的。

__define_initcall宏定义如下:

#define __define_initcall(level,fn) /

static initcall_t __initcall_##fn __attribute_used__ /

__attribute__((__section__(".initcall" level ".init"))) = fn

这句话的意思为定义一个initcall_t型的初始化函数,函数存放在.initcall”level”.init section内。.initcall”level”.init section定义在vmlinux.lds内。

/* arch/arm/kernel/vmlinux.lds */

……

__initcall_start = .;

*(.initcall1.init)

*(.initcall2.init)

*(.initcall3.init)

*(.initcall4.init)

*(.initcall5.init)

*(.initcall6.init)

*(.initcall7.init)

__initcall_end = .;

……

正好包括了上面init.h里定义的从core_initcall到late_initcall等7个level等级的.initcall”level”.init section. 因此通过不同的*_initcall声明的函数指针最终都会存放不同level等级的.initcall”level”.init section内。这些不同level的section按level等级高低依次存放。

下面我们再来看看,内核是什么时候调用存储在.initcall”level”.init section内的函数的。

内核是通过do_initcalls函数循环调用执行initcall.init section内的函数的,流程如下:

start_kernel -> rest_init -> kernel_thread -> init -> do_basic_setup -> do_initcalls

这里要分析两个函数: kernel_thread和do_initcalls,这两个函数都定义在init/main.c内

1)    kernel_thre

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值