库函数与系统调用 系统调用可以解释为操作系统为用户提供的一些接口,这些接口提供了对系统硬件功能的操作。这样说大家可能还有点抽象,我再举一个更具体的例子:比如我要写一个程序,这个程序的功能就是在屏幕上显示一个字符串“hello,world!”。那么实现这么一个在屏幕上显示一个字符串的操作就是系统调用write()的功能。
那么系统调用的意义在哪里呢? 你想想看,你写一个程序还需要自己去实现在屏幕上打印字符串的代码,这也太累人了吧,,因此系统调用把我们从底层的硬件编程中解放了出来。再者,系统调用是内核代码,内核代码能访问系统上的所有地址空间,而我们执行的代码是用户空间的代码,用户空间的代码在对系统进行操作时是有限制的,(作为一个菜鸟程序员,系统如果不对你写的代码进行限制,,万一把系统搞蹦了呢。。)。因此系统调用的另一个功能就是维护了系统的安全性,,你要用就直接调用我这个接口就行了,,不用你自己写。系统调用还有一个功能就是为了方便程序的移植性。。 总之,你就把系统调用当做一个接口,什么时候你需要使用它了,调用一下它就行了,既方便又安全。。 你可能会有疑问,我们平时在写C语言时打印一个字符串不是用PRintf()函数吗?这个printf()跟前面提到的那个系统调用write()有什么区别呢?问对了。 其实你可以把库函数当做是对系统调用的又一次封装。。什么意思呢?系统调用作为内核提供给我们的接口,它的执行效率是比较高效精简的。但是有时候我们需要对获取的信息进行更复杂的处理,这个时候如果我们把这些处理过程包装成一个函数再提供给程序员,不是更方便编程了吗?因此一个库函数有可能含有一个系统调用,有可能有好几个系统调用,当然也有可能没有系统调用,比如有些操作就不需要涉及内核的功能。 总之,库函数是面向程序员的应用编程接口。看一下下面这张图也许更明白了它们之间的关系: 说完了库函数和系统调用之间的关系,下面我们来看看系统调用到底是怎么运行的。 当一个进程正在运行时,遇到读写文件什么的,此时会发生一个中断,中断发生后,系统会把当前用户进程的一些寄存器信息保存在内核堆栈中(以备将来恢复),接着去执行中断服务程序,我们这里是去执行系统调用,linux中通过执行int $0x80来执行系统调用的中断,但是内核实现了很多系统调用,所以进程必须指明需要哪个系统调用,这时候就需要传递一个系统调用号。这个系统调用号就存放在%eax寄存器中。 下面我们通过一个例子来说明:我们这里这个程序用来显示当前的时间。 首先我们通过库函数来实现: 结果如下:成功获得当前时间。 接下来我们通过嵌入汇编语言来实现系统调用: 发现没?首先通过mov $0xd %%eax来将系统调用号放入%eax寄存器中,通过查阅,发现time()的系统调用号是13。这个时候通过执行int $0x80,系统就会去执行time()这个系统调用了。 查看结果: 看,依然能够获得系统的时间! 这里涉及的很多知识可能大家都不太看得懂,没关系,我们后面会详细介绍!这篇博客的目的是让大家理解库函数和系统调用的区别,以及系统调用的大致执行方式。