第十章,系统级I/O(续)
系统调用(System Call)是操作系统为在用户态运行的进程与硬件设备(如CPU、磁盘、打印机等)进行交互提供的一组接口。当用户进程需要发生系统调用时,CPU 通过软中断切换到内核态开始执行内核系统调用函数。下面介绍Linux 下三种发生系统调用的方法:glibc函数库、syscall直接调用、int指令陷入。
通过 glibc 提供的库函数
glibc 是 Linux 下使用的开源的标准 C 库,它是 GNU 发布的 libc 库,即运行时库。glibc 为程序员提供丰富的 API(Application Programming Interface),除了例如字符串处理、数学运算等用户态服务之外,最重要的是封装了操作系统提供的系统服务,即系统调用的封装。
- 通常情况,每个特定的系统调用对应了至少一个 glibc 封装的库函数,如系统提供的打开文件系统调用
sys_open
对应的是 glibc 中的open
函数; - 其次,glibc 一个单独的 API 可能调用多个系统调用,如 glibc 提供的
printf
函数就会调用如sys_open
、sys_mmap
、sys_write
、sys_close
等等系统调用; - 另外,多个 API 也可能只对应同一个系统调用,如glibc 下实现的
malloc
、calloc
、free
等函数用来分配和释放内存,都利用了内核的sys_brk
的系统调用。
使用 syscall 直接调用
使用上面的方法有很多好处,首先你无须知道更多的细节,如 chmod 系统调用号,你只需了解 glibc 提供的 API 的原型;其次,该方法具有更好的移植性,你可以很轻松将该程序移植到其他平台,或者将 glibc 库换成其它库,程序只需做少量改动。
但有点不足是,如果 glibc 没有封装某个内核提供的系统调用时,我就没办法通过上面的方法来调用该系统调用。如我自己通过编译内核增加了一个系统调用,这时 glibc 不可能有你新增系统调用的封装 API,此时我们可以利用 glibc 提供的syscall
函数直接调用。
sysno 是系统调用号,每个系统调用都有唯一的系统调用号来标识。在 sys/syscall.h
中有所有可能的系统调用号的宏定义。
- ... 为剩余可变长的参数,为系统调用所带的参数,根据系统调用的不同,可带0~5个不等的参数,如果超过特定系统调用能带的参数,多余的参数被忽略。
- 返回值 该函数返回值为特定系统调用的返回值,在系统调用成功之后你可以将该返回值转化为特定的类型,如果系统调用失败则返回 -1,错误代码存放在
errno
中。
通过 int 指令陷入
如果我们知道系统调用的整个过程的话,应该就能知道用户态程序通过软中断指令int 0x80
来陷入内核态(在Intel Pentium II 又引入了sysenter
指令),参数的传递是通过寄存器,eax 传递的是系统调用号,ebx、ecx、edx、esi和edi 来依次传递最多五个参数,当系统调用返回时,返回值存放在 eax 中。
grep -nr xxx /usr/include
n表示显示行号,r表示递归,include含义为只查找xxx内容的php。
利用grep -nr来查找对象里的个别字符或者指定内容。
参考资料
hazir的博客
Linux系统指令查询
问题
我的虚拟机出现了点问题,打不开了;在这个人的博客里看到了很多有用的东西,以上过半的指令及其运用并不能够理解,可能需要老师和同学再做讲解。