当system_call函数被调用时,它应该检查一些参数并根据eax传入的参数调用系统调用表中指向的函数。这是保存寄存器的部分:

system_call: 
pushl %eax 
SAVE_ALL 
movl $0xffffe000, %ebx /* or 0xfffff000 for 4-KB stacks */ 
andl %esp, %ebx 

为什么它保存 eax 两次? (在命令 pushl %eax 和保存 eax 的宏 SAVE_ALL 中)。

请您参考如下方法:

x86-32 上的标准 C 调用约定使用 %eax从函数返回一个值。 Linux 系统调用也将它们的返回值传递回用户空间 %eax .这是如何在 x86-32 上完成的?
arch/x86/entry/entry_32.S 中的系统调用入口点调用系统调用处理函数,然后覆盖 %eax 的存储值(由 SAVE_ALL 存储的)及其返回值在堆栈中。稍后,当返回用户空间时,所有寄存器的存储值都会从堆栈中弹出到寄存器中。自 %eaxSAVE_ALL 存储的值被期望的返回值覆盖,当用户代码恢复执行时,自然会在%eax中找到系统调用的返回值。 .

但是有时内核需要找到%eax的原始保存值。 .即使 SAVE_ALL 保存的值已经被覆盖了,还是可以查看第一个pushl %eax保存的值.在内核代码中,这个值被称为orig_eax . (grep 内核源代码,你会在几个地方找到它。)

RESTORE_REGS宏在 arch/x86/entry/entry_32.S你会看到它需要一个 pop参数,用于在将所有保存的寄存器值弹出回寄存器后调整堆栈。你会发现 RESTORE_REGS 4就在系统调用返回用户空间的时候。那个“4”是为了摆脱 pushl %eax 插入的值。您询问的,也称为 orig_eax !


评论关闭
IT序号网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!