在旧版本的 Linux 架构中,系统调用在执行过程中总会生成中断。它们的执行方式是将系统调用号放入 %eax,将参数放入 %ebx、%ecx 等,然后发出特定的中断 int 0x80。因此,可以说系统调用是系统中软件中断的常见原因。
然而,在现代 x86_64 架构上,有一个特定的系统调用指令“syscall”,它完全不需要使用中断 0x80,因此也不需要中断描述符表。虽然我相信以前为 syscall 生成中断的方法仍然受支持,但 syscall 指令似乎是实际使用的方式。
因此,我的问题是:系统调用产生中断的说法不再正确了吗?例如,系统调用是否仍会增加 vmstat 的“中断”列输出中显示的数字?
答案1
是的,Linux x86_64 的现代 C 代码使用 syscall 指令,例如参见 glibc sysdeps/unix/sysv/linux/x86_64/syscall.S。不,这并不意味着由于兼容性,系统调用中断会消失。
https://www.kernel.org/doc/Documentation/x86/entry_64.txt
x86 架构有多种跳转到内核代码的方式。大多数入口点都在 arch/x86/kernel/traps.c 中注册,并在 arch/x86/entry/entry_64.S(64 位)、arch/x86/entry/entry_32.S(32 位)以及最后的 arch/x86/entry/entry_64_compat.S(实现 32 位兼容性系统调用入口点)中实现,从而为 32 位进程提供在 64 位内核上运行时执行系统调用的能力。
IDT 向量分配在 arch/x86/include/asm/irq_vectors.h 中列出。
其中一些条目如下:
system_call:来自 64 位代码的系统调用指令。
entry_INT80_compat:来自 32 位或 64 位代码的 int 0x80;无论如何都是 compat 系统调用。
entry_INT80_compat、ia32_sysenter:32 位代码中的 syscall 和 sysenter
对于只读系统调用(gettimeofday),vDSO 根本不会进入内核模式。
系统调用可以通过几种方式进行分析,例如 ftrace 或 eBPF。除了在 64 位模式下已过时之外,中断还会因系统调用以外的原因而发生。