在哪里可以找到 Linux 的系统调用表?

在哪里可以找到 Linux 的系统调用表?

我看到网上很多人参考

arch/x86/entry/syscalls/syscall_64.tbl

对于系统调用表,效果很好。不过还有很多人参考

/include/uapi/asm-generic/unistd.h

这通常在 headers 包中找到。怎么syscall_64.tbl显示,

0 common  read      sys_read

正确答案,并unistd.h表明,

#define __NR_io_setup 0
__SC_COMP(__NR_io_setup, sys_io_setup, compat_sys_io_setup)

然后它显示__NR_read

#define __NR_read 63
__SYSCALL(__NR_read, sys_read)

为什么是 63,而不是 1?我该如何理解 out of /include/uapi/asm-generic/unistd.h?里面/usr/include/asm/还有

/usr/include/asm/unistd_x32.h
#define __NR_read (__X32_SYSCALL_BIT + 0)
#define __NR_write (__X32_SYSCALL_BIT + 1)
#define __NR_open (__X32_SYSCALL_BIT + 2)
#define __NR_close (__X32_SYSCALL_BIT + 3)
#define __NR_stat (__X32_SYSCALL_BIT + 4)

/usr/include/asm/unistd_64.h
#define __NR_read 0
#define __NR_write 1
#define __NR_open 2
#define __NR_close 3
#define __NR_stat 4

/usr/include/asm/unistd_32.h
#define __NR_restart_syscall 0
#define __NR_exit 1           
#define __NR_fork 2           
#define __NR_read 3           
#define __NR_write 4          

unistd有人可以告诉我这些文件之间的区别吗?解释一下如何unistd.h运作?查找系统调用表的最佳方法是什么?

答案1

当我调查这种事情时,我发现直接询问编译器很有用(请参阅在终端中打印标准 C/GCC 预定义宏详情):

printf SYS_read | gcc -include sys/syscall.h -E -

这表明涉及的标头(在 Debian 上)是/usr/include/x86_64-linux-gnu/sys/syscall.h/usr/include/x86_64-linux-gnu/asm/unistd.h/usr/include/x86_64-linux-gnu/asm/unistd_64.h/usr/include/x86_64-linux-gnu/bits/syscall.h,并打印 的系统调用号read,在 x86-64 上为 0。

如果您安装了适当的系统头文件(在交叉编译器环境中),您可以找到其他体系结构的系统调用号。对于 32 位 x86,这很简单:

printf SYS_read | gcc -include sys/syscall.h -m32 -E -

其中涉及/usr/include/asm/unistd_32.h其他头文件,并打印数字 3。

因此从用户空间的角度来看,32 位 x86 系统调用在 中定义asm/unistd_32.h,64 位 x86 系统调用在 中定义asm/unistd_64.hasm/unistd_x32.h用于x32 ABI

uapi/asm-generic/unistd.h列出了默认系统调用,这些调用用于没有特定于体系结构的系统调用表的体系结构。

在内核中,引用略有不同,并且是特定于体系结构的(同样,对于不使用通用系统调用表的体系结构)。这就是诸如此类的文件arch/x86/entry/syscalls/syscall_64.tbl出现的地方(它们最终会生成在用户空间unistd_64.h等中使用的头文件)。您将在有关该主题的两篇 LWN 文章中找到有关系统调用的更多详细信息,系统调用剖析第 1 部分系统调用剖析第 2 部分

答案2

不同的体系结构在不同的文件中定义了不同的系统调用号

每个架构的系统调用号都不同,例如:

include/uapi/asm-generic/unistd.harch/*定义

我认为这include/uapi/asm-generic/unistd.h是统一所有架构的系统调用号的新尝试。

但由于系统调用编号无法更改以不破坏系统调用 API,因此统一工作之前的旧架构(包括 x86、x86_64 和 arm)保留了在arch/. arm64 较新,并且获得了新的unistd.hAPI。

这个相关问题需要一种自动方式来获取完整的系统调用列表,包括参数:https://stackoverflow.com/questions/6604007/how-can-i-get-a-list-of-linux-system-calls-and-number-of-args-they-take-automati

strace源代码

我信任该工具,并且他们将数据保持整洁linux/,例如:

请注意,aarch64#include与 arch 无关64/syscallent.h我之前提到过。

这些表包含参数的数量,但不包含实际的参数类型,我想知道strace它们在哪里编码。

glibc源代码

答案3

我有一个页面列出了每个 Linux 支持的体系结构的所有系统调用:

https://marcin.juszkiewicz.com.pl/download/tables/syscalls.html

答案4

这个答案不会涉及asm-generic的版本unistd.h,因为没有任何内容包含它。1

如中所述syscalls(2)

粗略地说,属于中定义的编号为__NR_xxx的系统调用的代码/usr/include/asm/unistd.h可以在Linux内核源代码的例程sys_xxx()中找到。

也就是说,正确的系统调用号将在 中找到/usr/include/asm/unistd.h。现在,在典型的 x86 系统上,这将仅包含asm/unistd_*.h取决于目标的文件之一。

适用于 64 位程序的系统调用号位于 中asm/unistd_64.h,适用于 32 位程序的系统调用号位于asm/unistd_32.h(或几乎等效的_x32.h变体)中。两者是不同的,因为 32 位和 64 位架构实际上是完全不同的操作系统。由于各种原因,它们共享同一组系统调用,但顺序不同。

其中大多数也有 C 语言包装器,因此很少需要syscall(2)直接使用。


1因为我不知道它的用途是什么。

相关内容