在Linux 32位代码中,“int 0x80”和“syscall”哪个更好?

76

我研究了Linux内核并发现针对x86_64架构,中断int 0x80不能用于调用系统调用1

对于i386架构(32位x86用户空间),更适合使用syscallint 0x80?为什么?

我使用的是Linux内核版本3.4。


注脚1:int 0x80在某些情况下可以在64位代码中工作,但不建议使用。 如果在64位代码中使用32位int 0x80 Linux ABI会发生什么?


你在内核的哪里看到了int 0x80的使用?能具体指出一些文件吗? - Mike
@Mike 实际上,我找到了一个关于 Linux 内核的教程,其中使用了它作为示例。它是基于 2.6 版本的。 - Alex
类似于 https://dev59.com/cWnWa4cB1Zd3GeqPzVEJ 的问题。 - Basile Starynkevitch
我认为 int 0x80 直接在 x86-64 内核上向后兼容。而英特尔手册指出,在32位模式下 syscall 是无效的。 - Ciro Santilli OurBigBook.com
1
自我补充:syscall 在 AMD 实现中是有效的,只有在 Intel 实现中无效:http://stackoverflow.com/questions/29783896/why-does-syscall-compile-in-nasm-32-bit-output-while-popa-does-not-compile-in-64 - Ciro Santilli OurBigBook.com
我对这个问题的答案是“冰淇淋”。首先,“更好”是主观的。其次,你甚至没有定义一个标准,让其他人可以评估“更好”的标准。这是一个无用的问题。而且它得到了一堆只比问题略微有用的答案。 - Omnifarious
3个回答

102
  • syscall 是在 x86-64 上进入内核模式的默认方式。但是这条指令在 Intel 处理器的 32 位操作模式下不可用。
  • sysenter 是在 32 位操作模式下最常用于调用系统调用的指令。它与 syscall 类似,但使用起来稍微困难一些,不过这是内核的问题。
  • int 0x80 是一个遗留的调用系统调用的方式,应该避免使用。

调用系统调用的首选方式是使用 vDSO,它是每个进程地址空间中映射的一部分内存,允许更有效地使用系统调用(例如,在某些情况下根本不需要进入内核模式)。相对于传统的 int 0x80 方式,vDSO 还可以处理更困难的 syscallsysenter 指令。

此外,请参见 此文此文


5
选择一个系统调用方式优于另一个的建议是给操作系统内核开发者的。他们的选择会成为ABI的一部分,如果你正在为某个操作系统开发程序,你必须遵守该ABI。例如,Linux/i386使用int 0x80并将参数传递到寄存器中,而MirBSD/i386使用int 0x80并将参数传递到栈中,并在其中加入一个帧指针(这意味着使用cdecl时在用户空间没有设置成本)。[这个答案主要是给被引导到这里来但不是操作系统内核设计者的人们。] - mirabilos
2
这个问题涉及到Linux,回答描述了在Linux(i386和x86_64)上调用系统调用的可能方法。你认为Linux/i386只使用int 0x80,但这是不正确的。更好的方式是使用VDSO来进行系统调用。 - Paweł Dziepak
相关:如果在64位代码中使用32位int 0x80 Linux ABI会发生什么?。(它“可以工作”,但只能使用寄存器的低32位,因此无法与64位指针一起使用。) - Peter Cordes
1
VDSO仅适用于32位x86。 我认为x86-64 glibc直接使用syscall ABI,除了像clock_gettime()getpid()这样的系统调用,在VDSO中导出用户空间实现。 - Peter Cordes

25

我的回答 在这里 涵盖了你的问题。

实际上,最近的内核正在实现一个VDSO,尤其是为了动态优化系统调用(内核将VDSO设置为适合当前处理器的某个代码)。 因此,您应该使用VDSO,并且最好使用libc提供的接口来使用现有的系统调用。

请注意,据我所知,简单系统调用的大部分成本都是从用户空间到内核空间再返回。 因此,对于某些系统调用(可能包括gettimeofdaygetpid等),VDSO甚至可以避免这种情况(并且从技术上讲,可能避免进行真正的系统调用)。 对于大多数系统调用(例如openreadsendmmap等),系统调用的内核成本足够大,以至于任何改进从用户空间到内核空间转换的方法(例如使用SYSENTERSYSCALL机器指令而不是INT)都不重要。


22
回到 80386 处理器时代,进入内核最快的方式实际上是执行一个无效指令。 - Adam Rosenfield
@AdamRosenfield是您要链接的正确博客文章“寻找更快的系统调用陷阱”吗?您的链接已经失效了... - Ruslan
@Ruslan:是的,就是那个链接。Raymond Chen的博客在去年进行了迁移,很多像这样的旧链接都失效了。 - Adam Rosenfield

9

问题是关于在32位模式下使用syscall,其中它调用32位ABI(仅在AMD CPU上可能,并且与64位用户空间版本的行为不同)。但是,是的,64位syscall ABI在调用号码和调用约定方面不同。 - Peter Cordes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接