linux模块编写
Posted Linux_xl
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux模块编写相关的知识,希望对你有一定的参考价值。
一、linux模块化机制简介
模块化的优势: linux内核是单内核结构,由于所有内容都集成在一起,效率很高,但可扩展性和可维护性相对较差,模块机制弥补这一缺陷。
Linux模块可以通过静态或动态的方法加载到内核空间,静态加载是指在内核启动过程中加载;动态加载是指在内核运行的过程中随时加载。一个模块被加载到内核中时,就成为内核代码的一部分。模块加载入系统时,系统修改内核中的符号表,将新加载的模块提供的资源和符号添加到内核符号表中,以便模块间的通信。
从代码的特征上来看,模块就是可以完成一个独立功能的一组函数的集合,但以特殊的方法来编译,从而使之可以在需要时随时安装,在不需要时随时卸载。它们扩展了操作系统内核功能却不需要重新编译内核、启动系统。
Linux 内核模块主要由以下几个部分组成:
模块加载函数(必须):当通过insmod命令加载内核模块时,模块的加载函数会自动被内核执行,完成本模块相关初始化工作;
模块卸载函数(必须):当通过rmmod命令卸载模块时,模块的卸载函数会自动被内核执行,完成与模块加载函数相反的功能;
模块许可证声明(必须):模块许可证(LICENCE)声明描述内核模块的许可权限,如果不声明LICENCE,模块被加载时将收到内核被污染的警告。大多数
模块参数(可选):模块参数是模块被加载的时候可以被传递给他的值,它本身对应模块内部的全局变量;
模块导出符号(可选):内核模块可以导出符号(symbol,对应于函数或变量),这样其他模块可以使用本模块中的变量或函数;
模块作者等信息声明(可选)。
二、模块的内核描述
每一个内核模块在内核中都对应一个数据结构module,所有的模块通过一个链表维护
在线查看内核源码:https://elixir.bootlin.com
v2.6.28内核
include/linux/module.h
struct 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!
以上是关于linux模块编写的主要内容,如果未能解决你的问题,请参考以下文章