/系统调用中的 ptregs table

/ptregs in syscall table

为什么系统调用table中的某些系统调用有/ptregs

来自 arch/x86/entry/syscalls/syscall_64.tbl 的示例:

54      64      setsockopt              sys_setsockopt
55      64      getsockopt              sys_getsockopt
56      common  clone                   sys_clone/ptregs
57      common  fork                    sys_fork/ptregs
58      common  vfork                   sys_vfork/ptregs
59      64      execve                  sys_execve/ptregs
60      common  exit                    sys_exit
61      common  wait4                   sys_wait4

这些是特殊的系统调用,需要在堆栈上布置完整的寄存器转储(作为 struct pt_regs)。这只适用于 64 位 x86 架构,因为它有更多的寄存器(与 32 位相比)。

系统调用处理程序 (arch/x86/entry/entry_64.S:entry_SYSCALL_64) 在系统调用入口时将大部分寄存器保存在堆栈中。这样做部分是为了支持 ptrace(),部分是为了将参数传递给用 C 编写的实际系统调用处理程序(这就是为什么他们有 asmlinkage 规范,它使函数从堆栈中获取参数)。系统调用最多有 6 个参数(rdi、rsi、rdx、r10、r8、r9),一些寄存器用于 SYSCALL 簿记(rax、rcx、r11)。您不需要保存 rbp、rbx、r12、r13、r14、r15(因为它们是被调用者保存的),因此出于性能原因它们不会在入口时保存。系统调用处理完成后,寄存器会在返回用户空间之前从此备份中恢复。

但是,有些系统调用(如execve()、fork()、sigreturn()等)需要在栈上有all寄存器(包括rbp、rbx , r12–r15), 在 struct pt_regs。这是因为这些系统调用会导致用户空间从不同的地方重新开始执行,所以它们需要保存准确的寄存器值。它们在 syscall_64.tbl 中用 /ptregs 标记,以便发生以下魔术。

通常系统调用处理程序 table (sys_call_table) 包含指向 C 函数的指针。但是对于那些特殊的系统调用,处理程序是 small assembly thunks,它首先保存额外的寄存器,然后跳转到 C 代码(这就是慢路径所做的)。 table 中的 /ptregs 后缀指示脚本将这些存根而不是 C 函数插入处理程序 table.