我知道系统调用接口是在低级别上实现的,因此依赖于体系结构/平台,而不是“通用”代码。
然而,我无法清楚地看出为什么 Linux 32 位 x86 内核中的系统调用编号与类似架构 Linux 64 位 x86_64 中的编号不同?这个决定背后的动机/原因是什么?
我的第一个猜测是后台原因是保持 32 位应用程序在 x86_64 系统上运行,以便通过系统调用号的合理偏移,系统可以知道用户空间是 32 位还是 64 位分别。然而事实并非如此。至少在我看来,read()作为x86_64中的系统调用号0不能与这个想法保持一致。
另一个猜测是,更改系统调用号可能具有安全/强化背景,但我自己无法证实这一点。
由于不了解实现依赖于架构的代码部分的挑战,我仍然想知道如何更改系统调用号,当似乎没有必要时(因为即使是 16 位寄存器也会存储比当前约 346 个数字更多的数字来表示所有调用),除了破坏兼容性之外,将有助于实现任何目标(尽管通过库 libc 使用系统调用可以减轻这种情况)。
答案1
至于具体编号背后的原因,它与任何其他架构都不匹配[除了“x32”,它实际上只是 x86_64 架构的一部分]:在 Linux 内核中支持 x86_64 的早期,在有任何严重的向后兼容性限制,所有系统调用都被重新编号在缓存行使用级别对其进行优化。
我对内核开发了解不够,无法知道这些选择的具体依据,但显然有一些选择使用这些特定数字对所有内容进行重新编号背后的逻辑,而不是简单地从现有架构中复制列表并删除未使用的列表。看起来顺序可能取决于它们的调用频率 - 例如读/写/打开/关闭位于前面。 exit 和 fork 可能看起来“基本”,但每个进程只调用一次它们。
将常用的系统调用保留在同一高速缓存行中也可能会发生一些事情(这些值只是整数,但内核中有一个表,其中每个系统调用都有函数指针,因此每组 8 个系统调用占用该表的 64 字节缓存行)
答案2
看那个答案问题“为什么 amd64 linux 中的系统调用号不同?”在堆栈溢出上。
总结一下:为了兼容性,系统调用列表是稳定的,只能增长。当x86 64架构出现时,ABI(参数传递,返回值)有所不同,因此内核开发人员趁机带来了期待已久的改变。
答案3
简而言之,因为有人认为“N+1
无端不相容的做法比N
方法更好”。对于历史架构,通常选择系统调用号来匹配一些遗留的专有 UNIX。但对于 x86_64,内核开发人员可以自由选择他们喜欢的任何编号。他们没有做出简单的选择并重复使用现有的编号,而是选择发明一个新的标准。然后他们又为 aarch64 和其他一些人做了同样的事情。这是 Linux 内核开发中经常重复的模式。