当前位置:嗨网首页>书籍在线阅读

05-系统调用

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

1.1.3 系统调用

系统编程始于系统调用,也终于系统调用。系统调用(通常简称为syscall)是为了从操作系统请求一些服务或资源,是从用户空间如文本编辑器、游戏等向内核(系统的核心)发起的函数调用。系统调用范围很广,从大家都熟悉的如read()和write(),到罕见的如get_thread_area()和set_tid_address()都在其范畴之内。

Linux实现的系统调用远远少于其他内核。举例来说,微软的Windows,其系统调用号称有几千个,而Linux x86-64体系结构的系统调用大概只有300个。在Linux内核中,每种体系结构(Alpha、x86-64或PowerPC)各自实现了标准系统调用。因此,不同体系结构支持的系统调用可能存在区别。然而,超过90%的系统调用在所有的体系结构上都实现了。本书所探讨的正是这部分共有的内容。

调用系统调用

位于用户空间的应用程序无法直接访问内核空间。从安全和可靠性角度考虑,也需要禁止用户空间的应用程序直接执行内核代码或操纵内核数据。但从另外一个角度看,内核也必须提供这样一种机制,当用户空间的应用希望执行系统调用时,可以通过该机制通知内核。有了这种机制,应用程序就可以“深入”内核,执行内核允许的代码。这种机制在不同的体系结构上又各不相同。举个例子,在i386微处理器上,用户空间的应用需要执行参数值为0x80的软件中断指令int。该指令会把当前运行环境从用户空间切换成内核空间,即内核的保护区域,内核在该区域执行中断处理函数——中断0x80的处理函数是什么呢?只能是系统调用处理函数!

应用程序通过寄存器告诉内核调用哪个系统调用以及传递什么参数。系统调用以数值表示,从0开始。举个例子,在i386微处理器体系结构上,要请求系统调用5(即open()),用户空间在发送int指令前,需要把5写到寄存器eax中。

参数传递也以类似的方式处理。还是以i386为例,为每个可能的参数指定一个寄存器——寄存器ebx、ecx、edx、esi和edi顺序存储前5个参数。对于极少数参数超过5个的系统调用,则使用单个寄存器指向保存所有参数的用户空间缓存。当然,大部分系统调用只包含几个参数。

虽然基本思想是一致的,但不同体系结构处理系统调用的方式不同。作为一名系统程序员,通常不需要了解内核是如何处理系统调用的。系统调用已经集成到各种体系结构的标准调用规范中,并通过编译器和C库自动处理。