汉扬编程 编程大纲 Linux系统编程003-系统调用、API、标准C库

Linux系统编程003-系统调用、API、标准C库

Linux系统编程003-系统调用、API、标准C库

1 系统调用概述

Linux系统编程003-系统调用、API、标准C库

计算机系统的各种硬件资源比较有限,运行在操作系统之上的多个进程都需要访问这些资源,并且试图独占这些资源。如果进程都能随心所欲地问这些资源,冲突再所难免,系统塴溃就会时常产生。

Linux系统编程003-系统调用、API、标准C库

所以为了更好地管理,操作系统是不能允许进程直接操作这些硬件资源的。进程如果要想访问这些资源,必须向操作系统申请。进程向操作系统申请的入口就是系统调用(System Call),它由操作系统提供。

在linux中系统调用是用户空间访问内核的唯一手段,除异常和陷入外,他们是内核唯一的合法入口。

2 API/POSIX/标准C库的区别与联系

API,应用程序接口(Application Programming Interface)。是一些按照约定来预先定义的接口,衔接软件系统不同组成部分,相当于一个中间件。在《Linux系统编程学习001-架构、内核概要》中提到过:在Linux中进行系统编程,当以进程为视角。所以,在Linux中,可以理解API就是Application Process Interface。

上面说过的Linux系统调用,是内核中实现的功能十分强大的一系列的函数。是操作系统为用户态运行的进程和内核态管理的硬件设备(如CPU、磁盘、打印机等)进行交互提供的一组接口。也就是说,Linux系统调用就是设置在应用程序和硬件设备之间的一个服务层。因此可以说系统调用,是操作系统留给用户程序的一个接口,这个接口以API的形式向应用提供。

一般情况下应用程序通过应用编程接口API来编程,而不是直接通过系统调用来编程。

POSIX是一种标准,它的全称是可移植操作系统接口(Portable Operating System Interface)。在Unix/Linux世界,最流行的API是基于POSIX标准的,基于内核系统调用,为了人们编程的方便,以C语言函数的形式,供进程使用。

虽说Linux平台上的API是以C函数形式包装的。但它不是标准C语言函数库。

API是系统调用的接口,它是系统级API,它形成的函数集,也称系统C库。内部调用system call内核例程,力图向进程屏蔽内核复杂的细节。比如open/read/werite,内部会调用内核的sys_open/sys_read/sys_write。

标准C语言库函数,简称C库,是ANSIC标准的C函数集。可以理解它是用户级的API。替用户写好函数,方便调用,使程序员可以将焦点放在设计程序逻辑上面,而不必再编写繁琐、重复的程序,不必关注技术的细节。比如fopen()、fread()、fwrite()等等,它们内部调用对应的API函数(open/read/write)来实现。

其实,在实际使用过程中,很少有人刻意去区分哪些函数属于标准C语言库,哪些属于系统C库的,都通称C库函数。只需要明白这些函数,哪些有底层系统内核调用功能就可以了。当然,ANSI C的上层C函数,最好不要与系统内核提供的底层API C函数混用。

3 系统调用API函数与内核函数区别

系统调用API是用户进入内核的接口层。系统调用API本身并非内核函数,但是它由内核函数实现。比如read()函数不是内核函数,但它内部是调sys_read()函数实现的,再往内核更深层次,可能调用是虚拟文件系统函数vfs_read。

进入内核后,不同的系统调用会找到各自对应的内核函数,这些内核函数被称为系统调用“服务例程”。如系统调用getpid实际上调用的服务例程为sys_getpid(),或者说系统调用getpid()是服务例程sys_getpid()的封装例程。

API(以C函数的形式提供)调用是语言或者应用程序的一部分,而系统内核调用则是操作系统的一部分。

4 系统调用API函数与普通函数调用

系统调用API是内核函数面向进程调用的包装接口,也同普通函数一样是C函数形式包装的。

用户程序运行起来后,进程调用API后,有的API函数在用户空间,如一些数学计算函数,不需要使用系统调用。有的运行在内核空间,因为它们使用了系统调用system call。

普通函数永远运行在用户空间。

5 系统调用的过程

操作系统一般是通过中断从用户态切换到内核态。中断就是一个硬件或软件请求,要求CPU暂停当前的工作,去处理更重要的事情。中断有两个重要的属性,中断号和中断处理程序。中断号用来标识不同的中断,不同的中断具有不同的中断处理程序。在操作系统内核中维护着一个中断向量表(Interrupt Vector Table),这个数组存储了所有中断处理程序的地址,而中断号就是相应中断在中断向量表中的偏移量。

一般地,系统调用都是通过软件中断实现的,x86系统上的软件中断由int $0x80指令产生,而128号异常处理程序就是系统调用处理程序system_call(),它与硬件体系有关,在entry.S中用汇编写。

Linux系统下有300多个系统调用,中断号明显是一种稀缺资源,不可能每一个系统调用都对应一个中断号。int $0x80指令产生中断后,系统会把API的函数名称转换成系统调用号传入中断处理程序,同时把参数传到中断处理程序。

如上图所示,进程调用C标准库函数printf(),printf又调用系统API write()函数,通过int 0x80中断调用system_call中断处理,系统调用就开始产生。

内核维护一张系统调用表,sys_call_table,表中的元素是系统调用函数的起始地址,而系统调用号就是系统调用在调用表的偏移量。在x86上,系统调用号是通过eax寄存器传递给内核的。通过查表sys_call_table,找到sys_write开始执行。

本文来自网络,不代表汉扬编程立场,转载请注明出处:http://www.hyzlch.com/mianfei/6697.html

站在祖师爷尼古拉斯•威茨的肩上,看编程世界

C\\C++语言4|表达式与运算符

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注

返回顶部