我研究了 Linux 内核,发现对于 x86_64 架构,中断 int 0x80
不适用于调用系统调用1。
对于 i386 架构(32 位 x86 用户空间),哪个更可取:syscall
或 int 0x80
,为什么?
我使用 Linux 内核版本 3.4。
脚注 1:int 0x80
在某些情况下确实适用于 64 位代码,但从不推荐。 What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code?
int 0x80
的内核?你能指定一些文件吗?
int 0x80
直接在 x86-64
内核上工作是为了向后兼容。英特尔手册说 syscall
在 32 位模式下无效。
syscall 是在 x86-64 上进入内核模式的默认方式。此指令在 Intel 处理器的 32 位操作模式下不可用。
sysenter 是最常用于在 32 位操作模式中调用系统调用的指令。它类似于 syscall,虽然使用起来有点困难,但这是内核关心的问题。
int 0x80 是调用系统调用的传统方式,应避免使用。
调用系统调用的首选方法是使用 vDSO,它是映射到每个进程地址空间的内存的一部分,允许更有效地使用系统调用(例如,在某些情况下根本不进入内核模式)。与传统的 int 0x80
方式相比,vDSO 还处理更困难的 syscall
或 sysenter
指令处理。
我的回答 here 涵盖了您的问题。
在实践中,最近的内核正在实现 VDSO,特别是为了动态优化系统调用(内核将 VDSO 设置为一些最适合当前处理器的代码)。所以你应该使用VDSO,对于现有的系统调用,你最好使用libc提供的接口。
请注意,AFAIK,简单系统调用成本的很大一部分是从用户空间到内核并返回。因此,对于某些系统调用(可能是 gettimeofday
、getpid
...),VDSO 甚至可以避免这种情况(并且在技术上可能会避免执行真正的系统调用)。对于大多数系统调用(如 open
、read
、send
、mmap
....),系统调用的内核成本足够大,可以改进用户空间到内核空间的转换(例如,使用SYSENTER
或 SYSCALL
机器指令而不是 INT
) 无关紧要。
更改前请注意:执行 0x80 或 syscall 时系统调用号不同,例如 sys_write 为 4 与 0x80 和 1 与 syscall。
http://docs.cs.up.ac.za/programming/asm/derick_tut/syscalls.html 用于 32 位或 0x80 http://blog.rchapman.org/post/36801038863/linux-system-call-table-for-x86-64 用于系统调用
syscall
来调用 32 位 ABI(仅在 AMD CPU 上可能,并且行为与 64 位用户空间版本不同)。但是,是的,64 位系统调用 ABI 在调用号和调用约定方面有所不同。
int 0x80
是一个更好的术语,表示它是对内核的系统调用,告诉它做某事。
含义和解释可以互换,“进行系统调用”或“发布 int 80h”。
这与 DOS 时代没有什么不同:
调用 int 21h 让 DOS 做一些依赖于 AX 寄存器和可选的 ES:DX 寄存器对的事情,
int 13h 是 BIOS 硬盘处理程序。
int 10h 是 EGA/VGA 屏幕。
int 09h 是键盘处理程序。
这里的共同主题是,当调用中断/系统调用时,内核会检查寄存器的状态以查看需要什么类型的系统调用。例如,通过查看 eax
寄存器并确定要执行的操作,内部上下文切换到内核空间,执行过程并将上下文切换回用户空间,并可以选择返回结果呼叫,即它是成功还是失败。
syscall
指令。在这方面,int 0x80
仅用于 32 位 Linux 环境中的系统调用。
int 0x80
,这是不正确的。进行系统调用的最佳方法是使用 VDSO。syscall
ABI,除了在 VDSO 中导出用户空间实现的clock_gettime()
和getpid()
等系统调用。