linux模块编写

江枫思渺然 提交于 2019-11-28 04:05:52

一、linux模块化机制简介

      模块化的优势: linux内核是单内核结构,由于所有内容都集成在一起,效率很高,但可扩展性和可维护性相对较差,模块机制弥补这一缺陷。

      Linux模块可以通过静态或动态的方法加载到内核空间,静态加载是指在内核启动过程中加载;动态加载是指在内核运行的过程中随时加载。一个模块被加载到内核中时,就成为内核代码的一部分。模块加载入系统时,系统修改内核中的符号表,将新加载的模块提供的资源和符号添加到内核符号表中,以便模块间的通信。

     从代码的特征上来看,模块就是可以完成一个独立功能的一组函数的集合,但以特殊的方法来编译,从而使之可以在需要时随时安装,在不需要时随时卸载。它们扩展了操作系统内核功能却不需要重新编译内核、启动系统。

     

      Linux 内核模块主要由以下几个部分组成: 

      模块加载函数(必须):当通过insmod命令加载内核模块时,模块的加载函数会自动被内核执行,完成本模块相关初始化工作;
      模块卸载函数(必须):当通过rmmod命令卸载模块时,模块的卸载函数会自动被内核执行,完成与模块加载函数相反的功能;
      模块许可证声明(必须):模块许可证(LICENCE)声明描述内核模块的许可权限,如果不声明LICENCE,模块被加载时将收到内核被污染的警告。大多数        

      模块参数(可选):模块参数是模块被加载的时候可以被传递给他的值,它本身对应模块内部的全局变量;

      模块导出符号(可选):内核模块可以导出符号(symbol,对应于函数或变量),这样其他模块可以使用本模块中的变量或函数;
      模块作者等信息声明(可选)。

二、模块的内核描述

      每一个内核模块在内核中都对应一个数据结构module,所有的模块通过一个链表维护

      在线查看内核源码:https://elixir.bootlin.com

     

v2.6.28内核include/linux/module.hstruct module
{
    enum module_state state;              //模块状态,枚举类型的变量,可取的值为MODULE_STATE_LIVE、MODULE_STATE_COMING、MODULE_STATE_GOING,分为当前正常使用中(存活状态)、模块当前正在被加载和模块当前正在被卸载三种状态。

    /* Member of list of modules */
    struct list_head list;                //所有的模块构成双链表,包头为全局变量modules

    /* Unique handle for this module */
    char name[MODULE_NAME_LEN];           //模块名称,一般不包含.ko

    /* Sysfs stuff. */
    struct module_kobject mkobj;           
    struct module_attribute *modinfo_attrs;
    const char *version;
    const char *srcversion;
    struct kobject *holders_dir;

    /* Exported symbols */
    const struct kernel_symbol *syms;
    const unsigned long *crcs;
    unsigned int num_syms;

    /* GPL-only exported symbols. */
    unsigned int num_gpl_syms;
    const struct kernel_symbol *gpl_syms;
    const unsigned long *gpl_crcs;

#ifdef CONFIG_UNUSED_SYMBOLS
    /* unused exported symbols. */
    const struct kernel_symbol *unused_syms;
    const unsigned long *unused_crcs;
    unsigned int num_unused_syms;

    /* GPL-only, unused exported symbols. */
    unsigned int num_unused_gpl_syms;
    const struct kernel_symbol *unused_gpl_syms;
    const unsigned long *unused_gpl_crcs;
#endif

    /* symbols that will be GPL-only in the near future. */
    const struct kernel_symbol *gpl_future_syms;
    const unsigned long *gpl_future_crcs;
    unsigned int num_gpl_future_syms;

    /* Exception table */
    unsigned int num_exentries;
    struct exception_table_entry *extable;

    /* Startup function. */
    int (*init)(void);       //模块初始化函数指针

    /* If this is non-NULL, vfree after init() returns */
    void *module_init;       //如果该函数不为空,则init结束后就可以调用进行适当释放

    /* Here is the actual code + data, vfree'd on unload. */
    void *module_core;

    /* Here are the sizes of the init and core sections */
    unsigned int init_size, core_size;

    /* The size of the executable code in each section.  */
    unsigned int init_text_size, core_text_size;

    /* The handle returned from unwind_add_table. */
    void *unwind_info;

    /* Arch-specific module values */
    struct mod_arch_specific arch;

    unsigned int taints;    /* same bits as kernel:tainted */

#ifdef CONFIG_GENERIC_BUG
    /* Support for BUG */
    unsigned num_bugs;
    struct list_head bug_list;
    struct bug_entry *bug_table;
#endif

#ifdef CONFIG_KALLSYMS
    /* We keep the symbol and string tables for kallsyms. */
    Elf_Sym *symtab;
    unsigned int num_symtab;
    char *strtab;

    /* Section attributes */
    struct module_sect_attrs *sect_attrs;

    /* Notes attributes */
    struct module_notes_attrs *notes_attrs;
#endif

    /* Per-cpu data. */
    void *percpu;

    /* The command line arguments (may be mangled).  People like
       keeping pointers to this stuff */
    char *args;
#ifdef CONFIG_MARKERS
    struct marker *markers;
    unsigned int num_markers;
#endif
#ifdef CONFIG_TRACEPOINTS
    struct tracepoint *tracepoints;
    unsigned int num_tracepoints;
#endif

#ifdef CONFIG_MODULE_UNLOAD
    /* What modules depend on me? */
    struct list_head modules_which_use_me;

    /* Who is waiting for us to be unloaded */
    struct task_struct *waiter;

    /* Destruction function. */
    void (*exit)(void);

    /* Reference counts */
    struct module_ref ref[NR_CPUS];
#endif
};

 

三、实验

     hello模块

      ubuntu 请安装源代码 

sudo apt-get install linux-source

 

     centos安装

yum install kernel*

     hello.c

    

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>

static int __init init_hello(void)
{
        printk(KERN_ALERT "my first module test,output \"hello!\"\n");
        return 0;
}

static void __exit exit_hello(void)
{
        printk(KERN_DEBUG "bye bye test module!\n");
}
module_init(init_hello);
module_exit(exit_hello);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("xiaoan");
MODULE_VERSION("v0.1");
MODULE_DESCRIPTION("TEST FOR MODULE");

Makefile

  

obj-m := hello.o
KERNELBUILD :=/lib/modules/$(shell uname -r)/build
default:
        make -C $(KERNELBUILD) M=$(shell pwd) modules

 

执行make 即可

验证:

    

$ inmod ./hello.ko$ dmesg...  [ 2502.490509] my first module test,output "hello!"$ rmmod heelo.ko$ dmesg...   [ 2568.969806] bye bye test module!

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!