2021-05-31内核模块调用多个模块函数实验

第一个内核模块实验

注:本实验基于Ubuntu 16.04.3 LTS (GNU/Linux 4.4.0-93-generic x86_64)
实验环境为阿里云服务器轻量级应用服务器

一. 、预习要求

(1)做本实验之前,请复习PPT里内核模块相关知识。
(2)请了解内核模块的编写、编译及安装与卸载方法。
(3)请学习内核打印函数printk()的用法。
(4)请复习Makefile文件的编写。

二、实验目的

(1)掌握内核模块的组成部分。
(2)掌握内核模块的编译、安装与卸载方法。(3)学会查看内核模块的信息。

三、实验要求

(1)编写三个模块mainmod、lenmod、summod。summod模块导出对数组元素求和函数,lenmod模块导出求数组元素的个数函数,mainmod模块使用summod和lenmod导出的函数。注意路径清晰,分别在三个目录下编写。
(2)每个shell命令提示符的用户名必须是自己的名字。

四、实验步骤

1.建立3个文件夹mainmod、lenmod、summod
在这里插入图片描述

2.分别编写mainmod.c、lenmod.c、summod.c以及各自文件夹的Makefile
在这里插入图片描述

mainmod.c
在这里插入图片描述
在这里插入图片描述

lenmod.c
在这里插入图片描述
在这里插入图片描述

summod.c
在这里插入图片描述
在这里插入图片描述

3.4.按summod、lenmod、mainmod的顺序编译(make)并插入模块
在这里插入图片描述

5.使用dmesg |tail -10查看结果
在这里插入图片描述

五、实验代码

mainmod.c

/*包含了对模块的结构定义以及模块的版本控制,
* 任何模块程序的编写都要包含这个头文件*/
#include <linux/module.h>    

#include <linux/kernel.h>    //包含了常用的内核函数

extern int sum(int* a,int len);
extern int len(int* a);

/*宏__init告诉编译程序相关的函数和变量仅用于初始化,
* 编译程序将标有__init的所有代码存储到特殊的内存段中,
* 初始化结束后就释放这段内存*/
#include <linux/init.h>      //包含了宏__init和宏__exit

static int __init lkp_init(void)   //lkp_init()是模块初始化函数
{
    /*printk()函数,该函数是由内核定义的,功能与C库中的
      printf()类似,它把要打印的信息输出到终端或者系统日志*/
	int result = 0;
	int length = 0;
	int a[] = {1,6,4,9};
	printk(KERN_INFO"Hello,mainmod!\n");
	length = len(a);
	result = sum(a,length);
	printk(KERN_INFO"Array's length is %d,Array's sum is %d\n",length,result);
    return 0;
}
static void __exit lkp_cleanup(void) //lkp_cleanup()是模块的退出和清理函数
{
    printk("<1>Goodbye,World! leaving kernel space...\n");

}
/*是模块编程中最基本也是必需的两个函数*/
module_init(lkp_init);  //向内核注册模块提供新功能
module_exit(lkp_cleanup); //注销由模块提供所有的功能
MODULE_LICENSE("GPL"); //告诉内核该模块具有GNU公共许可证

Mainmod的Makefile

obj-m := mainmod.o
KERNELDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)

KBUILD_EXTRA_SYMBOLS += /root/summod/Module.symvers
KBUILD_EXTRA_SYMBOLS += /root/lenmod/Module.symvers
export KBUILD_EXTRA_SYMBOLS

default:
        $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
        rm -f *.o *.ko *.mod.c *.order *.symvers

lenmod.c

/*包含了对模块的结构定义以及模块的版本控制,
* 任何模块程序的编写都要包含这个头文件*/
#include <linux/module.h>    

#include <linux/kernel.h>    //包含了常用的内核函数

/*宏__init告诉编译程序相关的函数和变量仅用于初始化,
* 编译程序将标有__init的所有代码存储到特殊的内存段中,
* 初始化结束后就释放这段内存*/
#include <linux/init.h>      //包含了宏__init和宏__exit

static int __init lkp_init(void)   //lkp_init()是模块初始化函数
{
    /*printk()函数,该函数是由内核定义的,功能与C库中的
      printf()类似,它把要打印的信息输出到终端或者系统日志*/
    printk(KERN_INFO"Hello,lenmod!\n");
    return 0;
}
static void __exit lkp_cleanup(void) //lkp_cleanup()是模块的退出和清理函数
{
    printk("<1>Goodbye,World! leaving kernel space...\n");

}
int len(int* a){
	printk(KERN_INFO"Hello,lenmod!sizeof=%d\n",(int)sizeof(a));
    return (int)sizeof(a)/2;
}
EXPORT_SYMBOL(len);
/*是模块编程中最基本也是必需的两个函数*/
module_init(lkp_init);  //向内核注册模块提供新功能
module_exit(lkp_cleanup); //注销由模块提供所有的功能
MODULE_LICENSE("GPL"); //告诉内核该模块具有GNU公共许可证

Lenmod的Makefile

obj-m :=lenmod.o
all:
	make -C /lib/modules/$(shell uname -r)/build SUBDIRS=$(PWD) modules    #编译模块
clean:
	make -C /lib/modules/$(shell uname -r)/build SUBDIRS=$(PWD) clean      #清理

summod.c

/*包含了对模块的结构定义以及模块的版本控制,
* 任何模块程序的编写都要包含这个头文件*/
#include <linux/module.h>    

#include <linux/kernel.h>    //包含了常用的内核函数

/*宏__init告诉编译程序相关的函数和变量仅用于初始化,
* 编译程序将标有__init的所有代码存储到特殊的内存段中,
* 初始化结束后就释放这段内存*/
#include <linux/init.h>      //包含了宏__init和宏__exit

static int __init lkp_init(void)   //lkp_init()是模块初始化函数
{
    /*printk()函数,该函数是由内核定义的,功能与C库中的
      printf()类似,它把要打印的信息输出到终端或者系统日志*/
    printk(KERN_INFO"Hello,summod!\n");
    return 0;
}
static void __exit lkp_cleanup(void) //lkp_cleanup()是模块的退出和清理函数
{
    printk("<1>Goodbye,World! leaving kernel space...\n");

}
int sum(int* a,int len)
{
	int i = 0;
	int result = 0;
	for(i = 0;i < len;i++)
	{
		result += a[i];
	}
	return result;
}
EXPORT_SYMBOL(sum);
/*是模块编程中最基本也是必需的两个函数*/
module_init(lkp_init);  //向内核注册模块提供新功能
module_exit(lkp_cleanup); //注销由模块提供所有的功能
MODULE_LICENSE("GPL"); //告诉内核该模块具有GNU公共许可证

Summod的Makefile

obj-m :=summod.o
all:
	make -C /lib/modules/$(shell uname -r)/build SUBDIRS=$(PWD) modules    #编译模块
clean:
	make -C /lib/modules/$(shell uname -r)/build SUBDIRS=$(PWD) clean      #清理

六、实验总结
1.在mainmod中,要加入

extern int sum(int* a,int len);
extern int len(int* a);

来引入外部函数

2.在被依赖的函数后面,要使用

EXPORT_SYMBOL(len);

来进行导入函数

3.在mainmod的Makefile文件中,要加入

KBUILD_EXTRA_SYMBOLS += /root/summod/Module.symvers
KBUILD_EXTRA_SYMBOLS += /root/lenmod/Module.symvers
export KBUILD_EXTRA_SYMBOLS

来引入其他模块的Module.symvers

参考文献
https://blog.csdn.net/ningxiaowei2013/article/details/13630267
https://blog.csdn.net/xhz1234/article/details/44278137 Copyright 徐洪志(MacroSAN). All rights reserved.
https://blog.csdn.net/weixin_43858015/article/details/106209813

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值