我知道有一个约定,但是当您调用 to而不是 时syscall
,您将其前面的调用约定称为什么,就像这样。int 80
syscall
mov rax,4 ; system call number (sys_write)
mov rbx,1 ; file descriptor (stdout)
mov rcx,hello ; message to write
mov rdx,12 ; message length
int 0x80 ; call kernel
我读这里之后的参数rdx
是esi
, edi
, ebp
(或对于 x64 rsi
, rdi
, rbp
),我没有看到它记录在维基百科的调用约定页面, 但整数80小时似乎表明 Windows 也使用此约定?
这个约定叫什么名字。在 Linux 内核源代码中的哪里可以看到它的定义?并且,rax
当您调用时解析过程的表在哪里int 0x80
?对于syscall
,sys_write
是rax=1
答案1
您的问题涵盖了很多主题,我将尽力解决所有主题。
我不确定调用系统调用的方式有一个单一的规范术语,更不用说调用系统调用的特定方式(中断 0x80 而不是
SYSENTER
orSYSCALL
)。在 x86-64 上,记录在案System V x86-64 ABI 中描述了使用 的系统调用接口SYSCALL
,但这只是提供信息,而不是规范性的。同样,虽然如果您将其称为“i386 Linux 内核 ABI”(用您正在谈论的任何架构替换“i386”),大多数人都会理解您在说什么,但这也可能会令人困惑,因为“内核 ABI”有另一个含义(在内核模块的上下文中),并且这不仅限于中断 0x80。在实践中,大多数人无论如何都不应该关心这种细节级别的细节,特别是因为它们可以演变:中断 0x80
SYSCALL
等,正如您提到的,而且 vDSO 也引入了自己的微妙之处,并且是首选的入口点对于现在 x86 上的所有系统调用...当然,这并不意味着不能有一个术语来指代特定的调用约定,但我不确定它是否会有那么有用。Windows 还支持使用中断作为其系统调用接口 0x2E,但其“调用约定”是很不一样:参数被压入堆栈,请求的系统调用由EAX给出,EBX指向堆栈上的参数。
当前的 x86 内核定义了系统调用接口
arch/x86/entry
:entry_32.S
包含 i386 接口,entry_64.S
x86-32 和 x86-64 接口,entry_64_compat.S
32 位 x86-64 接口(用于向后兼容),syscalls/syscall_32.tbl
i386系统调用表,syscalls/syscall_64.tbl
x86-32 和 x86-64 系统调用表。这些文件中的注释记录了接口,特别是如何传递参数:对于 32 位调用,EAX 包含系统调用号,其参数放置在 EBX、ECX、EDX、ESI、EDI 和 EBP 中(参数本身为
SYSENTER
,指向包含中断参数 0x80 的用户堆栈的指针);对于 64 位调用,RAX 包含系统调用号,其参数放在 RDI、RSI、RDX、R10、R8 和 R9 中(另请参阅为什么系统调用寄存器和顺序从Intel 32位变为64位?)。有一个很好的总结,里面有图表calling.h
。
附带说明一下,历史比较通常参考 MS-DOS 调用接口,该接口主要使用中断0x21;它还包括多路复用中断,0x2F,其中提供了可扩展的机制用于添加系统服务(通常涉及 TSR;设备驱动程序大多使用不同的接口)。