增加Linux系统调用——通过增加内核模块

来源:互联网 发布:linux if语句嵌套 编辑:程序博客网 时间:2024/05/16 12:36

在上一篇日志《增加Linux系统调用——通过重新编译内核》中已经介绍了如何通过编译Linux内核的方式来增加系统调用。这里将继续介绍如何通过增加内核模块的方式增加Linux系统调用。

●添加系统调用的入口参数

#define __NR_zzr_callmod 336

●在linux-2.6.30.6/arch/x86/kernel/syscall_table_32.S 中添加:.long sys_zzr_callmod /* 336 */

.long sys_zzr_callmod /* 336 */

●添加自定义系统响应函数

修改linux-2.6.30.6/kernel/sys.c文件,在文件末尾添加自定义的系统响应函数。函数实现如下:

/*The function point that is used to call system module Added by ZZR                  */int (*zzr_function)(int *, int, int, char) = NULL;//函数指针EXPORT_SYMBOL_GPL(zzr_function);asmlinkage int sys_zzr_callmod(int *result, int first, int second, char op)//模块调用函数{if(zzr_function){return zzr_function(result,first,second,op);}}

在sys_zzr_callmod之前定义与要调用的外部模块中函数同类型的函数指针zzr_function,并且把zzr_function通过EXPORT_SYMBOL_GPL放到内核全局符号表中

注:EXPORT_SYMBOL(符号名);EXPORT_SYMBOL_GPL(符号名); //只有包含GPL许可权的模块才可以访问该符号名

编写内核模块代码

新建文件夹放置内核模块代码和Makefile文件。

内核模块代码testmodule.c:

#include <linux/kernel.h>#include <linux/module.h>MODULE_LICENSE("GPL");  extern int (*zzr_function)(int *, int, int, char);//函数指针int my_function_module(int *result, int first, int second, char op){printk("In the kernel module\n");switch(op){case '+': *result = first + second; break;case '-': *result = first - second; break;case '*': *result = first * second; break;case '/':if(second == 0){printk("divisor can't be 0.\n");return -1;}*result = first / second; break;default:printk("operator is illegal.\n");return -1;}return 0;}static int my_init(void)  {  zzr_function = my_function_module;    printk("ZZR_module_init success!\n");      return 0;  } static int my_exit(void)  {      printk("ZZR_module_exit success!\n");      return 0;  }  module_init(my_init);  module_exit(my_exit);  
Makefie文件:

ifneq ($(KERNELRELEASE),)obj-m := testmodule.oelseKERNEL_VER := $(shell uname -r)KERNEL_DIR := /lib/modules/$(KERNEL_VER)/build CUR_PATH := $(shell pwd) default:$(MAKE) -C $(KERNEL_DIR) M=$(CUR_PATH) modulesmodules_install:$(MAKE) -C $(KERNEL_DIR) M=$(CUR_PATH) modules_installclean:$(MAKE) -C $(KERNEL_DIR) M=$(CUR_PATH) cleanendif
注意testmodule.o文件的名字必须与内核模块代码的文件名相同。

编译内核模块

$ make


$ insmod testmodule.ko插入内核模块

$ lsmod 查看目前已经加载的内核模块


编写测试代码

#include <stdio.h>#include <sys/syscall.h>#include <unistd.h>#include <time.h>#define __NR_zzr_calculator 335#define __NR_zzr_callmod 336int main(){clock_t start,finish;double duration1,duration2;start = clock();int result;syscall(__NR_zzr_callmod,&result,3,4,'+');printf("+:\t%d\n",result);syscall(__NR_zzr_callmod,&result,3,4,'-');printf("-:\t%d\n",result);syscall(__NR_zzr_callmod,&result,3,4,'*');printf("*:\t%d\n",result);syscall(__NR_zzr_callmod,&result,3,4,'/');printf("/:\t%d\n",result);finish = clock();duration1 = (double)(finish-start)/CLOCKS_PER_SEC;printf("Kernel:\t%f\n",duration1);return 0;}
程序运行结果与增加Linux系统调用——通过重新编译内核》完全相同,实验成功。

这里要注意的是,事实上,虽然可以动态地修改内核模块代码,但是最开始的时候还是要通过编译内核来增加函数指针,通过这个函数指针来调用内核模块。也就是说,这个函数指针的形式事实上已经固定了,这也就限制了内核模块函数的形式。这种动态加载并不是完全的自由。



0 0
原创粉丝点击