系统调用的工作机制

谈起系统调用,不得不提一下Linux下对文件操作的两种方式:系统调用(system call)和库函数调用(Library functions)。系统调用实际上就是指最底层的一个调用,在Linux程序设计里面就是底层调用的意思,面向的是硬件。而库函数调用则面向的是应用开发的,相当于应用程序的API,采用这样的方式有很多种原因,第一:双缓冲技术的实现;第二,可移植性;第三,底层调用本身的一些性能方面的缺陷;第四:让API也可以有了级别和专门的工作面向。

接下来我用一个简单的实验,即使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用来给大家展示下系统调用的工作机制:

首先编写一个简单的C语言函数,其中包含了API函数getpid(),


然后再将它编译成可执行文件,并运行。



这时我们看到了系统调用后的结果,显示了process pid:5185。

接下来,我们再用C代码中嵌入汇编代码来实现系统调用,以下是程序截图,此处有点小问题,第一步应该是把寄存器ebx清零,系统调用的第一个参数是通过寄存器ebx来传递的,因为getpid()函数没有调用参数,所以需将寄存器ebx清零。

同样再把它编译成可执行文件,并运行。


我们可以看到,这段程序同样也可以完成系统调用,显示结果为process pid:14477。

关于为什么两个显示结果会不一样,在此做个说明,因为计算机在不同时刻执行的进程是不一样的,所以显示的结果当然也是不同的进程号了。

接下来我们重点分析下这段汇编代码:

"mov $0, %%ebx\n\t"    //这个指令是把寄存器ebx清零;

"mov $0x14,  %%eax\n\t"   //然后把系统调用号0x14放到寄存器eax中;

"int $0x80\n\t"    //这个指令是执行系统调用,类似于DOS中的int  21h;

"mov %%eax, %0\n\t"  //把系统调用之后的返回值(此返回值存放在寄存器eax中)放入到参数pid中;

:"=m"(pid)    //"="表示操作数在指令中是只写的,"m"表示内存变量,这条指令表示将pid的值写入到内存中,而不是寄                       存器中;

);

这里要注意的是系统调用号是由寄存器eax来传递的。

最后我们来谈谈系统调用的过程,首先看下系统调用的过程,


首先我们需要在用户态时将系统调用号放入到寄存器eax中,再由指令int 0x80进行系统调用,然后进入到内核态,以我的实验为例,在内核态就会由sys_getpid函数来完成相关的功能,并将返回值返回到寄存器eax中,然后退出内核态系统调用,再退出内核态返回到用户态。

实验总结:

关于系统调用的工作机制,我们可以看到,系统调用可以用API函数直接调用或者在C语言中嵌入汇编代码来进行调用,但两者的本质是一样的,都需要使用系统调用号,只不过API函数已经把系统调用号封装起来了,与内核系统调用形成了映射关系。


                                      作者: 叶涛

《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ”







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值