(2009-12-27)
一、实验背景
操作系统的主要功能是为应用程序的运行创建良好的环境,为了达到这个目的,内核提供一系列具备预定功能的多内核函数,通过一组称为系统调用(system call)的接口呈现给用户。系统调用把应用程序的请求传给内核,调用相应的的内核函数完成所需的处理,将处理结果返回给应用程序,如果没有系统调用和内核函数,用户将不能编写大型应用程序。读者熟知的系统调用例子有:进程控制的fork、exit等,文件系统操作的open、close、read、write等,网络套接口的bind、accept、send、recv、sendto、recvfrom等。
二、实验目的
学习Linux内核的系统调用,理解、掌握Linux系统调用的实现框架、用户界面、参数传递、进入/返回过程。阅读Linux内核源代码,通过添加一个简单的系统调用实验,进一步理解Linux操作系统处理系统调用的统一流程。
三、实验内容
在现有的系统中添加一个不用传递参数的系统调用。调用这个系统调用,使用户的uid变成0。实验主要内容:
(1)添加系统调用的名字
(2)利用标准C库进行包装
(3)添加系统调用号
(4)在系统调用表中添加相应表项
(5)sys_mysyscall的实现
(6)编写用户态测试程序
四、实验步骤
(一)重建Linux内核
(1)下载内核源代码压缩包:linux-2.6.20.tar.gz,下载地址:http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.20.tar.gz。然后将压缩包放到/usr/src目录下。
(2)进入/usr/src目录:cd /usr/src,然后解压内核包:tar zxvf linux-2.6.20.tar.gz,这样生成的内核源代码就在linux-2.6.20目录中了。
(3)进入内核代码目录:cd linux-2.6.20,执行命令:make mrproper,确保该目录下没有相关文件和配置。
(4)执行命令:make menuconfig,配置内核模块的功能。主要做了以下几项配置:选中所有支持ext3文件系统的配置项编译进内核(如图1所示);选择SCSI device support的部分功能编译进内核(如图2、图3所示)。
图1 将ext3文件系统的功能选项编译进内核
图2 将SCSI disk support功能编译进内核
图3 将SCSI low-level drivers下的BusLogic SCSI support编译进内核
(5)编译内核,执行命令:make。
(6)编译和安装内核模块,执行命令:make modules_install。
(7)安装内核,执行命令:make install。
(8)清除编译时的临时文件,执行命令:make clean。
(9)重新启动Linux操作系统。
(二)添加系统调用
(1)进入新内核源代码所在目录:cd /usr/src/linux-2.6.20。
(2)进入unistd.h文件所在目录:cd include/asm。再进入unistd.h文件对之进行编辑:vi unistd.h。在unistd.h里面添加自己的系统调用号:__NR_mysyscall,如图4所示:
图4 添加系统调用号__NR_mysyscall
(3)进入系统调用表文件所在目录:
cd /usr/src/linux-2.6.20/arch/i386/kernel,然后进入系统调用表文件对之进行编辑:vi syscall_table.S。在该文件中添加与我们定义的系统调用号相应的表项sys_mysyscall,如图5所示:
图5 添加系统调用表项sys_mysyscall
(4)系统调用的实现。进入内核代码目录下的kernel目录:
cd /usr/src/linux-2.6.20/kernel,然后进入其下的sys.c文件:vi sys.c,将系统调用实现函数sys_mysyscall(void)添加到sys.c中,该系统调用实现的功能是遍历输出进程,如图6所示:
图6 系统调用实现函数sys_mysyscall(void)
(5)按照(一)中所述重建Linux内核的方法重新编译安装内核,然后重新启动Linux操作系统。
(6)编写用户态测试程序test.c来测试我们新添的系统调用,程序如图7所示:
图7 用户态测试程序test.c
编译程序:gcc –o test test.c,运行程序:./test。
五、实验结果和分析
(一)重建Linux内核实验结果
(1)执行make命令后的结果,如图8所示:
图8 执行make后的结果
(2)执行make_modules_install命令后的结果,如图9所示:
图9 执行make_modules_install后结果
(3)执行make_install命令后的结果,如图10所示:
图10 执行make_install后结果
(4)重启Linux操作系统后显示的选择内核版本界面,表示重建内核成功,如图11所示(原lInux版本是2.4.20):
图11 选择内核版本
(二)添加系统调用测试结果
运行test后,由于mysyscall系统调用中的printk函数输出的信息在/var/log/messages文件中,所以打开该文件就可以看到运行结果了,如图12所示:
图12 运行结果
六、遇到的问题和解决方法 (1)在第一次执行make后,出现下列错误: make[1]:***No rule to make target ‘|’,needed by ‘firmware/keyspan/usa19qi.fw.S’.Stop. make:***[firmware] Error 2 对于此错误,执行下列编译命令:make bzImage,刚才的错误消失,取而代之的是下列错误: OBJCOPY arch/i386/boot/compressed/vmlinux.bin BFD: Warning: Writing section‘.bss' to huge (ie negative) file offset 0xc0277000. objcopy: arch/i386/boot/compressed/vmlinux.bin: File truncated make[2]: *** [arch/i386/boot/compressed/vmlinux.bin] Error 1 make[1]: *** [arch/i386/boot/compressed/vmlinux] Error 2 make: *** [bzImage] Error 2 解决方法是:在arch/i386/Makefile里面做一些修改:将OBJCOPYFLAGS所在那一行改成如下的: OBJCOPYFLAGS :=-O binary --change-section-lma .bss-0xc0000000 –R .note -R .comment –S 改完后无论用make bzImage还是make都能编译成功。 (2)make install时报错:No module BusLogic found for kernel 2.6.20,解决方法是在/etc/modules.conf中删除BusLogic的加载项,即把下列这行注释掉:alias scsi_hostadapter BusLogic。此后make install就能成功了。 (3)当添加系统调用功能实现完后,重新编译内核时,执行make install时出现如下错误:All of your loopback devices are in use.mkinitrd failed,这时可能由于笔者还在2.6.20内核下编译,因为修改完一个版本的内核不能马上就在该版本下编译自己,所以重启系统进入原来的2.4.20-8内核下编译改后的2.6.20内核,然后make install成功。