当调用system_call函数时,它应该检查一些参数并根据eax中传递的参数调用系统调用表中指向的函数。这是保存寄存器的部分:
system_call:
pushl %eax
SAVE_ALL
movl $0xffffe000, %ebx /* or 0xfffff000 for 4-KB stacks */
andl %esp, %ebx
为什么它会两次保存eax? (在命令pushl%eax和宏SAVE_ALL中也保存eax)。
答案 0 :(得分:1)
x86-32上的标准C调用约定使用%eax
从函数返回值。 Linux系统调用还将其返回值传递回%eax
中的用户空间。如何在x86-32上完成?
arch/x86/entry/entry_32.S
中的系统调用入口点调用系统调用处理函数,然后覆盖存储的%eax
(由SAVE_ALL
存储的值)堆栈及其返回值。之后,当返回到用户空间时,所有寄存器的存储值将从堆栈弹出到寄存器中。由于%eax
存储的SAVE_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
!