码迷,mamicode.com
首页 > 其他好文 > 详细

modules

时间:2015-12-09 17:13:21      阅读:136      评论:0      收藏:0      [点我收藏+]

标签:

内核模块可以使用两种方式加入进内核:
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");   

 

modules

标签:

原文地址:http://www.cnblogs.com/black-mamba/p/5032997.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!