当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
存储的)及其返回值在堆栈中。稍后,当返回用户空间时,所有寄存器的存储值都会从堆栈中弹出到寄存器中。自 %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
!