• 编写一个简单的Linux内核模块


    为了在运行时动态增加和删除某个功能,Linux内核引入了内核模块这一机制,可在内核运行时加载一组目标代码来实现某个特定的功能,这样在实际使用Linux的过程中就不需要重新编译内核代码来实现动态扩展。

    为了深入Linux内核的学习,我们从编写一个简单的Linux内核模块开始。

    helloworld.c

    创建一个名为helloworld.c的文件,内容如下:

    1. #include <linux/init.h>
    2. #include <linux/module.h>
    3. static int __init hello_init(void)
    4. {
    5. printk(KERN_INFO "hello world enter\n");
    6. return 0;
    7. }
    8. module_init(hello_init);
    9. static void __exit hello_exit(void)
    10. {
    11. printk(KERN_INFO "hello world exit\n");
    12. }
    13. module_exit(hello_exit);
    14. MODULE_AUTHOR("fukaiqiang");//作者
    15. MODULE_LICENSE("GPL v2");//模块许可证声明,一般用GPL v2
    16. MODULE_DESCRIPTION("A simple hello world module");//模块描述
    17. MODULE_ALIAS("hw"); //别名
    • 这个简单的内核模块只有两个函数,一个是hello_init,一个是hello_exit。
    • 头文件有两个,分别是init.h和module.h,它们分别对应内核源代码中的 include/linux/init.h 文件和 include/linux/module.h 文件,其中module_init和module_exit是在init.h中,MODULE_AUTHOR等宏是在module.h中。
    • module_init告诉内核这是该模块的入口。
    • module_exit告诉内核这是该模块的退出函数。
    • 函数hello_init和hello_exit都只利用printk往终端输出一句话。printk函数类似C语言中的printf函数,只是增加了输出级别的支持。
    • MODULE_AUTHOR描述作者信息,MODULE_LICENSE描述软件许可协议。MODULE_DESCRIPTION描述该模块的用途或功能。MODULE_ALIAS描述模块的别名。
    • Linux内核是一个使用了GPLv2许可证的开源项目,这要求所有使用和修改Linux源代码的个人或公司都有义务把修改后的源代码公开,GPL是一个强制性的开源协议,因此我们编写的驱动代码中需要显示地声明和遵循这个协议。

    Makefile

    1. KVERS = $(shell uname -r)
    2. obj-m := helloworld.o
    3. all:
    4. make -C /lib/modules/$(KVERS)/build M=$(PWD) modules
    5. clean:
    6. make -C /lib/modules/$(KVERS)/build M=$(PWD) clean
    7. rm -rf *.ko;
    1. $make
    2. make -C /lib/modules/4.15.0-142-generic/build M=/media/fukaiqiang/Disk960/Codes/kernel/hello_world
    3. make[1]: Entering directory '/usr/src/linux-headers-4.15.0-142-generic'
    4. CC [M] /media/fukaiqiang/Disk960/Codes/kernel/hello_world/helloworld.o
    5. Building modules, stage 2.
    6. MODPOST 1 modules
    7. CC /media/fukaiqiang/Disk960/Codes/kernel/hello_world/helloworld.mod.o
    8. LD [M] /media/fukaiqiang/Disk960/Codes/kernel/hello_world/helloworld.ko
    9. make[1]: Leaving directory '/usr/src/linux-headers-4.15.0-142-generic'
    1. uname -r 用于获取内核的版本
    2. obj-m 表示要生成的模块,其值组成为 <模块名>.o
    3. -C 这是make的递归调用,用在这里指进入/usr/src/linux-headers-4.15.0-142-generic,并递归这个目录下所有的Makefile进行make.
    4. M 并非是make的参数,而是内核编译的选项,所以M的值是/media/fukaiqiang/Disk960/Codes/kernel/hello_world
    5. make过程: 进入/usr/src/linux-headers-4.15.0-142-generic,通过hello_world.c生成hello_world.o,通过helloworld.mod.c生成helloworld.mod.o(不熟悉这个环节).链接hello_world.o和helloworld.mod.o生成helloworld.ko.离开/usr/src/linux-headers-4.15.0-142-generic.
    6. 作者:付凯强
    7. 链接:https://www.jianshu.com/p/d6c7314cdce7
    8. 来源:简书
    9. 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    检测ko文件的正确性

    1. $file helloworld.ko
    2. helloworld.ko: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), BuildID[sha1]=225d75bec2feeab394d6567f8104a13874623dd1, not stripped

    当看到 x86-64 的 ELF 文件,就证明编译成功了.

    查看ko文件的信息

    1. $modinfo helloworld.ko
    2. filename: /media/fukaiqiang/Disk960/Codes/kernel/hello_world/helloworld.ko
    3. alias: hw
    4. description: A simple hello world module
    5. license: GPL v2
    6. author: fukaiqiang
    7. srcversion: 897BBFF3273E374126017CE
    8. depends:
    9. retpoline: Y
    10. name: helloworld
    11. vermagic: 4.15.0-142-generic SMP mod_unload

    加载内核模块

    sudo insmod helloworld.ko

    查看内核是否已被加载

    1. lsmod | grep helloworld
    2. helloworld 16384 0

    查看内核的输出信息

    1. dmesg
    2. [421558.748577] hello World enter

    补充: 模块被加载后会在/sys/module下生成一个文件夹

    1. { fukaiqiang@superman /sys/module/helloworld }
    2. $tree -a
    3. .
    4. ├── coresize
    5. ├── holders
    6. ├── initsize
    7. ├── initstate
    8. ├── notes
    9. │ └── .note.gnu.build-id
    10. ├── refcnt
    11. ├── sections
    12. │ ├── .exit.text
    13. │ ├── .gnu.linkonce.this_module
    14. │ ├── .init.text
    15. │ ├── __mcount_loc
    16. │ ├── .note.gnu.build-id
    17. │ ├── .rodata.str1.1
    18. │ ├── .strtab
    19. │ └── .symtab
    20. ├── srcversion
    21. ├── taint
    22. └── uevent
    23. 3 directories, 16 files

    文章来源:编写一个简单的Linux内核模块 - 简书 (jianshu.com)

  • 相关阅读:
    网络安全(黑客)自学
    element ui 里面只能输入input 数字 +限制长度
    简单获取易贝/EBAY的商品详情
    ElasticSearch 学习(docker,传统方式安装、安装遇到的问题解决,)
    【Web基础入门】一文搞懂HTML + CSS + JavaScript 简单了解
    基于信通院 Serverless 工具链模型的实践:Serverless Devs
    企业级磁盘阵列存储系统由硬到软全析
    全场景流量验证系统
    C++&QT---QT-day1
    qs序列化插件
  • 原文地址:https://blog.csdn.net/buhuidage/article/details/126445448