一、简介
sysenter 指令可用于特权级 3 的用户代码调用特权级 0 的系统内核代码,而 SYSEXIT 指令则用于特权级 0 的系统代码返回用户空间中。sysenter 指令可以在 3,2,1 这三个特权级别调用(Linux 中只用到了特权级 3),而 SYSEXIT 指令只能从特权级 0 调用。
sysenter/sysexit 和 int n/iret 指令的一个区别,那就是 sysenter/sysexit 指令并不成对,sysenter 指令并不会把 SYSEXIT 所需的返回地址压栈,sysexit 返回的地址并不一定是 sysenter 指令的下一个指令地址。
二、执行步骤
sysenter指令执行前的准备工作
1. 在调用SYSENTER指令进行系统调用时,需要在GDT中建立四个段,分别用来描述SYSENTER指令进入内核模式时使用的代码段(CS)和栈段(SS),以及SYSEXIT指令从内核模式返回用户模式时使用的代码段(CS)和栈段(SS)。这四个描述符在GDT表中的排列应该严格按照以上顺序,这样只要指定一个段描述符的位置便能计算出其他的。
2. 设置下图中专门用于系统调用的MSR寄存器(使用WRMSR指令来设置这些寄存器):
IA32_SYSENTER_CS 寄存器保存了内核代码段的描述符的index。
IA32_SYSENTER_EIP 寄存器保存了内核里的快速系统调用分发例程的线性地址。
IA32_SYSENTER_ESP 寄存器保存了内核里能获得本地TSS描述符的基地址。(只有这样,进入内核态后才能正确的设定esp为正确的值)
sysenter指令执行步骤如下:
1. 将IA32_SYSENTER_CS保存到CS中。
2. 将IA32_SYSENTER_EIP保存到EIP中。
3. 将IA32_SYSENTER_CS + 8 保存到SS中。
4. 将IA32_SYSENTER_ESP保存到ESP寄存器中。
5. 切换到ring 0级别。
6. 如果EFLAGS中的VM标志被设定,那么清0该标志。
7. 开始执行ring0代码。
这sysexit指令执行前需要如下准备工作:
设置EDX为ring3下要执行的指令的首地址。设置ECX为ring3下的栈指针。
sysexit指令的执行步骤如下:
1. 将IA32_SYSENTER_CS + 16保存到CS中。(ring3下代码段)
2. 将EDX赋值给EIP
3. 将IA32_SYSENTER_CS + 24保存到SS中。
4. 将ECX赋值给ESP。
5. 切换到ring3下继续执行ring3代码。
转载自: http://hi.baidu.com/taozpwater/item/98529bf681f9ebc6521c2677