您的位置:首页 > 运维架构 > Linux

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

2014-05-28 22:32 711 查看
在上一篇日志《增加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许可权的模块才可以访问该符号名
[b]●编写内核模块代码[/b]

新建文件夹放置内核模块代码和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.o
else
KERNEL_VER := $(shell uname -r)
KERNEL_DIR := /lib/modules/$(KERNEL_VER)/build
CUR_PATH := $(shell pwd)

default:
$(MAKE) -C $(KERNEL_DIR) M=$(CUR_PATH) modules
modules_install:
$(MAKE) -C $(KERNEL_DIR) M=$(CUR_PATH) modules_install
clean:
$(MAKE) -C $(KERNEL_DIR) M=$(CUR_PATH) clean
endif
注意testmodule.o文件的名字必须与内核模块代码的文件名相同。

[b]●编译内核模块[/b]

$ 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 336

int 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系统调用——通过重新编译内核》完全相同,实验成功。

这里要注意的是,事实上,虽然可以动态地修改内核模块代码,但是最开始的时候还是要通过编译内核来增加函数指针,通过这个函数指针来调用内核模块。也就是说,这个函数指针的形式事实上已经固定了,这也就限制了内核模块函数的形式。这种动态加载并不是完全的自由。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐