SYSENTER/SYSEXIT 指令
在 x86 下,以前的系统调用都是通过 int 指令来发出,然后跳转到内核中的服务例程。但 int 指令执行时要做一些不必要的安全检查,而且因为系统调用是系统内被调用最频繁的地方,因此采用 int 指令会影响系统的性能。
这时 Intel 和 AMD 就专门设计了系统调用指令来代替以前的 int 指令。
Intel 中采用的指令是 SYSENTER/SYSEXIT , AMD 中采用的指令是 SYSCALL/SYSRETURN.
下面我简单的描述一下 Intel 下的 SYSENTER/SYSEXIT 指令的执行前提和执行过程。
准备工作:
1. 在调用 SYSENTER 指令进行系统调用时,需要在 GDT 中建立四个段,分别用来描述 SYSENTER 指令进入内核模式时使用的代码段 (CS) 和栈段 (SS), 以及 SYSEXIT 指令从内核模式返回用户模式时使用的代码段 (CS) 和栈段 (SS)。这四个描述符在 GDT 表中的排列应该严格按照以上顺序,这样只要指定一个段描述符的位置便能计算出其他的。
2. 设置下表中专门用于系统调用的 MSR 寄存器(使用 WRMSR 指令来设置这些寄存器):
| MSR | Address |
| IA32_SYSENTER_CS | 174H |
| IA32_SYSENTER_ESP | 175H |
| IA32_SYSENTER_EIP | 176H |
- IA32_SYSENTER_CS 寄存器保存了内核代码段的描述符的 index。
- IA32_SYSENTER_EIP 寄存器保存了内核里的快速系统调用分发例程的线性地址。
- IA32_SYSENTER_ESP 寄存器保存了内核里能获得本地 TSS 描述符的基地址. (只有这样, 进入内核态后才能正确的设定 esp 为正确的值)
sysenter指令执行步骤如下:
- 将IA32_SYSENTER_CS保存到CS中
- 将IA32_SYSENTER_EIP保存到EIP中
- 将IA32_SYSENTER_CS + 8 保存到SS中
- 将IA32_SYSENTER_ESP保存到ESP寄存器中
- 切换到ring 0级别
- 如果EFLAGS中的VM标志被设定,那么清0该标志
- 开始执行ring0代码
下面再说说 sysexit
这条指令执行前需要如下准备工作:
- 设置 EDX 为 ring3 下要执行的指令的首地址
- 设置 ECX 为 ring3 下的栈指针
sysexit指令的执行步骤如下:
- 将IA32_SYSENTER_CS + 16保存到CS中。(ring3下代码段)
- 将EDX赋值给EIP
- 将IA32_SYSENTER_CS + 24保存到SS中
- 将ECX赋值给ESP
- 切换到ring3下继续执行ring3代码
参考:
《软件调试》 张银奎 8.3.3节
ia32 intel architecture software developer manuals 指令卷2 sysenter/sysexit部分

sysenter还将清除中断标志。
sysexit对eflags没有影响。