请参见https://elixir.bootlin.com/linux/v5.0.21/source/arch/x86/entry/entry_64.S#L168。
从以上链接复制:
ENTRY(entry_SYSCALL_64)
UNWIND_HINT_EMPTY
/*
* Interrupts are off on entry.
* We do not frame this tiny irq-off block with TRACE_IRQS_OFF/ON,
* it is too small to ever cause noticeable irq latency.
*/
swapgs
/* tss.sp2 is scratch space. */
movq %rsp, PER_CPU_VAR(cpu_tss_rw + TSS_sp2)
SWITCH_TO_KERNEL_CR3 scratch_reg=%rsp
movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp
/* Construct struct pt_regs on stack */
pushq $__USER_DS /* pt_regs->ss */
pushq PER_CPU_VAR(cpu_tss_rw + TSS_sp2) /* pt_regs->sp */
pushq %r11 /* pt_regs->flags */
pushq $__USER_CS /* pt_regs->cs */
pushq %rcx /* pt_regs->ip */
GLOBAL(entry_SYSCALL_64_after_hwframe)
pushq %rax /* pt_regs->orig_ax */
PUSH_AND_CLEAR_REGS rax=$-ENOSYS
TRACE_IRQS_OFF
...
PUSH_AND_CLEAR_REGS
的调用不会更改RAX。实际上,它是少数未被宏清除(设置为0)的通用寄存器之一。由于RAX保留正在调用的系统调用的系统调用号,因此其值保持不变。在您显示的代码之后,该代码立即作为第一个参数传递给do_syscall_64
。
设置为-ENOSYS
的是RAX在堆栈上的保存值。即,宏不保存RAX的实际值,而是保存-ENOSYS
。当系统调用返回时,除非-ENOSYS
将其更改为其他值,否则RAX中的值将设置为do_syscall_64
。如果输入的RAX值不是有效的系统调用号码,则可以这样做,因此do_syscall_64
可以简单地返回,而输出的RAX将为-ENOSYS
,表明系统调用无效。