系统调用大体过程:
1、应用程序调用库函数(API);
2、API 将系统调用号存入 EAX,然后通过中断调用使系统进入内核态;
3、用户栈ss:sp压入内核栈,待会返回。
4、内核中的中断处理函数根据系统调用号,调用对应的内核函数(系统调用);涉及到调用就会压栈。
5、系统调用完成相应功能,将返回值存入 EAX,返回到中断处理函数;
6、中断处理函数返回到 API 中;
7、API 将 EAX 返回给应用程序。
以pc为线索看系统调用原理(忽略压栈)
1、PC是对cs:ip的称呼,cs是代码段寄存器,ip为指针寄存器,对于CS:IP要知道:可以确定下一条指令的内存地址,CS的后两位记录当前特权级,特权级只能被INT0X80修改。
2、GDT表(全局描述表)记录了所有内存段(大小不等)的特权级DPL(内核为0,用户为3)。PC要访问指令所在内存,就要看自己CS中的当前特权级CPL是否小于等于要访问内存段的DPL。通过硬件的配合,实现了内核段与用户段的隔离。用户态不能JMP到内核,也不能MOV内核段中的东西。
3、用户可通过系统调用(或其它中断)来进入内核。系统调用是通过中断INT 0X80进入内核的。使用系统调用的C库函数write,会被展开成:eax=4; INT 0X80;。INT 0X80所在段DPL为3,可被用户态访问,且它可以修改CS中的CPL为0,以此进入内核段。
之后利用eax经过在内核中的函数调用,可以找到系统调用号对应得函数。执行系统调用。