ChatGPT解决这个技术问题 Extra ChatGPT

Linux 上 32 位代码中的“int 0x80”或“syscall”哪个更好?

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

对于 i386 架构(32 位 x86 用户空间),哪个更可取:syscallint 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 的内核?你能指定一些文件吗?
@Mike实际上我找到了一种关于linux内核的教程,作为一个例子。它是基于 2.6 的。
我认为 int 0x80 直接在 x86-64 内核上工作是为了向后兼容。英特尔手册说 syscall 在 32 位模式下无效。
补充 self: syscall 仅在 Intel 实现中无效,而不是 AMD: stackoverflow.com/questions/29783896/…

M
Matthias Braun

syscall 是在 x86-64 上进入内核模式的默认方式。此指令在 Intel 处理器的 32 位操作模式下不可用。

sysenter 是最常用于在 32 位操作模式中调用系统调用的指令。它类似于 syscall,虽然使用起来有点困难,但这是内核关心的问题。

int 0x80 是调用系统调用的传统方式,应避免使用。

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

另请参阅 thisthis


选择其中之一的建议适用于 OS 内核开发人员。然后他们的选择成为 ABI 的一部分,如果您正在为某个操作系统进行开发,则必须尊重该 ABI。例如,Linux/i386 使用 int 0x80 并在寄存器中传递参数,而 MirBSD/i386 使用 int 0x80 并在堆栈上传递参数,中间有一个帧指针(这意味着使用 cdecl 时用户空间中没有设置成本)。 [这个答案主要是针对那些被送到这里但不是操作系统内核设计者的人。]
问题是关于 Linux 的,答案描述了在 Linux(i386 和 x86_64)上调用系统调用的可能方法。您建议 Linux/i386 仅使用 int 0x80,这是不正确的。进行系统调用的最佳方法是使用 VDSO。
相关:What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code?。 (它“有效”,但仅适用于寄存器的低 32 位,因此您不能将其与 64 位指针一起使用。)
VDSO 仅适用于 32 位 x86。我认为 x86-64 glibc 直接使用 syscall ABI,除了在 VDSO 中导出用户空间实现的 clock_gettime()getpid() 等系统调用。
C
Community

我的回答 here 涵盖了您的问题。

在实践中,最近的内核正在实现 VDSO,特别是为了动态优化系统调用(内核将 VDSO 设置为一些最适合当前处理器的代码)。所以你应该使用VDSO,对于现有的系统调用,你最好使用libc提供的接口。

请注意,AFAIK,简单系统调用成本的很大一部分是从用户空间到内核并返回。因此,对于某些系统调用(可能是 gettimeofdaygetpid ...),VDSO 甚至可以避免这种情况(并且在技术上可能会避免执行真正的系统调用)。对于大多数系统调用(如 openreadsendmmap ....),系统调用的内核成本足够大,可以改进用户空间到内核空间的转换(例如,使用SYSENTERSYSCALL 机器指令而不是 INT) 无关紧要。


早在 80386 天,进入内核的最快方式其实就是 execute an invalid instruction
@AdamRosenfield "The hunt for a faster syscall trap" 是您链接到的正确博客条目?你的已经烂了...
@Ruslan:是的,就是这样。 Raymond Chen 的博客在去年的某个时候经历了一次迁移,很多像这样的旧链接都坏了。
T
Thomas

更改前请注意:执行 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 用于系统调用


问题是关于在 32 位模式下使用 syscall 来调用 32 位 ABI(仅在 AMD CPU 上可能,并且行为与 64 位用户空间版本不同)。但是,是的,64 位系统调用 ABI 在调用号和调用约定方面有所不同。
t
t0mm13b

int 0x80 是一个更好的术语,表示它是对内核的系统调用,告诉它做某事。

含义和解释可以互换,“进行系统调用”或“发布 int 80h”。

这与 DOS 时代没有什么不同:

调用 int 21h 让 DOS 做一些依赖于 AX 寄存器和可选的 ES:DX 寄存器对的事情,

int 13h 是 BIOS 硬盘处理程序。

int 10h 是 EGA/VGA 屏幕。

int 09h 是键盘处理程序。

这里的共同主题是,当调用中断/系统调用时,内核会检查寄存器的状态以查看需要什么类型的系统调用。例如,通过查看 eax 寄存器并确定要执行的操作,内部上下文切换到内核空间,执行过程并将上下文切换回用户空间,并可以选择返回结果呼叫,即它是成功还是失败。


实际上,x86_64 指令集有一条 syscall 指令。在这方面,int 0x80 仅用于 32 位 Linux 环境中的系统调用。
好吧,公平地说,OP应该更清楚x86架构更可取的系统调用或int 0x80 - 它是模棱两可的,因为OP提到x86-64并且从那个上下文来看,暗示32位......这让我的回答有点走误入歧途或中断异常:P