在32位Linux上,是使用Syscall还是sysenter?

9
自从 MS-DOS 时代开始,我就知道可以使用中断来调用系统。在早期的文献中,我看到过在 Linux 上调用系统函数需要使用“int 80h”的参考资料。现在已经有相当长一段时间了,我知道“int 80h”已被“syscall”指令取代了。但是我在我的32位机器上无法让它工作。
问题是,是否只有64位平台才能使用“syscall”指令?32位的 Linux 是否也使用“syscall”?
在我的32位 Linux(Ubuntu Precise)上,运行此程序会导致核心转储。
global _start

_start:
        mov     eax, 4                ; 4 is write
        mov     ebx, 1                ; 1 is stdout
        mov     ecx, message          ; address of string
        mov     edx, length           ; number of bytes
        syscall

        mov     eax, 1                ; 1 is exit
        xor     ebx, ebx              ; return code 0
        syscall

message:
        db  10,"Hello, World",10,10
length  equ $ - message

我尝试使用sysenter代替syscall,但它以相同的方式崩溃。


可能是什么更好“int 0x80”还是“syscall”?的重复问题。 - Michael
1
确实有相关内容在这里,链接如下(https://dev59.com/JGcs5IYBdhLWcg3wfEHa#12806910),但并没有回答问题。他说`syscall`不可用于Intel CPU的32位模式中,但汇编器是在32位模式下编译的;要么这个断言不清楚,要么就是错误的。然后,我因为一个非法指令而获得了核心转储(core-dump),但这个指令在从Pentium II开始的所有Intel CPU上都是可用的,而我的CPU也符合要求。他提到了sysenter,我尝试过,结果相同。无论如何,在Linux ABI中我从未见过关于sysenter的任何提及,只有int 80hsyscall - Hibou57
2
根据“系统调用(wiki.osdev.org)”,syscall是AMD版本的Intel sysenter。它说:“*在英特尔CPU上,从Pentium II开始,出现了一对新指令sysenter/sysexit。它允许更快地从用户模式切换到内核模式,通过限制改变模式的开销。AMD创建了类似的指令对:Syscall/Sysret。但是这些指令的行为与英特尔的不同。” - Hibou57
2
参考资料,int 0x80 一直是 Linux 的事情。Windows 和 MS-DOS 使用 int 0x2E。 - SecurityMatt
1
选择一种而非另一种的建议是针对操作系统内核开发人员的。他们的选择随后成为ABI的一部分,如果您正在为某个特定的操作系统开发,则必须遵守该ABI。例如,Linux/i386使用int 0x80并在寄存器中传递参数,而MirBSD/i386使用int 0x80并将参数传递给堆栈,并在其间使用一个帧指针(这意味着在使用cdecl时用户空间没有设置成本)。 - mirabilos
2个回答

6

1
有人在初始问题的评论中提出了同样的问题。我回答说,我使用的汇编程序已经编译指令,而且32位操作码已经记录下来了,没有任何警告。也许这只在64位架构的32位模式下无效...无论如何,正如你所说,在Linux的环境下,最好依赖于VDSO(即使没有Glibc,也有检索它的方法)。 - Hibou57
1
@Hibou57:根据此评论线程:它仅在AMD CPU的32位模式下有效。我也很惊讶它可以在32位代码中汇编和反汇编,但显然AMD在AMD64架构之前(或许是在之前)单独引入了syscall。Intel的指令在32位模式下胜出(像往常一样),但AMD的成为了AMD64的标准。 - Peter Cordes

6
经过一番网络搜索,我找到了StackOverflow上的另一个主题:Linux invoke a system call via sysenter tutorial。它说调用系统的推荐方法既不是使用int 80h,也不是syscallsysenter,而是linux-gate.so
仍然存在关于崩溃和核心转储的问题。我的猜测是,尽管syscallsysenter指令都可以作为CPU指令使用,但Linux内核可能只是在决定在给定硬件平台上它不是真正有用时才正确地设置这个“入口点”。
似乎在32位平台上,sysentersyscall可能可用,而在64位平台上,它始终可用。
虽然我觉得这回答了我的问题,但我仍然欢迎更多的材料,比如对我上面的猜测的权威参考。
-- 更新 --
至少,我找到了这个证实了上述结论。虽然这还不是一个权威的参考,但我相信它是可信的。 What is linux-gate.so.1?说:

调用系统调用的首选方法是 由内核在引导时确定, 显然这个盒子使用sysenter。

此外,还有另一个来源的FASM汇编源代码(如果您使用NASM,则需要进行一些翻译)来通过linux-gate.so调用系统函数:Finding linux-gate.so.1 in Assembly

1
请注意,使用sysenter/syscall时,约定可能与使用int 0x80不完全相同。对于sysenter,您需要在sysenter之前正确执行以下操作:push ecx、push edx、push ebp、mov ebp, esp - nos
1
请注意,由于它是“在启动时由内核确定的”,因此您会得到int 80、sysenter或syscall,具体取决于CPU的功能。Int 80始终有效,但速度较慢,在更新的CPU上只有sysenter或syscall之一有效。这不是程序应该做出的选择,内核会为您做出最佳选择。 - Goswin von Brederlow

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