为什么存在系统调用表而不只是附加到中断向量表中?我不明白这里的设计选择。如果它可以提高区分事件的性能,那么为什么不系统调用呢?
答案1
我还没有研究在 i386 上使用单个中断(0x80)进行系统调用背后的历史背景,有几个原因不是对各个系统调用使用单独的软件中断。
- 软件中断的数量是有限的,这限制了系统调用的数量(并且在x86上,许多中断描述符表条目需要用于其他目的)。现在的系统调用数量超出了大多数使用软件中断的架构所能支持的数量。
- 相当多的体系结构具有专用的系统调用指令,它们不使用软件中断(或其等效物)。这包括 x86-64、其中专用
SYSCALL
指令提供比软件中断更快的系统调用访问。man 2 syscall
提供了每种体系结构的系统调用约定的详细信息。
如果您查看 ARM/OABI 架构的详细信息,您可能会觉得那里使用了中断表,因为系统调用号已编码在指令中;但相应的指令执行固定的软件中断,忽略编码的数字,系统调用处理程序从指令本身检索该数字。 EABI 放弃了这种方法,因为它会导致缓存污染(较新的 ARM CPU 具有单独的指令和数据缓存)。
答案2
其一,x86(-64) 支持256 个条目的中断表,其中一些用于实际的硬件中断。从 开始计数手册页syscalls(2)
在这里,Linux 上有超过 400 个不同的系统调用。可能并非所有架构都存在,但根据另一个清单,x86-64 上有 314 个不同的系统调用(0 到 313)。因此,至少对于 x86 上的 Linux,似乎没有办法为每个系统调用保留不同的中断号。
当然,x86 并不是唯一的架构。其他人可能有更少的可用软件中断,或者有完全不同的系统调用路径,与硬件中断分开。事实上,现代的x86(-64),已经有了这样一条单独的路径,通过SYSCALL 和 SYSENTER 指令:
SYSENTER/SYSEXIT 指令(以及 AMD 上的等效 SYSCALL/SYSRET)可快速进入内核,避免中断开销。
仅使用内核的单个入口点的另一个可能原因是与用户空间/内核切换相关的任何强制安排,独立于特定的系统调用。也许需要保存某些状态,或者需要切换堆栈。任何此类任务都将再次取决于架构和系统设计的特定功能,但如果需要执行此类任务,则在一个地方完成它们可能会更容易。 (特别是因为这样的低级任务可能需要成为首先要做的事情,然后才能在新上下文中进行函数调用。)
请注意,上面的大部分内容几乎只是猜测,我对任何非 x86 架构一点也不熟悉(除了一些不运行通用操作系统的架构),也没有看过 Linux 系统调用实现如此紧密,更不用说其他操作系统了。如果您需要更多底层细节,我希望其他人能够提供。