资源预览内容
第1页 / 共31页
第2页 / 共31页
第3页 / 共31页
第4页 / 共31页
第5页 / 共31页
第6页 / 共31页
第7页 / 共31页
第8页 / 共31页
第9页 / 共31页
第10页 / 共31页
亲,该文档总共31页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
1 of 31 内核出口内核出口系统调用系统调用2 of 31基本知识3 of 31 xyz() system_call: sys_xyz() ret_from_sys _call: iretxyz() int 0x80 sys_xy z() 用户态 内核态在应用程序中使 用系统调用glibc标准库中的 封装例程 (系统调用函数 的具体实现)系统调用 处理程序系统调用 服务例程 (内核函数)系统调用处理过程系统调用处理过程4 of 31为什么有系统调用? 一般用户进程不能直接访问系统内核,不能直接使用或修改 内核数据,以免干扰内核程序的执行,妨碍系统安全。系统调用是什么? u用户进程要使用内核功能时,只能通过内核提供的接口 系统调用来实现,系统调用实际是操作系统内核提供的、 功能较强的一系列函数。 u系统调用好比一个中间人,把用户进程的系统调用请求传 达给内核,待内核把请求处理完毕后再将处理结果送回给用 户空间。 u系统调用是用户空间访问内核的唯一手段。系统调用发生 时会从用户态转到内核态,完成功能后又由内核态转回用户 态。5 of 31使用系统调用的两种方式1、通过C库函数2、使用syscall函数syscall函数原型为:int syscall(int number,);通过指定系统调用号和一组 函数来调用系统调用* 2.6.19版前使用_syscall宏C库函数 内核系统调用应用程序代码6 of 31C C库函数系统调用例子库函数系统调用例子用户程序中使用C库中的函数malloc 函数free 函数srccpy 函数open 函数brk 系统调用open 系统调用7 of 31系统统如何响应调应调 用的?系统调 用函数中的int$0x80汇编 指令,会产生向量为128 的异常。内核通过查 中断向量表找到128号异常对应 的处理程 序系统调 用处理程system_call()如何找到对应对应 的内核函数?system_call()利用系统调 用号查系统调 用表sys_call_table,找 到对应 每个系统调 用号的处理函数。8 of 31实验9 of 31一、实验目的一、实验目的学习如何产生一个系统调用往内核中 添加一个新的函数实现对用户空间的读写理解、掌握Linux系统调用的实现框架、用户界面、 参数传递、进入/返回过程。10 of 31二、主要实验环境二、主要实验环境Linux环境:CentOS 6.0,linux kernel 2.6.32.71欲编译内核:linux-2.6.35.13命令uname r11 of 31三、实验指导三、实验指导获得内核源代码www.kernel.org,本次下载的内核版 本为2.6.35.13将内核源码保存到/usr/src目录下cd /usr/srctar xjvf linux-2.6.35.13.tar.bz2tar zxvf linux-2.6.35.13.tar.gz定义系统调用编号和修改系统调用表12 of 311)系统调用表系统调用表sys_call_table存储了所有系统调用 对应的服务例程的函数地址。u对于X86 32位体系结构的系统调 用表位于 arch/X86/kernel/syscall_table_32.S文件中定义。u系统调 用服务例程的名字均遵守一定的规则 :系统调 用名称 前增加“sys_”前缀,比如open系统调 用对应 sys_open函数。u可以使用man 2 syscalls浏览 所有系统调 用的添加历史13 of 31系统调 用表位置cd /usr/src/linux-2.6.35.13/arch/x86/kernelvi syscall_table_32.S第n个表项对应项对应 了系统调统调 用号为为n的服务务例程的入口地址的指 针针修改系统调 用表:将.long sys_my_new_call添加到 arch/x86/kernel/syscall_table_32.S中最后一行14 of 312 2)系统调用号)系统调用号 /arch/x86/include/asm/unistd_32.h 每个系统调用号都是唯一的,依次对应sys_call_table 中的一项,系统调用号写在unistd.h文件中,以 “_NR_”开头。内核通过系统调用号作为下标去获取sys_call_table中 的服务例程函数地址。系统调用号一旦分配就不能再有任何变更,系统运行 中即使该系统调用被删除,它所拥有的系统调用号也 不能被回收利用。15 of 31对于对于3232位位x86x86架构系统调用号位于架构系统调用号位于 arch/x86/include/asm/unistd_32.harch/x86/include/asm/unistd_32.h16 of 314.4.编译内核的方法编译内核的方法make mrproper make clean make oldconfig make all make modules_install make install 命 令“make all”用于生成期望的内核映像及模块; “make modules_install”将安装模块到 “默认目录/lib/module/”下面; “make install”最终将内核映像等几个文件复制到“/boot”目录,并 修改引导程序的配置以启用该新内核。17 of 31以上命令执行完毕后,会在当前目录下生成一个名为 System.map的文件,会在/usr/src/linux-版本号 /arch/i386/boot/下生成一个bzImage文件和vmlinuz文件。cd /boot (进入/boot目录)18 of 315.5.修改引导程序修改引导程序GRUBGRUBcd /boot /grubvi menu.lst为了以后能直接操作菜单,可把menu.lst文件中hiddenmenu那一行注释掉(前加#)或删除,并且可以根据需要设置其中的default和timeout的值,分别表示默认启动项及等待时间。19 of 31# hiddenmenu default=0 timeout=15 splashimage=(hd0,0)/grub/splash.xpm.gz title centos (2.6.35.13) root (hd0,0) kernel /vmlinuz-2.6.35.13 ro root=/dev/mapper/vg_wufeifei- lv_root initrd /initramfs-2.6.35.13.imgtitle centos (2.6.32-71.el6.i686) root (hd0,0) kernel /vmlinuz-2.6.32-71.el6.i686 ro root=/dev/mapper/vg_wufeifei-lv_root20 of 31rebootreboot重启系统就可以看到重启系统就可以看到GRUBGRUB菜单已菜单已 经包含了新编译的内核经包含了新编译的内核选择新编译的内核启动系统。可用uname r 测试当前内 核版本号。任务完成后也可修改/boot/grub/menu.1st文件 中移去不需要的引导内核信息21 of 31测试小例子:测试小例子:在现有的系统中添加一个传递数值参数的在现有的系统中添加一个传递数值参数的 系统调用。这个系统调用的功能打印传入内核的参数。系统调用。这个系统调用的功能打印传入内核的参数。主要内容:在系统调用表中添加相应表项添加系统调用号sys_my_sys_call的实现编写用户态测试程序22 of 31在系统调用表中添加或修改相应表项在系统调用表中添加或修改相应表项在2.6.35.13的内核下,只需要修改 arch/x86/kernel/syscall_table_32.S.long sys_rt_tgsigqueueinfo/* 335 */ .long sys_perf_event_open .long sys_recvmmsg .long sys_my_new_call /* 338 */ .long sys_pedagogictime /* 339 */23 of 31添加系统调用号添加系统调用号系统调用号在文件unistd_32.h里面定义 这个文件在kernel2.6.35.13位于 /arch/x86/include/asm/unistd_32.h。现在我们在 unistd.h中添加我们的系统调用号: _NR_my_new_call , 如下所示: #define _NR_rt_tgsigqueueinfo335 #define _NR_perf_event_open336 #define _NR_recvmmsg337 #define _NR_my_new_call 338 #define _NR_pedagogictime 33924 of 31sys_my_new_callsys_my_new_call函数实现函数实现cd /usr/src/linux-2.6.35.13/kernel 添加一个打印输入值的系统调用 vi sys.c上面在系统调用表中指明了系统调用号 _NR_my_new_call对应的系统调用服务例程是 sys_my_new_call25 of 31重新编译内核。成功后,重启。此时,在启动 项中有2.6.32和2.6.35两个选项,其中新的内核是 2.6.35。选择它并进入系统。至此,我们已经成功添 加了一个自己的系统调用。编译成功之后编写用户 空间程序进行测试testcall.c #include int main() syscall(338,50); /*338是新添加的系统调用号,50是参 数*/return 0; 终端编译 gcc a o testcall 运行 ./a 查看结果 :终端运行命令dmesg 会看到在最后一行输出 call number is 5026 of 31问题问题A A设计并实现一个新的内核函数pedagogictime(),该函 数通过使用一个引用参数的调用返回当前的系统时间。如 果flag的参数为TRUE,内核就把当前的系统时间打印输出 int pedagogictime (int flag,struct timeval * tv) 新函数基本和gettimeofday()类似 cd /usr/src/linux2.6.35.13/kernel vi time.c添加实现代码27 of 31#include #include #includeasmlinkage int sys_pedagogictime(int flag,struct timeval*tv) if(tv)struct timeval ktv; do_gettimeofday( if(copy_to_user(tv, if(flag=true)printk(“tv.sec:%ldn“,(*tv).tv_sec); return 0; 28 of 31问题问题B B编写用户空间程序来测试pedagogictime()的执行情况#include #include int main() struct timeval tv; tv.tv_sec=10; syscall(339,1, printf(“user first get tv_secn”,tv.tv_sec); printf(“now sleep 10 secondsn”); sleep(10); printf(“use
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号