Linux如何提取系统调用的第六个参数?

时间:2015-12-07 12:49:59

标签: linux x86 system-calls

在32位Intel架构中,mmap2系统调用有6个参数。第六个参数存储在ebp寄存器中。但是,在通过sysenter进入内核之前,会发生这种情况(在linux-gate.so.1中,内核映射到用户进程的代码页):

push %ebp
movl %esp, %ebp
sysenter

这意味着ebp现在应该有堆栈指针的内容而不是第六个参数。 Linux如何正确获取参数?

1 个答案:

答案 0 :(得分:2)

您在评论中链接的blog post有一个链接to Linus's post,它为我提供了答案的线索:

  

这意味着现在内核可以很高兴地将%ebp作为其中的一部分   第六个参数设置,因为系统调用重新启动将重新初始化   它要指向%ebp 中我们需要的用户级堆栈,因为   否则就完全迷失了。

     

我是一头令人作呕的猪,并以此为荣。

     

- Linus Torvalds

事实证明sysenter 设计要求用户空间与内核合作以保存返回地址和用户空间堆栈指针。 (进入内核后,%esp将成为内核堆栈。)它比int 0x80更少的东西,这就是为什么它的速度更快。

进入内核后,内核在%esp中拥有用户空间的%ebp值,无论如何都需要它。它从用户空间堆栈内存访问第6个参数,以及SYSEXIT的返回地址。输入后,(%ebp)立即拥有第6个系统调用参数。来自迈克尔的评论:"这里是32-bit sysenter_target code:看看从第417行开始的部分"

来自英特尔SYSENTER的指令参考手册条目( wiki中的链接):

  

SYSENTER和SYSEXIT指令是配套说明,但是   它们不构成呼叫/返回对。执行SYSENTER时   指令,处理器不保存状态信息   用户代码(例如,指令指针),以及SYSENTER   SYSEXIT指令也不支持在堆栈上传递参数。   使用SYSENTER和SYSEXIT指令作为配套指令   用于特权级别3代码和特权级别0之间的转换   操作系统程序,必须遵循以下约定   如下:

     
      
  • 特权级别0代码和的段描述符   堆栈段和特权级别3代码和堆栈段   必须在描述符表中连续。这个惯例允许   处理器根据输入的值计算段选择器   SYSENTER_CS_MSR MSR。

  •   
  • 快速系统调用“存根”例程   由用户代码执行(通常在共享库或DLL中)必须   如果a,保存所需的返回IP和处理器状态信息   需要返回调用过程。同样,操作   用SYSENTER指令调用的系统或执行程序必须   有权访问并使用此保存的返回和状态信息   返回用户代码。

  •