实验编号 |
课程设计专题二 |
题目 |
系统调用 |
|
实验目的 |
1.什么是系统调用 2.系统调用实现原理 3.增加用户自定义的系统调用 |
|||
实验内容 |
为Linux内核增加一个系统调用,并编写用户进程的程序来测试。要求该系统调用能够完成以下功能: (1) 该系统调用有1个整型参数,接收输入自己的学号; (2) 若参数为奇数,则返回自己学号的最后5位。如你的学号为16130120101 ,则返回20101; (3) 若参数为偶数,则返回自己的学号的最后6位。如你的学号为16130120102 ,则返回120102 。 |
|||
报告内容要求 |
(1) 程序实现方法和思路 (2) 测试及结果 |
|||
报 告 正 文 |
||||
(1) 操作系统的主要功能是为管理硬件资源和为应用程序开发人员提供良好的环境来使应用程序具有更好的兼容性,为了达到这个目的,内核提供一系列具备预定功能的多内核函数,通过一组称为系统调用(system call)的接口呈现给用户。系统调用把应用程序的请求传给内核,调用相应的的内核函数完成所需的处理,将处理结果返回给应用程序。
1.通过中断使进程切换到内核模式[i386为int 80h指令完成] 系统调用中断的入口为 syscall(调用号), 2.查找系统调用跳转表,并调用相应函数:
3.linux-2.6.32.60/arch/x86/include/asm/unistd_32.h中定义了所有系统调用的编号 4.跳转表以系统调用编号为下标,总个数由NR_syscalls确定 5.每个系统调用都有自己的编号,而且是固定的,如果想修改编号,则要改变跳转表的顺序。 6.没有定义的跳转表项,一律指向函数 sys_ni_syscall()/*kernel/sys.c*/ {return -ENOSYS;}
第一步: 解压缩内核源码包linux-2.6.32.60.tar.bz2到目录/usr/src下 解压缩命令tar xvf linux-2.6.32.60.tar.bz2 /usr/src 解压缩后在/usr/src中多了一个linux-2.6.32.60的文件夹,之后的修改源码的工作都是在这个文件夹中进行。
第二步: 修改系统调用表文件 linux-2.6.32.60/arch/x86/kernel/syscall_table_32.S 在文件中最后一组.long代码后添加一行 .long sys_mycall
第三步: 修改系统调用号文件,增加函数的系统调用号,并将系统总调用号增加到相应文件中。 linux-2.6.32.60/arch/x86/include/asm/unistd_32.h 在文件最后增加系统调用 #define __NR_mycall 337 //自己函数的调用号 同时修改系统调用函数总数,这是可以调用的编号上限 #define NR_syscalls 338
第四步: 增加系统调用声明,修改文件 linux-2.6.32.60/include/linux/syscalls.h 在文件后添加代码 asmlinkage long sys_mycall(int num);
第五步: 添加系统调用函数的实现,修改文件 linux-2.6.32.60/kernel/sys.c 在文件后添加代码,必须和第四步的声明完全对应 printk()的输出可以在终端中用dmesg命令查看 1 asmlinkage long sys_mycall(int num){
2 //在此处加入自己的代码
3 printk(“This is my syscall from kernel.
”);
4 printk(“current pid is:%d.
”,current->pid);
5 return num;
6 }
第六步:内核编译 重新编译内核,用新编译的内核作为启动项。
第七步:打开终端编写测试代码,代码中调用你自己写的系统函数,编译运行查看运行结果是否调用成功。 也可以用dmesg命令查看进程的printk()函数的输出。 调用方式:syscall(系统调用号,参数列表); 创建一个.c的源文件,写入测试代码。 1 #include <stdio.h>
2 int main()
3 {
4 printf("The return value is: %d.
", syscall(337, 5));
5 return 0;
6 }
(2)
|