一、内核模块原理

1. Linux内核增加功能

Linux内核整体结构很庞大,包含了很多的组件,现在有两种方法将需要的功能包含进内核当中:
- 静态加载:将所有的功能都编译进Linux内核。
- 动态加载:将需要的功能编译成模块,在需要的时候动态地添加。
  • 第一种方法优点在于不会有版本不兼容的问题,不需要进行严格的版本检查;但是生成的内核会很大,要在现有的内核中添加新的功能,要编译整个内核。
  • 第二种方法有点在于模块本身不编译进内核,从而控制了内核的大小,模块一旦被加载,将和其它的部分完全一样。可能会有内核与模块版本不兼容的问题,导致内核崩溃,会造成内存的利用率比较低。

2. 内核模块概述

  • 之所以提供模块机制,就是为了弥补Linux这个单内核可扩展性和可维护性相对较差的缺陷。
  • 一个模块被加载到内核中时,就成为内核代码的一部分。模块加载入系统时,系统修改内核中的符号表,将新加载的模块提供的资源和符号添加到内核符号表中,以便模块间的通信。

二、实现内核模块

1. 编写一个空模块

(1)模块许可证声明

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h> MODULE_LICENSE("GPL");
  • 内核支持GPL兼容代码,因此如果把许可证设置为其它非GPL兼容的(如,“Proprietary”[专利]),某些特定的内核功能在模块中不可用。
  • 如果不声明,则在模块加载时会收到内核被污染的警告,一般应遵循GPL协议。

(2)模块加载函数

static int __init XXX_init(void)
{
return 0;
}
moudle_init(XXX_init);
  • 在用insmod命令加载模块时,该函数被执行,完成模块的初始化工作。
  • 命名:Linux内核的模块加载函数一般用 __init 标识声明,模块加载函数必须以 XXX_init (函数名)的形式被指定。
  • 返回值:该函数返回整型值,如果执行成功,则返回0,初始化失败时则返回错误编码,Linux内核当中的错误编码是负值,在<linux/errno.h>中定义。

(3)模块卸载函数

static void __exit XXX_exit(void)
{
}
moudle_exit(XXX_exit);
  • 在用rmmod命令卸载模块时,该函数被执行,完成与加载相反的工作。
  • 命名:Linux内核的模块加载函数一般用 __exit 标识声明,模块加载函数必须以 XXX_exit (函数名)的形式被指定。
  • 主要包括:
    • 若模块加载函数注册了XXX,则模块卸载函数注销XXX
    • 若模块加载函数动态分配了内存,则模块卸载函数释放这些内存
    • 若模块加载函数申请了硬件资源,则模块卸载函数释放这些硬件资源
    • 若模块加载函数开启了硬件资源,则模块卸载函数一定要关闭这些资源

(4)模块参数

static 类型 名称 = 赋值;
  • 模块在被加载时传递给模块的值,本身应该是模块内部的全局变量。

2. 模块操作

(1)编译模块

  • 编写makefile:

      obj-m:=XXX.o
    CURRENT_PATH:=$(shell pwd)
    LINUX_KERNEL_PATH:=/usr/src/linux-headers-4.4.0-21-generic //这里写编译机器上的路径和版本
    all:
    make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
    clean:
    make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean //make -C $(LINUX_KERNEL_PATH) 指明跳转到内核源码目录下读取那里的Makefile
    //M=$(CURRENT_PATH) 表明返回到当前目录继续执行当前的Makefile
  • 将其放在编写的模块.c文件同级目录下,使用make命令编译,生成XXX.ko模块文件。

(2)加载模块

sudo insmod XXX.ko
  • 此时已经加载了模块。

(3)查看与测试

查看已经安装好的模块:
lsmod

  • 也可以通过查看/proc/modules文件的内容。实际上,lsmod读命令就是通过查看/proc/modules的内容来显示模块信息的。
显示linux内核的记录信息:
dmesg
显示模块信息:
modinfo XXX.ko

(4)卸载模块

sudo rmmod XXX
  • 这时用dmesg看内核信息,就会看到写在module_exit()中的输出。

3. 实现功能(参考学姐代码)

(1)输出当前进程信息

  • 代码:

  • 编译:

  • 查看内核信息,验证信息:

(2)读取进程链表

  • 代码:

  • 从第一个PCB(叫做init_task)开始,顺着next指针读了一圈:


参考资料

参考资料1:Linux内核模块简介

参考资料2:编写属于你的第一个Linux内核模块

Linux课程实践二:编译模块实现内核数据操控的更多相关文章

  1. 20135218 Linux 实践二 编译模块

    20135218 姬梦馨 1.编写模块代码 模块构造函数:执行insmod或modprobe指令加载内核模块时会调用的初始化函数.函数原型必须是module_init(),括号内是函数指针 模块析构函 ...

  2. 《Linux及安全》课程实践二

    编译生成新内核 一.实践原理 Linux模块是一些可以作为独立程序来编译的函数和数据类型的集合.之所以提供模块机制,是因为Linux本身是一个单内核.单内核由于所有内容都集成在一起,效率很高,但可扩展 ...

  3. 20135337——Linux实践二:模块

    一.编译&生成&测试&删除 1.编写模块代码,查看如下 gedit 1.c(编写) cat 1.c(查看) MODULE_AUTHOR("Z") MODUL ...

  4. Linux课程实践一:Linux基础实践(SSH)

    一.SSH服务 1. 安装SSH (1)查看是否已经安装过ssh服务 rpm -qa |grep ssh (2)进行安装 sudo apt-get install openssh-server Ubu ...

  5. Linux课程实践一:Linux基础实践(基础操作)

    一.软件源维护 1. 基本操作 (1)查看源列表 sudo vim /etc/apt/sources.list deb:二进制软件安装包 deb-src:源码包 (2)备份软件源列表 sudo cp ...

  6. Linux实践二:模块

    一.基本模块的实现: 1.进程遍历打印输出 2.简单地编写一个新的系统调用(替换空的系统调用号) 基本模块学到的知识点: 1.相关指令 make oldconfig 配置内核 make 编译内核 ma ...

  7. Linux课程实践三:简单程序破解

    一.基本知识 1. 常用指令机器码 不同版本对应机器码不同,这里以我做实验的kali(Intel 80386)为例. 指令 作用 机器码 nop 无作用(no operation) 90 call 调 ...

  8. Linux课程实践四:ELF文件格式分析

    一.ELF文件格式概述 1. ELF文件 ELF:Executable and Linking Format,是一种对象文件的格式,用于定义不同类型的对象文件(Object files)中都放了什么东 ...

  9. linux内实践核分析模块

随机推荐

  1. X.509证书生成

    创建数字证书 用户对数字证书的认可决定于对证书颁发机构的信任,所以证书颁发机构决定了数字证书的可用范围.由于官方认可的数字证书颁发机构,比如VeriSign.Thawte(OpenSSL),具有普遍的 ...

  2. Laravel学习笔记(五)数据库 数据库迁移案例2——创建数据结构,数据表,修改数据结构

    默认假设 所有的列在定义的时候都有默认的假设,你可以根据需要重写. Laravel假定每个表都有一个数值型的主键(通常命名为”id”),确保新加入的每一行都是唯一的.Laravel只有在每个表都有数值 ...

  3. CM给hive添加自定义jar包

    使用的是cloudera manager管理的集群: hive添加自定义jar包 服务端:高级:Hive 辅助 JAR 目录 设置的的路径是影响所有服务端的设置,比如hue中使用到了hive查询编辑器 ...

  4. Pycharm注册码(2016.2)

    43B4A73YYJ-eyJsaWNlbnNlSWQiOiI0M0I0QTczWVlKIiwibGljZW5zZWVOYW1lIjoibGFuIHl1IiwiYXNzaWduZWVOYW1lIjoiI ...

  5. maven多项目配置实践

    工具:IntelliJ IDEA 1.新建maven项目top 略 提示:不使用任何模版 2.在上面的maven项目的目录下(虽然这不一定是必须的),新建另一个maven项目secend. 同上 3. ...

  6. 无需Try catch 的UI事件封装类

    在UI处理中,经常需要进行异常处理,以便在错误发生时能够进行一些自定义的操作,比如,弹出消息框给用户,进行重试操作,记录日志等,如果能够让用户写代码时不用写try...catch,而只是关注业务逻辑的 ...

  7. 怎样安装Ubuntu操作系统

    (转载自:http://jingyan.baidu.com/article/ff42efa9423991c19e22020d.html) 准备工作 1. 一台普通电脑(装没装操作系统无所谓),保证电脑 ...

  8. questasim仿真控制——breakpoint断点

    在使用questasim或者modelsim仿真时,如果需要控制仿真时间长度,一般在vsim中使用 run xxxxms/us等命令. 但是有时候不好估计仿真多长时间才能得到所有希望观察的结果,这个时 ...

  9. Windows Server 2012重复数据删除技术体验

    在企业环境中,对磁盘空间的需求是惊人的.数据备份.文件服务器.软件镜像.虚拟磁盘等都需要占据大量的空间.对此,微软在Windows Server 2012中引入了重复数据删除技术.重复数据删除技术通过 ...

  10. 带有静态方法的类(java中的math类)

    带有静态方法的类通常(虽然不一定是这样)不打算被初始化. 可以用私有构造函数来限制非抽象类被初始化. 例如,java中的math类.它让构造函数标记为私有,所以你无法创建Math的实例.但Math类却 ...