Ubuntu10.04+kernel2.6.32.60编译内核(五):Linux加载系统调用

三、实验二

1.任务

用内核模块的方式为系统添加一个系统调用。
要求该系统调用能够完成以下功能:
(1) 该系统调用有1个整型参数,接收输入自己的学号;
(2) 若参数为奇数,则返回自己学号的最后5位。如你的学号为130120101 ,则返回20101;
(3) 若参数为偶数,则返回自己的学号的最后6位。如你的学号为130120102 ,则返回120102 。

2.过程

  1. 得到sys_call_table的地址
grep sys_call_table /boot/System.map-`uname -r`
cat /proc/kallsyms | grep sys_call_tables
  1. 查看预留的系统调用号。
cd /usr/src/linux-2.6.32.60/arch/x86/include/asm
sudo gedit unistd_32.h

文件中查看预留的系统调用号。
在这里插入图片描述
可以看出223就是一个预留的系统调用号。

  1. 改内核程序源代码:.c文件
cd ~
mkdir project2 && cd project2
gedit burgerModule.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/unistd.h>
#include <asm/uaccess.h>
#include <linux/sched.h>


#define sys_call_table_adress 0xc0583110
int orig_saved=0;
unsigned long* sys_call_table = 0;
int make_rw(unsigned long address);  
int make_ro(unsigned long address);
asmlinkage long sys_mycall2(int num);

int make_rw(unsigned long address)  
{  
	unsigned int level;  
	pte_t *pte = lookup_address(address, &level);//查找虚拟地址所在的页表地址  
	if (pte->pte & ~_PAGE_RW)  //设置页表读写属性
		pte->pte |=  _PAGE_RW;  
	return 0;  
}  
  
  
  
int make_ro(unsigned long address)  
{  
	unsigned int level;  
	pte_t *pte = lookup_address(address, &level);  
	pte->pte &= ~_PAGE_RW;  //设置只读属性
	
	return 0;  
} 

static int syscall_init_module(void)  
{
    sys_call_table = (unsigned long*)sys_call_table_adress;//获取系统调用服务首地址
	printk(KERN_ALERT "sys_call_table: 0x%p\n", sys_call_table);//获取系统调用表的地址
	orig_saved = (unsigned long *)(sys_call_table[223]);  //保存原有的223号的系统调用表的地址
	printk(KERN_ALERT "orig_saved : 0x%p\n", orig_saved );  
	
	make_rw((unsigned long)sys_call_table);  //修改页的写属性
	sys_call_table[223] = (unsigned long *)sys_mycall2;  //将223号指向自己写的调用函数
	make_ro((unsigned long)sys_call_table);  
	
	return 0;  
}

asmlinkage long sys_mycall2(int num){
    printk("your number is %d\n",num);
    if(num%2==0)
        return num%1000000;
    else
        return num%100000;
}

static void syscall_cleanup_module(void)  
{  
	printk(KERN_ALERT "Module syscall unloaded.\n");  
	
	make_rw((unsigned long)sys_call_table);  
	sys_call_table[223] = (unsigned long *) orig_saved ;   
	make_ro((unsigned long)sys_call_table);  
}

module_init(syscall_init_module);  
module_exit(syscall_cleanup_module);  
  
MODULE_LICENSE("GPL");  
MODULE_DESCRIPTION("mysyscall");  
gedit Makefile
obj-m := burgerModule.o
KERNELDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
modules:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
	rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
make
sudo dmesg -c
sudo insmod burgerModule.ko
  1. 查看要关注的信息
  • 查看printk的输出在缓冲区的信息:
dmesg

在这里插入图片描述

  • 调用系统调用的信息
gedit helloworld.c
#include<stdio.h>
int main()
{
	int t;
	scanf("%d",&t);
	printf("%d\n",syscall(223,t));
	return 0;
}
gcc helloworld.c
./a.out

在这里插入图片描述

  • 卸载信息
sudo rmmod burgerModule
sudo dmesg -c

在这里插入图片描述


参考:

使用内核模块方式添加简单系统调用
Linux添加系统调用的两种方法

发布了461 篇原创文章 · 获赞 183 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/sandalphon4869/article/details/104764039