华南理工大学《高级操作系统》实验报告

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Linux系统本身并未有记录系统调用次数的数据结构,因此我们需要在内核中定义一个全局数组来记录 每个系统调用被执行的次数。从调用的原理上看,要记录每个系统调用被执行的次数,我们可以在 system_call()参数检查成功后,对相应的系统调用次数做一次增量操作,这样就完成了执行次数记录的工 作。为了能得到该数组信息和对该数组进行操作,我们还需要定义自己的系统调用。我们定义的系统调用 可以相应地在entry.S中的sys_call_table添加,并重新编译内核,使用该函数。
时返回-1。
(3) clrSysCall:接受 0 个参数,用于把系统调用次数数组清零。
6. 为三个系统调用增加具体实现
在/usr/src/linux-2.6.18/kernel/sys.c 中实现这三个函数:
asmlinkage int sys_allSysCall(void){ int i=0; printk("Times of system calls\n"); for(;i<NR_syscalls;i++) printk("System call [%d] was called %ld times. \n",i,callCount[i]); return 0; }
3. 在系统调用表中增加表项
在/usr/src/linux-2.6.18/arch/i386/kernel/syscall_table.S 尾部添加三个系统调用的表项: .long sys_allSysCall .long sys_spcSysCall .long sys_clrSysCall
翻到 syscall_table.S 的头部可以看到下图内容,这个文件存储的是系统调用表,实际 上就是 sys_call_table 这个数组,共有 NR_syscalls 个表项。语句前面的点号’’.’指的 是 当 前 的 地 址 , sys_call_table 是 数 组 的 首 地 址 , 调 用 表 中 的 第 321 个 表 项 sys_clrSysCall 指代系统调用号为 320 的 clcSysCall()服务例程地址。这个表项的作用 就是用来通过系统调用号索引内核服务例程。
在用户空间无法直接调用系统调用来执行内核代码,所以需要通过软中断的方式来实现系统调用。通 过int $0x80指令产生系统软中断,触发异常使得系统切换到内核态执行128号异常处理程序,调用 system_call()函数。但是仅仅陷入内核空间是不够的,还需要通过eax寄存器把相应的系统调用号传递给 内核。在陷人内核之前,用户空间就把相应系统调用所对应的号放入eax中了。这样系统调用处理程序一旦 运行,就可以从eax中得到数据。system_call()函数通过将给定的系统调用号与NR_syscalls做比较来检查 其有效性。如果它大于或者等于NR syscalls,该函数就返回一ENOSYS。否则,就执行相应的系统调用。由 于系统调用表中的表项是以32位(4字节)类型存放的,所以内核需要将给定的系统调用号乘以4,然后用所 得的结果在该表中查询其位置。
课程大作业报告书
题目:高级操作系统与分布式系统大作业
学院
计算机科学与工程
专 业 计算机科学与技术(全英创新班)
学生姓名
黄炜杰
学生学号
201230590051
联系方式 _15626243309(Tel)/651476895(QQ)_
指导教师
吴一民
课程编号
S0812011
课程学分
2分
起始日期
2016 年 1 月 11 日
5. 在头文件中声明三个系统调用
在/usr/src/linux-2.6.18/include/linux/syscalls.h 的尾部添加: asmlinkage int sys_allSysCall(void); asmlinkage int sys_spcSysCall(int sys_callNum); asmlinkage int sys_clrSysCall(void);
int sysNum; scanf("%d",&sysNum); syscall(test_spcSysCall,sysNum); return 0; }
asmlinkage int sys_clrSysCall(void){ int i=0; for (;i < NR_syscalls;i++) callCount[i]=0; printk("Times of system call setted to 0.\n"); return 0; }
7. 重新编译内核
7. 安装内核: make install
8. 内核版本验证: vim /boot/grub/grub.conf 查看内核版本列表,可以看到 2.6.18 内核已安装,修改 default=0, 默认启动新安装的内核。
9. 重启,查看内核版本: uname –a 内核从 2.6.18-308 变为 2.6.18,内核安装成功。
【实验环境】 操作系统: Centos-5.8-i386(内核版本 2.6.18-308) 编译的内核: 2.6.18 虚拟机: VMware Workstation 12.1.0.2487
【虚拟机账号密码】★★★★ 账号:root 密码:aaasss
实验一
实验内容
【实验原理】
linux系统调用是linux在其内核里都有一些内建的函数,这些函数可以用来完成一些系统级别的功能。 这些函数代表了从用户空间到内核空间的一种转换,例如在用户空间调用open函数,则会在内核空间调用 sys_open。Linux中每个系统调用都有相应的系统调用号,这样,通过这个独一无二的号就可以关联系统调 用。当用户空间的进程执行一个系统调用的时候,这个系统调用号就被用来指明到底是要执行哪个系统调 用。进程不会提及系统调用的名称。在这次试验采用的linux-2.6.18内核中共有317个系统调用,他们储存在 sys_call_table的数据结构当中,这个数据结构在此内核中的entry.S中定义。sys_call_table是一张由指向实 现各种系统调用的内核函数的函数指针组成的表。
incl callCount(,%eax,4)这条会变代码的含义是:incl 是对后面的地址的内容进行自增 操作,也就是对 callCount(,%eax,4)这个元素的内容+1。其中 eax 是用户空间传递到 eax 寄存器中的系统调用号。,%eax,4 的含义是 eax 寄存器里面的值乘以 4,由于系 统调用表中的表项是以 32 位(4 字节)类型存放的,所以内核需要将给定的系统调用 号乘以 4,所以是对 callCount 第%eax*4 个元素进行增量操作。
实验概述
【实验目的及要求】 内核版本要求:
Linux-2.6.18 实验任务:
1.修改 system_call(),使内核能够记录每一个系统调用被使用的次数。同时,为了使应用 程序能够查询到这些数据,本实验要求实现两个系统调用,一个供应用程序来查询某个特 定系统调用被使用的次数,另一个系统调用将系统调用计数清零。编制一个用户态程序调 用你所增加的这两个系统调用,统计在一段时间内各系统调用被调用的次数。 2.修改系统的缺页异常处理程序使之能够记录系统缺页次数和当前进程的缺页次数。同样, 本实验也要求实现两个系统调用,一个供应用程序查询缺页次数,另一个系统调用将缺页 计数清零。编制一个用户态程序你所增加的这两个系统调用,统计在一段时间内你的进程 缺页的次数。
4. 为三个新增的系统调用添加系统调用号的宏
在/usr/src/linux-2.6.18/include/asm/unistd.h 中添加三个系统调用的调用号: #define __NR_allSysCall 318 #define __NR_spcSysCall 319 #define __NR_clrSysCall 320 把__NR_syscalls 这个记录系统调用总数的宏增加 3 #define __NR_syscalls 321
asmlinkage int sys_spcSysCall(int callNum){ if(callNum < NR_syscalls && callNum >= 0){ printk("System call --%d has been call %ld time(s). \n",callNum,mycount[callNum]); return callCount[callNum]; } else{ printk("Inviliad system call number.\n"); return -1; } }
syscall.h 这个头文件适用于实现系统调用表中指向的服务例程,在本实验中,我定
义了三个函数:
(1) allSysCall:接受 0 个参数,用于显示所有系统调用被执行的次数。
(2) spcSysCall:源自文库接受 1 个参数,查询的系统调用号作为参数,用于显示某个特定
的系统调用被执行的次数,返回值为该系统调用被调用的次数。参数不合法
实验过程:
内核安装
1. 安装 vmware workstation,并在其上安装 CentOS 5.8。 2. 安装 vmware-tools,设置共享文件夹。并把内核文件 linux-2.6.18.tar.xz 下载至共享文
件夹当中(/mnt/hgfs/sharedFiles)。 3. 登录 root,把内核文件压缩包解压至/usr/src 目录下:
syscall(test_allSysCall); return 0; }
测试结果:
所有系统调用的次数都已被列出(这里只显示前几个),函数正常工作。 (2) 测试 spcSysCall(): test_spcSysCall.c
#include<linux/unistd.h> #include<stdlib.h> #include<stdio.h> #include<errno.h> #define test_spcSysCall 319 int main() {
2. 修改 system_call(),使其能对每个系统调用进行计数
在/usr/src/linux-2.6.18/arch/i386/kernel/entry.S 的 syscall_call:和 call *sys_call_table (,%eax,4)之间插入语句: vim /usr/src/linux-2.6.18/arch/i386/kernel/entry.S incl callCount(,%eax,4)
记录系统调用次数
1. 创建一个全局数组记录系统调用次数
在/usr/src/linux-2.6.18/kernel/sys.c 中添加一个 callCount 数组记录系统调用次数 vim /usr/src/linux-2.6.18/kernel/sys.c long callCount [NR_syscalls]; EXPORT_SYMBOL (callCount); 其中 NR_syacalls 是 sys.c 中的一个宏,记录了系统调用的数量。
# tar -xvf linux-3.13.2.tar.xz -C /usr/src/
4. 安装 gcc 和 ncurses 包: yum -y install gcc yum install ncurses ncurses-deve
5. 进行内核配置: make menuconfig
6. 进入 usr/src/linux-2.6.18/目录编译内核: cd usr/src/linux-2.6.18/ make make modules_install
8. 编写测试函数
(1) 测试 allSysCall(): test_allSysCall.c
#include<linux/unistd.h> #include<stdlib.h> #include<stdio.h> #include<errno.h> #define test_allSysCall 318 int main() {
相关文档
最新文档