内核资料收集
系统调用处理程序及服务例程
1. 执行过程:
当用户的进程调用一个系统调用时,CPU切换到内核态并开始执行一个内核函数。在x86体系结构中调用linux系统调用时,最终结果都是跳转到所谓系统调用处理程序(system call handler)的汇编语言函数
2. 关于参数:
由于内核实现了很多不同的系统调用,因此进程必须传递一个名为系统调用号的参数,来识别所需的系统调用,x86系统结构中的eax寄存器就用作此目的。系统调用通常还需要传递其它的参数。
3. 关于返回值:
所有的系统调用都返回一个整数值。此返回值与封装例程返回值的约定是不同的。在内核中,0表示系统调用成功结束。负数表示一个出错条件。在后一种情况下,这个值就是存放在errno变量中,必须返回给应用程序的负出错码。内核没有设置或使用errno变量,而封装例程从系统调用返回之后设置这个变量。
4. 程序结构:
系统调用处理程序与其它异常处理程序的结构类似,执行以下操作:
a.在内核态栈保存大多数寄存器的内容(此操作对所有系统调用通用,用汇编语言编写)
b.调用名为系统调用服务例程(system call service routine)的相应C函数来处理系统调用
c.退出系统调用处理程序:用保存在内核栈中的值加载寄存器,CPU从内核态切换回到用户态(所有系统调用都用此相同操作,该操作用汇编语言编写)
xyz()系统调用的对应的服务例程通常是sys_xyz(). 不过也有例外。
下图显示系统调用/相应封装例程/系统调用处理程序/系统调用服务例程之间的关系。
箭头表示函数之间的执行流。占位符“SYSCALL”和“SYSEXIT”是真正的汇编语言指令,它们分别把CPU从用户态切换到内核态和从内核态切换到用户态。
5. 系统调用号与服务例程
内核利用一个存放在sys_call_table数组中的系统调用分派表,将系统调用号与相应的服务例程关联起来。NR_syscalls个表项,第n个表项包含系统调用号为n的服务例程的地址。NR_syscalls宏只是对可实现的系统调用最大个数的静态限制,并不代表实际已实现的系统调用个数。分派表中任意一个表项也可以包含sys_ni_syscall()函数的地址。此函数 是“未实现”系统调用的服务例程,它仅仅返回出错码-ENOSYS。
阅读(875) | 评论(0) | 转发(0) |