• modules


    内核模块可以使用两种方式加入进内核:
    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
    ");                                                 
                                             
        return 0;                                     
    }                                                               
     
    void test_exit(void)                                        
    {                                          
        printk("test test exit
    ");        
    }                    
                             
    module_init(test_init);                               
    module_exit(test_exit);
                                           
                           
    MODULE_LICENSE("GPL");
    MODULE_AUTHOR("frank");
    MODULE_VERSION("1.0");   
  • 相关阅读:
    优麒麟(UbuntuKylin)不是国产Linux操作系统
    中间件
    RapeLay(电车之狼R)的结局介绍 (隐藏结局攻略)
    HDU 4284 状压dp+spfa
    素数推断算法(高效率)
    【iOS开发-60】案例学习:多组数据的tableView设置、添加右側组索引、多层数据模型设置以及valueForKeyPath
    理解class.forName()
    Oracle经典查询案例
    Java抓取网页数据(原网页+Javascript返回数据)
    破解windows下MySQL服务启动不了的情况下不能对其进行全然卸载的解决方式
  • 原文地址:https://www.cnblogs.com/black-mamba/p/5032997.html
Copyright © 2020-2023  润新知