您的位置:首页 > 其它

modules

2015-12-09 15:32 169 查看
内核模块可以使用两种方式加入进内核:
1.使用insmod等命令动态加载到内核(obj-m);
2.作为内核的一部分静态编译进内核(obj-y);

在linux/init.h文件中

typedef int (*initcall_t)(void);

typedef void (*exitcall_t)(void);

#ifndef MODULE

//静态方式

#define __define_initcall(level,fn,id) \

static initcall_t __initcall_##fn##id __used \

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

//最终展开为:
//static initcall_t __initcall_test_init6 __used __attribute__((__section__(".initcall"6".init"))) = test_init

//即将初始化函数test_init的地址放在了.initcall6.init的section,内核在启动的时候按级别顺序调用__initcall_start处的函数
//start_kernel()->rest_init()->kernel_init()->do_basic_setup()->do_initcalls()

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

#define __initcall(fn) device_initcall(fn)

#define module_init(x) __initcall(x);

#define __exitcall(fn) \

static exitcall_t __exitcall_##fn __exit_call = fn

//module_exit在静态编译的时候没有意义,因为静态编译的驱动无法卸载

#define module_exit(x) __exitcall(x);

#else

//动态方式

#define module_init(initfn) \

static inline initcall_t __inittest(void) \ //检查初始化函数的格式是否满足initcall_t类型,当函数格式不匹配时,编译会warnning

{ return initfn; } \

int init_module(void) __attribute__((alias(#initfn)));
//为init_module函数定义一个别名,即初始化函数的名字。
//insmod时候,在系统内部会调用sys_init_module()去找到init_module函数的入口地址
  //用objdump -t xxx.ko 命令可以看出test_init函数名的地址与init_module函数的地址相同。



//module_exit函数的作用也是检查函数格式和定义别名。
#define module_exit(exitfn) \

static inline exitcall_t __exittest(void) \

{ return exitfn; } \

void cleanup_module(void) __attribute__((alias(#exitfn)));

linux/arch/arm/kernel/vmlinux.lds
.init.data : {

*(.init.data) *(.meminit.data) *(.init.rodata) . = ALIGN(8); __start_ftrace_events = .; *(_ftrace_events) __stop_ftrace_events = .; *(.meminit.rodata) . = ALIGN(3 2); __dtb_start = .; *(.dtb.init.rodata) __dtb_end = .;

. = ALIGN(16); __setup_start = .; *(.init.setup) __setup_end = .;

__initcall_start = .; *(.initcallearly.init) __initcall0_start = .; *(.initcall0.init) *(.initcall0s.init) __initcall1_start = .; *(.initcall1.init) *(.initcall1s .init) __initcall2_start = .; *(.initcall2.init) *(.initcall2s.init) __initcall3_start = .; *(.initcall3.init) *(.initcall3s.init) __initcall4_start = .; *(.initcal l4.init) *(.initcall4s.init) __initcall5_start = .; *(.initcall5.init) *(.initcall5s.init) __initcallrootfs_start = .; *(.initcallrootfs.init) *(.initcallrootfss.in it) __initcall6_start = .; *(.initcall6.init) *(.initcall6s.init) __initcall7_start = .; *(.initcall7.init) *(.initcall7s.init) __initcall_end = .;

__con_initcall_start = .; *(.con_initcall.init) __con_initcall_end = .;

__security_initcall_start = .; *(.security_initcall.init) __security_initcall_end = .;

. = ALIGN(4); __initramfs_start = .; *(.init.ramfs) . = ALIGN(8); *(.init.ramfs.info)

}

示例代码:

#include <linux/module.h>

int test_init(void)
{
printk("test test init\n");

return 0;
}

void test_exit(void)
{
printk("test test exit\n");
}

module_init(test_init);
module_exit(test_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("frank");
MODULE_VERSION("1.0");
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: