Linux 的module_init运行加载

Linux 的module_init运行加载

段说明

text段

代码段,通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定。

data段

数据段,通常是指用来存放程序中已初始化的全局变量的一块内存区域。数据段属于静态内存分配。

bss段

通常是指用来存放程序中未初始化的全局变量和静态变量的一块内存区域。BSS段属于静态内存分配。

init段

linux定义的一种初始化过程中才会用到的段,一旦初始化完成,那么这些段所占用的内存会被释放掉,

kernel启动过程中打印的内存相关信息

[    0.000000] Memory: 416732K/521952K available (9216K kernel code, 432K rwdata, 2280K rodata, 1024K init, 943K bss, 23300K reserved, 81920K cma-reserved, 0K highmem)
[    0.000000] Virtual kernel memory layout:
[    0.000000]     vector  : 0xffff0000 - 0xffff1000   (   4 kB)
[    0.000000]     fixmap  : 0xffc00000 - 0xfff00000   (3072 kB)
[    0.000000]     vmalloc : 0xd0800000 - 0xff800000   ( 752 MB)
[    0.000000]     lowmem  : 0xb0000000 - 0xd0000000   ( 512 MB)
[    0.000000]     pkmap   : 0xafe00000 - 0xb0000000   (   2 MB)
[    0.000000]     modules : 0xaf000000 - 0xafe00000   (  14 MB)
[    0.000000]       .text : 0x(ptrval) - 0x(ptrval)   (10208 kB)
[    0.000000]       .init : 0x(ptrval) - 0x(ptrval)   (1024 kB)
[    0.000000]       .data : 0x(ptrval) - 0x(ptrval)   ( 433 kB)
[    0.000000]        .bss : 0x(ptrval) - 0x(ptrval)   ( 944 kB)

我们可以在vmlinux.lds中看到init.data的断包含了.initcallearly.init之类,这个就是我们上面通过宏定义定义的函数___define_initcall

 .init.data : AT(ADDR(.init.data) - 0) { KEEP(*(SORT(___kentry+*))) *(.init.data init.data.*) *(.meminit.data*) *(.init.rodata .init.rodata.*) *(.meminit.rodata) . = ALIGN(8); __clk_of_table = .; KEEP(*(__clk_of_table)) KEEP(*(__clk_of_table_end)) . = ALIGN(8); __reservedmem_of_table = .; KEEP(*(__reservedmem_of_table)) KEEP(*(__reservedmem_of_table_end)) . = ALIGN(8); __timer_of_table = .; KEEP(*(__timer_of_table)) KEEP(*(__timer_of_table_end)) . = ALIGN(8); __cpu_method_of_table = .; KEEP(*(__cpu_method_of_table)) KEEP(*(__cpu_method_of_table_end)) . = ALIGN(8); __cpuidle_method_of_table = .; KEEP(*(__cpuidle_method_of_table)) KEEP(*(__cpuidle_method_of_table_end)) . = ALIGN(32); __dtb_start = .; KEEP(*(.dtb.init.rodata)) __dtb_end = .; . = ALIGN(8); __irqchip_of_table = .; KEEP(*(__irqchip_of_table)) KEEP(*(__irqchip_of_table_end)) . = ALIGN(8); __earlycon_table = .; KEEP(*(__earlycon_table)) __earlycon_table_end = .; . = ALIGN(16); __setup_start = .; KEEP(*(.init.setup)) __setup_end = .; __initcall_start = .; KEEP(*(.initcallearly.init)) __initcall0_start = .; KEEP(*(.initcall0.init)) __initcall0s_start = .; KEEP(*(.initcall0s.init)) __initcall1_start = .; KEEP(*(.initcall1.init)) __initcall1s_start = .; KEEP(*(.initcall1s.init)) __initcall2_start = .; KEEP(*(.initcall2.init)) __initcall2s_start = .; KEEP(*(.initcall2s.init)) __initcall3_start = .; KEEP(*(.initcall3.init)) __initcall3s_start = .; KEEP(*(.initcall3s.init)) __initcall4_start = .; KEEP(*(.initcall4.init)) __initcall4s_start = .; KEEP(*(.initcall4s.init)) __initcall5_start = .; KEEP(*(.initcall5.init)) __initcall5s_start = .; KEEP(*(.initcall5s.init)) __initcallrootfs_start = .; KEEP(*(.initcallrootfs.init)) __initcallrootfss_start = .; KEEP(*(.initcallrootfss.init)) __initcall6_start = .; KEEP(*(.initcall6.init)) __initcall6s_start = .; KEEP(*(.initcall6s.init)) __initcall7_start = .; KEEP(*(.initcall7.init)) __initcall7s_start = .; KEEP(*(.initcall7s.init)) __initcall_end = .; __con_initcall_start = .; KEEP(*(.con_initcall.init)) __con_initcall_end = .; __security_initcall_start = .; KEEP(*(.security_initcall.init)) __security_initcall_end = .; . = ALIGN(4); __initramfs_start = .; KEEP(*(.init.ramfs)) . = ALIGN(8); KEEP(*(.init.ramfs.info)) }
 .exit.data : {
  *(.exit.data .exit.data.*) *(.fini_array .fini_array.*) *(.dtors .dtors.*) *(.memexit.data*) *(.memexit.rodata*)
 }

通过System.map中可以看到,定义了__initcall_start 函数入口地址

b0d4dc48 T __initcall_start
b0d4dc48 T __setup_end
b0d4dc4c t __initcall_init_static_idmapearly
b0d4dc50 t __initcall_spawn_ksoftirqdearly
b0d4dc54 t __initcall_migration_initearly
b0d4dc58 t __initcall_check_cpu_stall_initearly
b0d4dc5c t __initcall_srcu_bootup_announceearly
b0d4dc60 t __initcall_rcu_spawn_gp_kthreadearly
b0d4dc64 t __initcall_cpu_stop_initearly
b0d4dc68 t __initcall_jump_label_init_moduleearly
b0d4dc6c t __initcall_dummy_timer_registerearly
b0d4dc70 t __initcall_initialize_ptr_randomearly
b0d4dc74 T __initcall0_start

module_init的宏定义

#define module_init(x)	__initcall(x);
    -->#define __initcall(fn) device_initcall(fn)
    	-->#define device_initcall(fn)		__define_initcall(fn, 6)
    		-->#define __define_initcall(fn, id) ___define_initcall(fn, id, .initcall##id)
    			-->  #define ___define_initcall(fn, id, __sec) \
						static initcall_t __initcall_##fn##id __used \
						__attribute__((__section__(#__sec ".init"))) = fn; \
    					typedef int (*initcall_t)(void); initcall_t是个函数指针

内核的init加载函数

 // Only for built-in code, not modules.
/*
 * A "pure" initcall has no dependencies on anything else, and purely
 * initializes variables that couldn't be statically initialized.
 *
 * This only exists for built-in code, not for modules.
 * Keep main.c:initcall_level_names[] in sync.
 */
#define early_initcall(fn)		__define_initcall(fn, early)
#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 console_initcall(fn)	___define_initcall(fn, con, .con_initcall)
#define security_initcall(fn)	___define_initcall(fn, security, .security_initcall)
//外部定义了__initcall_start相关参数,在System.map当中可以找到__initcall_start的地址
extern initcall_entry_t __initcall_start[];
extern initcall_entry_t __initcall0_start[];
extern initcall_entry_t __initcall1_start[];
extern initcall_entry_t __initcall2_start[];
extern initcall_entry_t __initcall3_start[];
extern initcall_entry_t __initcall4_start[];
extern initcall_entry_t __initcall5_start[];
extern initcall_entry_t __initcall6_start[];
extern initcall_entry_t __initcall7_start[];
extern initcall_entry_t __initcall_end[];

static initcall_entry_t *initcall_levels[] __initdata = {
	__initcall0_start,
	__initcall1_start,
	__initcall2_start,
	__initcall3_start,
	__initcall4_start,
	__initcall5_start,
	__initcall6_start,
	__initcall7_start,
	__initcall_end,
};
static char *initcall_level_names[] __initdata = {
	"pure",
	"core",
	"postcore",
	"arch",
	"subsys",
	"fs",
	"device",
	"late",
};

do_basic_setup
    -->do_initcalls
    	-->	for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++) \  initcall_levels是上面的函数指针数组的大小
				do_initcall_level(level);
			-->	for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++) \
					do_one_initcall(initcall_from_entry(fn)); initcall_from_entry--> *fn
				-->ret = fn();
do_one_initcall时,实际上就是取函数的地址,可以追踪到System.map中__initcall0_start,在上述已经列出

根据dump_stack()追踪驱动的的加载流程,我们可以看出跟我们跟踪的代码是一致的,执行do_one_initcall后,执行了gpioctl_driver_init,,符合流程

[    2.041595] CPU: 1 PID: 1 Comm: swapper/0 Not tainted 4.19.111 #1074
[    2.041661] Hardware name: Generic DT based system
[    2.041711] [<b010f408>] (unwind_backtrace) from [<b010b96c>] (show_stack+0x10/0x14)
[    2.041753] [<b010b96c>] (show_stack) from [<b098cc44>] (dump_stack+0x90/0xa4)
[    2.041794] [<b098cc44>] (dump_stack) from [<b0d23654>] (gpioctl_driver_init+0x8/0x34)
[    2.041830] [<b0d23654>] (gpioctl_driver_init) from [<b010265c>] (do_one_initcall+0x54/0x194)
[    2.041866] [<b010265c>] (do_one_initcall) from [<b0d00edc>] (kernel_init_freeable+0x144/0x1dc)
[    2.041900] [<b0d00edc>] (kernel_init_freeable) from [<b09a1524>] (kernel_init+0x8/0x110)
[    2.041932] [<b09a1524>] (kernel_init) from [<b01010d8>] (ret_from_fork+0x14/0x3c)
[    2.041948] Exception stack(0xcec75fb0 to 0xcec75ff8)
[    2.041971] 5fa0:                                     00000000 00000000 00000000 00000000
[    2.041998] 5fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[    2.042024] 5fe0: 00000000 00000000 00000000 00000000 00000013 00000000
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值