本系列文章由张同浩编写,转载请注明出处:http://blog.csdn.net/muge0913/article/details/7517303
邮箱:muge0913@sina.com
一般情况下,用户进程是不能访问内核空间的。它既不能访问内核中的数据,也不能访问内核中的函数。但在linux内核中设置了一组用于实现各种系统功能的函数,成为系统调用。用户可以在应用程序中调用它们。
linux系统还提供了一些c库,这些库对系统调用进行了一些包装和扩展。
系统调用,POSIX,C库,系统命令和内核函数
1、系统调用和POSIX
虽然系统调用是内核和用户空间的桥梁,但是用户的应用程序在访问内核时是通过系统提供的应用编程接口API来实现的。
操作系统的API主要作用是把操作系统的功能全展现出来,提供给应用程序。
在UNIX中最通用的操作系统API是基于POSIX(Portable Operating System ofUNIX)标准的。后来从UNIX发展来的版本各种各样,以至于给应用程序移植带来了很大的不便。为了结束这个局面IEEE制定了POSIX标准,提高UNIX环境下的用户程序移植性。POSIX标准不局限于UNIX,很多其他的操作系统也支持该标准如DEC OpenVMS和WindowNT。linux系统兼容POSIX标准,提供了根据POSIX而定义的API函数。这些函数和系统调用有着直接 的关系。一个API函数可以用一个系统调用实现,也可以多个系统调用来实现。同时不用系统调用来实现。
2、系统调用和c库
操作系统的API通常又有C库的方式来提供,linux也是如此。c库提供了兼容POSIX的绝大数API。内核提供的每个系统调用在c库中都有相应的函数封装。而且系统调用名和c库中封装的函数名往往相同。如read
c库中封装的函数在调用系统调用之前,一般只做一点工作。如系统调用truncate和truncate64在库中封装的truncate决定到底调用哪个系统调用。
封装的函数和系统调用不是一一对应关系。有的封装函数甚至不调用任何的系统调用如strcpy和atoi
3、系统调用和系统命令
系统命令是c库的更上层。是利用c库实现的应用程序。如ls命令。
strace可以跟踪系统调用。
4、系统调用和内核函数
可以认为系统调用时内核函数的一部分。
5、系统调用表:
系统调用表sys_call_table存储了所有系统调用对应的服务例程函数的地址。
在x86中:2.6.38/arch/x86/kernel/syscall_table_32.S
在arm中2.6.38/arch/arm/kernel/calls.S
6、系统调用号:每个系统调用对应一个唯一的系统调用号。用户通过系统调用号,而不是名称来调用。
x86:2.6.38/arch/x86/include/asm/unistd32.h或unistd64.h
arm:2.6.38/arch/arm/include/asm/unistd.h能找到它们。
内核是通过系统调用号作为下表去sys_call_table来获取服务例程的地址的。在系统中系统调用号一旦分配就不能去除,这是为了兼容。
7、系统调用例程
所有的系统调用服务例程都声明在include/linux/syscalls.h中,但分散在不同的文件中。
asmlinkagelong sys_nice(int increment);
系统调用除了sys_外还有一个asmlinkage来告诉编译器从堆栈中获取参数。还必须有一个long的返回,表示执行成功还是出错。系统调用号,名称和目的都是相同的,但是在不同内核和架构中实现的方法可能不同。
8、如何使用系统调用
1、通过c库来使用系统调用
2、在2.6.18之前的内核使用_syscall宏来使用系统调用。
3、在2.6.19开始废除了_syscall,而使用syscall()通过向函数提供调用号和参数实现调用