linux内核模块编译新手指南


  • 一 题目介绍
  • 二 实验思路
  • 三 核心代码及实验结果展示
  • 四 参考文献

在这里插入图片描述

一 题目介绍

  • 在本次实验中,要求我们用Linux提供的模块机制能动态扩充Linux的功能,它弥补了单体式内核相对于微内核可维护性、可扩展性的不足,也降低了系统功能的更新难度。
  • 先跟着教材设计一个“myhello”模块,在此过程中理解内核模块与重新编译内核的不同;接着设计一个能够列出系统中所有的内核线程的程序名、pid、进程状态、进程优先级与父进程pid;最后设计一个带参数的模块,它的参数是某个进程的pid号,此模块能够列出该进程的家族信息即父进程、兄弟进程、子进程的程序名、pid与进程状态。
  • 本次实验主要考察了我们以下几个知识点:1.内核模块的基本概念、原理、编写结构、编译与加载过程。2.学会用内核模块编程访问进程的基本信息。3.理解内核符号表的作用,即对于某些模块可以使用由某一模块导出的符号,利用这个现成代码实现更复杂的功能,即模块层叠技术。4.了解makefile文件的功能,即当make的时候需要先读取顶层的makefile文件,然后再继续编译。5.了解带参数的内核模块编译与不带参数的内核模块编译在代码结构上的不同。
  • 对于本次实验,问题的关键点在于如何通过教材所提供的宏来得到需要的信息;而本次实验使用模块化编译,修改模块代码后只需要重新编译和加载模块,不必重新编译内核和引导系统,大大减少了等待时间也适当的降低了本次实验的难度。

在这里插入图片描述

二 实验思路

在这里插入图片描述

  • Figure 1整体实验思路流程图

对于图1:

3编译:
make
(在当前目录中,默认此目录的makefile文件为描述文件。

4加载模块:
insmod 模块名
(加载模块命令的格式为insmod [filename] [module options…]

5查看已加载模块:
lsmod
(lsmod | grep 模块名 可查看指定模块是否已经加载

6查看模块信息:
modinfo 模块名```

7卸载:
rmmod 模块名

在这里插入图片描述

  • Figure 2模块代码编写流程

对于图2:
1头文件声明:
#include<linux/init.h>//模块初始化,清理函数
#include<linux/module.h>//加载模块所需函数和符号
等等
关键点:当该函数可以传参时,头文件应包含#include<linux/moduleparam.h>,除此之外要参数声明,对参数说明。
例:#include<linux/moduleparam.h>
static type name;
module_param(name,type,perm);//perm表示模块参数的访问权限
2函数初始化:
初始化函数格式
static int fun_init(void)
{
//初始化代码
}
3清理函数:
清理函数格式
static void fun_exit(void)
{
//清理代码
}
4调用宏注册函数:
module_init(fun_init);
module_exit(fun_exit);
5模块许可声明:
MODULE_LICENSE(“GPL”);//原则上可以写在任意地方,惯例放最后
在这里插入图片描述

  • Figure 3 makefile文件编写流程

对于图3:
1书写模块名称:
obj-m:=名称.o //生成的模块名为 名称.ko
2说明生成模块所需要的必要文件:
名称-objs:=<目标文件> //目标文件后缀为.o
3指定内核源码目录:
KDIR:=/lib/modules/$(shell uname -r)/build
该内核目录由当前运行内核使用的模块目录中build符号链接指定;直接给出源码目录也可。
4当前目录:

PWD:=$(shell pwd) //PWD为当前目录

5默认执行:
default:
make -C ( K D I R ) M = (KDIR)M= (KDIR)M=(PWD)modules //-C指定内核源码目录,M指定模块源码所在目录
6清理执行:
clean:
make -C ( K D I R ) M = (KDIR)M= (KDIR)M=(PWD)clean

在这里插入图片描述

  • Figure 4 module1的函数初始化

对于图4所用到的:
for_each_process( p )
次访问该链表中的每个进程,相当于for(p=&init_task;(p=next_task§)!=&init_task;)。
p->mm==NULL
其中p为进程控制块指针,mm 为内核映射,而内核进程的内核映射为空,由此可根据这个条件判断是否为内核映射。
在这里插入图片描述

  • Figure 5 module2的函数初始化

对于图5所用到的:
find_get_pid( pid_t nr )
根据进程号获取对应描述符指针。
pid_task( structpidpid,enumpid_typetype )
根据描述符指针返回进程控制块。
list_for_each(pos, head)
其中list_for_each可看作是一个遍历一个链表的循环,它与for(pos=(head)->next;pos!=(head);pos=pos->next)等价。
list_entry(ptr, type, member)
list_entry则是获得该项的结构体,即指针ptr指向type结构体中的成员member,通过该指针,获得整个结构体。

在这里插入图片描述

三 核心代码及实验结果展示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

  • Figure 6 hello的模块代码、makefile与输出结果等

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • Figure 7 module1的模块代码、makefile与输出结果等

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Figure 8 module2的模块代码、makefile与输出结果等
在这里插入图片描述

四 参考文献

  • https://blog.csdn.net/gatieme/article/details/51484562 Linux下0号进程的前世(init_task进程)今生(idle进程)----Linux进程的管理与调度(五)
  • https://blog.csdn.net/qq_26768741/article/details/54375524 进程—内存描述符(mm_struct)
  • https://blog.csdn.net/u013216061/article/details/70592461 Makefile基本语法
  • https://blog.csdn.net/zjl_1026_2001/article/details/5606544 Linux进程状态
  • https://blog.csdn.net/qq_40240576/article/details/82866731 进程控制块和状态——随堂笔记
  • https://blog.csdn.net/qq_36285879/article/details/88771623
    杭电操作系统实验二报告
    在这里插入图片描述
  • 如果对你有帮助的话,请给我点个赞吧~
  • 感谢你看到这里~
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值