226 views
首页 > 内核编程 > SYSENTER/SYSEXIT 指令

SYSENTER/SYSEXIT 指令

2010年5月25日

在 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指令执行步骤如下:

  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代码

参考:
《软件调试》 张银奎 8.3.3节
ia32 intel architecture software developer manuals 指令卷2 sysenter/sysexit部分

free2000fly 内核编程 ,

  1. tom
    2010年7月24日12:29 | #1

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

  1. 目前还没有任何 trackbacks 和 pingbacks.