在Linux2.6.11的Sysenter fast系统调用过程中,VDSO Package 器在进入Ring0之前使用pushl %EBP; MOVL %ESP, %EBP
,表示使用了带EBP的用户态度栈地址https://elixir.bootlin.com/linux/v2.6.11/source/arch/i386/kernel/vsyscall-sysenter.S#L19
内核堆栈,ESP(即用户状态堆栈的地址)在后续进程中被压入内核堆栈,但随后在sysenter
入口点中出现了MOVL (%EBP), %EBP
。(https://elixir.bootlin.com/linux/v2.6.11/source/arch/i386/kernel/entry.S#L192)
此时EBP寄存器不应该指向内核堆栈吗?或者有其他解释吗?
我的理解是这个EBP还是指向用户栈的,此时的方法是将EBP指向用户栈中断前的状态。
1条答案
按热度按时间vlju58qv1#
EBP仍然指向用户空间栈,内核入口点还没有修改它,这就是为什么
mov (%ebp), %ebp
前面的注解说“从用户栈加载潜在的第六个参数”。EBP是
int 0x80
ABI中传递第6个参数的位置。这也是为什么在sysenter
推送EBP之前运行的用户空间VDSO代码,然后将ESP复制到EBP,因此1.内核可以恢复用户空间堆栈指针,2.因此内核有一个指针指向那个不适合寄存器的参数。(6个参数加上EAX中的调用号)sysenter
itself覆盖ESP(使用MSRIA32_SYSENTER_ESP
中的固定值)。Linux选择使用sysenter入口点中的加载来获取当前任务的内核堆栈,而不是在每次上下文切换时更新MSR。无论哪种方式,ESP的用户空间值都会被覆盖。这种堆栈切换功能就是为什么只有在内核加载新ESP之后才会重新启用中断(
sti
)的原因(sysenter
清除IF,在执行任何内核指令之前禁用中断)。这就是为什么EBP不能保存第6个系统调用参数;sysenter入口点的ABI将其视为用户空间堆栈指针,堆栈顶部的项是第6个参数。