【Linux学习笔记】Linux/UNIX系统调用详解(资料整理)
2015-07-09 20:09
627 查看
当我们执行了一个函数,这个函数到底在系统里面完成了哪些工作呢?函数是按照怎样的路线执行呢??
不看不知道,一看吓一跳!这几天翻看一些书籍资料,整理了一下Linux系统调用方面的内容,以此与诸君共勉!
首先,说一下内核。系统内核是管理和分配计算机资源的的核心层软件。(ps: 一般情况下,Linux内核可执行文件存储在/boot/路径下,文件名一般以 “vmlinuz+内核版本号” 命名。末尾的z表示内核是经过压缩的可执行文件)
内核的主要任务有:任务调度;内存管理;文件系统管理;进程管理;设备管理;网络管理;提供系统调用应用编程接口(API)。
这里我们说一下最后一个功能---提供系统调用API,由于内核的管理功能,外围软件和标准库函数的作用,让我们很难接触到内核层。为我们提供了极大地方便,同时也造成我们可能对系统内核根本一无所知。
其实,当我们在执行prinf(“Hello World!\n”);的时候,系统就要由用户态切换到内核态工作了。
下面,是几点系统调用方面需要注意的地方:
1、系统调用将处理器从用户态切换到内核态,以便CPU访问到受保护的内核内存。
2、系统调用的组成是固定的,每个系统调用都由一个唯一的数字(以名称方式呈现给我们)来标识。
3、每个系统调用可辅之以一套参数,对用户空间(进程的虚拟地址空间)与内核空间之间传递的信息加以规范。
接下来,详细说明一下系统调用的详细步骤:
1、当我们在程序中调用某些函数时,应用程序会通过调用库函数中的外壳函数,发起系统调用。
2、对于系统调用中断处理来说,外壳函数必须保证所有的系统调用参数可用。通过堆栈,这些参数传入外壳函数,但内核却希望将这些参数置入特定寄存器。因此,外壳函数会将上述参数复制到寄存器。
3、由于所有系统调用进入内核的方式相同,内核需要设法区分每个系统调用。为此,外壳函数会将系统调用编号复制到一个特殊的CPU寄存器(%eax)中。
4、外壳函数执行一条中断机器指令(int 0x80,2.6.x内核之后都支持更快的sysenter指令了),让处理器从用户态切换到内核态,并执行系统中断0x80的中断矢量所指向的代码。
5、为了响应中断0x80,内核会调用system_call()例程(在内核汇编文件arch/i386/entry.S中)处理这次中断,具体步骤如下:
a) 在内核栈中保存寄存器值;
b) 审核系统调用编号的有效性;
c) 以系统调用编号对存放所有系统调用服务例程的列表(内核变量sys_call_table)进行索引,发现并调用相应的系统调用服务例程。若系统调用服务例程带有参数,则首先检查参数的有效性。随后该服务例程会执行必要的任务,可能涉及到对特定参数中指定地址处的值得修改,以及在用户内存和内核内存之间传递数据。最后,该服务例程会将结果状态返回给system_call()例程。
d) 从内核栈中恢复各寄存器值,并将系统调用返回值置于栈。
e) 返回至外壳函数,同时将处理器切换回用户态。
6、若系统调用服务的返回值表明调用有误,外壳函数会使用该值来设置全局变量errno。然后,外壳函数会返回到调用函数,并同时返回一个整型值,以表明系统调用是否成功。(PS: 在linux中,系统调用服务成功返回非负值,失败返回相应errno的取反值。库函数会再次对errno的负值取反得到非负的errno,同时用-1作为外壳函数的返回值,表示调用程序出错。)
总算告一段落,下面以系统调用execve()为例,展示了系统调用的执行路径!
MISSION SUCCESS ......
不看不知道,一看吓一跳!这几天翻看一些书籍资料,整理了一下Linux系统调用方面的内容,以此与诸君共勉!
首先,说一下内核。系统内核是管理和分配计算机资源的的核心层软件。(ps: 一般情况下,Linux内核可执行文件存储在/boot/路径下,文件名一般以 “vmlinuz+内核版本号” 命名。末尾的z表示内核是经过压缩的可执行文件)
内核的主要任务有:任务调度;内存管理;文件系统管理;进程管理;设备管理;网络管理;提供系统调用应用编程接口(API)。
这里我们说一下最后一个功能---提供系统调用API,由于内核的管理功能,外围软件和标准库函数的作用,让我们很难接触到内核层。为我们提供了极大地方便,同时也造成我们可能对系统内核根本一无所知。
其实,当我们在执行prinf(“Hello World!\n”);的时候,系统就要由用户态切换到内核态工作了。
下面,是几点系统调用方面需要注意的地方:
1、系统调用将处理器从用户态切换到内核态,以便CPU访问到受保护的内核内存。
2、系统调用的组成是固定的,每个系统调用都由一个唯一的数字(以名称方式呈现给我们)来标识。
3、每个系统调用可辅之以一套参数,对用户空间(进程的虚拟地址空间)与内核空间之间传递的信息加以规范。
接下来,详细说明一下系统调用的详细步骤:
1、当我们在程序中调用某些函数时,应用程序会通过调用库函数中的外壳函数,发起系统调用。
2、对于系统调用中断处理来说,外壳函数必须保证所有的系统调用参数可用。通过堆栈,这些参数传入外壳函数,但内核却希望将这些参数置入特定寄存器。因此,外壳函数会将上述参数复制到寄存器。
3、由于所有系统调用进入内核的方式相同,内核需要设法区分每个系统调用。为此,外壳函数会将系统调用编号复制到一个特殊的CPU寄存器(%eax)中。
4、外壳函数执行一条中断机器指令(int 0x80,2.6.x内核之后都支持更快的sysenter指令了),让处理器从用户态切换到内核态,并执行系统中断0x80的中断矢量所指向的代码。
5、为了响应中断0x80,内核会调用system_call()例程(在内核汇编文件arch/i386/entry.S中)处理这次中断,具体步骤如下:
a) 在内核栈中保存寄存器值;
b) 审核系统调用编号的有效性;
c) 以系统调用编号对存放所有系统调用服务例程的列表(内核变量sys_call_table)进行索引,发现并调用相应的系统调用服务例程。若系统调用服务例程带有参数,则首先检查参数的有效性。随后该服务例程会执行必要的任务,可能涉及到对特定参数中指定地址处的值得修改,以及在用户内存和内核内存之间传递数据。最后,该服务例程会将结果状态返回给system_call()例程。
d) 从内核栈中恢复各寄存器值,并将系统调用返回值置于栈。
e) 返回至外壳函数,同时将处理器切换回用户态。
6、若系统调用服务的返回值表明调用有误,外壳函数会使用该值来设置全局变量errno。然后,外壳函数会返回到调用函数,并同时返回一个整型值,以表明系统调用是否成功。(PS: 在linux中,系统调用服务成功返回非负值,失败返回相应errno的取反值。库函数会再次对errno的负值取反得到非负的errno,同时用-1作为外壳函数的返回值,表示调用程序出错。)
总算告一段落,下面以系统调用execve()为例,展示了系统调用的执行路径!
MISSION SUCCESS ......
相关文章推荐
- 《coredump问题原理探究》Linux x86版7.8节vector相关的iterator对象
- Linux/Unix下pid文件作用浅析
- Linux rpm 命令参数使用详解[
- CentOS6.5的安装
- Linux命令之权限与命令的关系
- Linux的时间设置与同步(NTP)
- 悟 -- 如何做到高效产出,结合Linux 服务器开发的感悟
- Linux下samba的安装与配置
- Linux绘制图形
- Bacula安装(linux上)
- Linux和类Unix系统上5个惊艳的开源备份软件
- CentOS 5下freeswitch中集成使用ekho实现TTS功能
- Linux建立文件目录链接的方法
- linux系统初始化脚本
- Linux中fdisk命令
- CentOS 6.5配置SSH免密码登录
- tar命令解压时如何去除目录结构及其解压到指定目录
- Linux开发中常见段错误问题原因分析
- Linux 下如何处理包含空格和特殊字符的文件名
- 手斧Linux – 从LFS到Funtoo (155)