作者:xujianguo
原创作品转载请注明出处,《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
——————————————————————————————————————————————————————-————
实验目的:
通过gdb调试和编译c文件及汇编嵌入的文件来加强理解系统调用的过程和思想。
实验环境:
实验楼:www.shiyanlou.com和putty。
实验步骤:
1.配置环境,登录实验楼网站。
由于自身原因,先采用putty登录,测试,结果中途断开连接;然后使用360浏览器来完成。
2.改后的源代码如下:
3.编译和测试程序是否正确。
4.利用gdb并采用如下命令来测试和调试。
$gcc -g -m32 -o fopen fopen.c $gdb fopen -q (gdb)layout split (gdb)b main (gdb)b fopen (gdb)r test
试验结果图如下:
设置open和main处断点。
5.利用汇编代码嵌入,测试:
- asm volatile(
- "mov $0,%%ebx "
- "mov %1,%%ebx "
- "mov %2,%%ecx "
- "mov $0x5,%%eax "
- "int $0x80 "
- "mov %%eax,%0 "
- :"=m"(fd)
- :"b"(fn),"c"(O_RDWR|O_CREAT)
-
);
6.按照前面的方式完成调试。
实验分析:
实验参考资料:
http://codelab.shiyanlou.com/xref/linux-3.18.6/arch/x86/syscalls/syscall_32.tbl
根据老师的课程资料和视频,系统调用是操作系统为用户态进程与硬件设备进行交互所提供的接口,其优势是减少用户在底层硬件的编程的时间耗费,甚至解放出来;分离客户和内核,可以保证系统的安全性;提供软件的可用性与可移植性。
在Linux系统中,glibc封装例程(wrapper routine),定义用户调用的API(每一系统调用对应一个封装例程,由封装例程定义API);由系统调用号来连接API和内核服务程序。
基本图例:
系统调用具体过程:
- 应用程序调用系统提供的API(eg:xyz)。
-
CPU切换到内核态,并调用执行相应的内核函数。
-
如果需要传递参数,见下图,参数过多,是以指令的方式存在;通过int指令来匹配调用系统调用程序。
- 内核中的服务处理程序根据系统调用号调用对应的系统调用;如需进程调度,还会调用相关进程调度服务。
- 系统完成相应功能,将返回值存入eax,返回到服务处理函数。
- 服务处理函数返回到API中。
- API将eax,即系统调用的返回值返回给相应的应用程序。
】
总结:
linux系统系统调用主要由封装例程提供API来完成,其靠C库支持。用户程序通过包含标准头文件并和C库链接,就可以使用系统调用(或者调用库函数,再由库函数实际调用)。Linux本身提供了一组宏,用于直接对系统调用进行访问。它会设置好寄存器并调用陷人指令。这些宏是_syscalln(),其中n的范围从0到6。代表需要传递给系统调用的参数个数,这是由于该宏必须了解到底有多少参数按照什么次序压入寄存器。内核在执行系统调用的时候处于进程上下文。current指针指向当前任务,即引发系统调用的那个进程。当系统调用返回的时候,控制权仍然在system_call()中,它最终会负责切换到用户空间并让用户进程继续执行下去。
参考资料:
1.老师的视频和ppt
2.https://git.oschina.net/exiahan/LinuxKernelStudy/blob/master/4/asmSCI.md