学习重点——系统调用
以下图示表示x86 32位机器的进程内存

中断处理的过程
Linux系统调用通过中断向量0x80实现
int 0x80,中断保存了用户态CS:EIP的值,及当前堆栈段寄存器的栈顶(注意在这里的栈顶是用户栈的栈顶,入栈到内核栈),EFLAGS寄存器的当前值保存到内核堆栈。利用int指令将系统调用的中断服务程序的入口加载在CS:EIP中。
iret回到原来的状态。
系统调用的意义是操作系统为用户态进程与硬件设备之间进行交互提供了一组接口。
操作系统的主要功能是为管理硬件资源和为应用程序开发人员提供良好的环境来使应用程序具有更好的兼容性,为了达到这个目的,内核提供一系列具备预定功能的多内核函数,通过一组称为系统调用(system call)的接口呈现给用户。系统调用把应用程序的请求传给内核,调用相应的的内核函数完成所需的处理,将处理结果返回给应用程序
系统调用的库函数就是我们使用的操作系统提供的API,系统调用是通过软中断向内核发出中断请求,int指令触发中断请求。
libc函数库内部定义的一些API内部就使用了系统调用的封装历程。
每个系统调用对应一个系统调用的封装例程,函数库再使用这些封装例程定义给出程序员可以调用的API一个API可能只对应一个系统调用,也可能由多个系统调用实现。

如上图所示,在用户态中
xyz()函数属于API函数SYSTEMCALL就是一个系统调用的封装例程由操作系统给,出会触发int $0x80中断在内核态中
system_call对应内核代码的起点,即中断向量0x80对应的终端服务程序的入口sys_xyz()系统调用处理函数
ret_from_sys_calliret返回用户态继续执行system_call这是中断的入口函数也是内核代码的起点。xyz()和系统调用内核函数sys_xyz()
利用上面的代码实现的是查看当前进程的pid和其父进程的pid,首先是利用库函数提供的API实现查看。下面是运行结果。

将上面的调用API转换成内嵌汇编代码的方式。通过查找可以看到对应的操作系统给出的系统调用的封装对应的系统调用号



下面对汇编代码解释其含义
movl $0,%%ebx\n\t表示传入参数,这里不需要传递参数,就将EBX寄存器清零
movl $0x14,%%eax\n\tEAX用于传递系统调用号,表示这里调用的是20号系统调用。
int $0x80\n\t是触发系统调用陷入内核执行20号系统调用的内核处理函数
movl %eax,%0\n\t系统调用会有一个返回值,通过EAX寄存器返回。
这样就完成了系统调用。

当libc没有提供某个系统调用的封装,可以利用libc提供的syscall函数直接调用


2018-2019-1 20189206 《Linux内核原理与分析》第五周作业
原文:https://www.cnblogs.com/zz-1226/p/9922000.html