“Linux内核分析”实验四
系统调用(上)
作者:何振豪
原创作品转载请注明出处 http://www.cnblogs.com/scoyer/p/6556391.html
《Linux内核分析》MOOC课程 http://mooc.study.163.com/course/USTC-1000029000
看了一些关于系统调用的博客和资料,感觉受益匪浅!
Linux的运行模式分为内核态和用户态,我们使用操作系统的时候一般在用户态,当我们需要使用系统功能的时候,例如创建文件,创建进程等,需要申请资源,这时候系统就切换内核态帮助我们执行,其中OS接受请求,就会利用系统调用帮助我们实现这个请求。
更专业一点的定义:系统调用是操作系统提供给用户与硬件进行交互的一层接口。
为什么需要系统调用呢?
1.让操作系统检查请求合法性,保证操作系统的正常运作;
2.给用户提供方便,毕竟谁也不想一直使用汇编进行编程;
先科普一些相关术语:
什么是封装例程(wrapper routine)?
在标准C库函数中,为每个系统调用设置了一个封装例程,当一个用户程序执行一个系统调用的时候,就会调用C函数中的相对应的封装例程。
什么是服务例程(service routine)?
实际上系统调用只是一个接口,所需要的系统功能由内核函数去执行,这些执行系统功能的内核函数就是服务例程。
以getpid函数为例,简单说是系统调用执行getpid函数时,详细一点就是在用户态执行模式调用getpid这个封装例程,利用系统调用进入内核态执行sys_getpid服务例程。
实验的前置知识:想要用汇编进行系统调用的话,需要设置好相应的参数到寄存器中,eax使用来存放系统调用号,每个内核函数都有唯一的编号,实现不同的功能,系统调用号列表可以参考:
http://codelab.shiyanlou.com/xref/linux-3.18.6/arch/x86/syscalls/syscall_32.tbl
此外ebx,ecx,edx,esi,edi都是用来存放需要的参数的,假设需要的参数如果大于六个的话,那么需要传的是内存的地址,将参数存放在内存中。设置好参数之后,需要使用中断指令进行系统调用,系统的调用的结果会返回到eax寄存器。
理论知识介绍完就开始进行实验了,这次实验要做的是使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用。
我要实现的系统调用是24号服务例程getuid,这个函数返回的是进程所在的用户id,很简单的一个函数。
下面是c代码:
下面是相应的汇编代码:
执行结果如下图所示:
上面这两个函数执行结果一样,说明调用的是同一个服务例程。
总结
下面简单描述一下系统调用的过程,这一节先粗略一讲,后面在进行详细叙述每个过程:
1.应用程序调用一个封装例程;
2.封装例程里面产生软中断,开始系统调用;
3.通过系统调用切换到内核态,调用服务例程;
4.调用完毕,关闭中断,返回系统调用;
5.从系统调用退出,从内核态切换到用户态;
用下述图片说明:
参考资料(推荐):