我看到很多人在网上参考
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
工作?查找系统调用表的最佳方法是什么?
当我研究这种事情时,我发现直接询问编译器很有用(有关详细信息,请参阅在终端中打印标准 C/GCC 预定义宏):
这表明(在 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,这很容易:
其中涉及
/usr/include/asm/unistd_32.h
其他头文件,并打印数字 3。所以从用户空间的角度来看,32 位 x86 系统调用在 中定义
asm/unistd_32.h
,64 位 x86 系统调用在asm/unistd_64.h
.asm/unistd_x32.h
用于x32 ABI。uapi/asm-generic/unistd.h
列出了默认系统调用,它们用于没有特定于体系结构的系统调用表的体系结构。在内核中,引用略有不同,并且是特定于体系结构的(同样,对于不使用通用系统调用表的体系结构)。这就是诸如此类的文件
arch/x86/entry/syscalls/syscall_64.tbl
的来源(它们最终会生成在用户空间中使用的头文件unistd_64.h
等)。您将在有关该主题的两篇 LWN 文章中找到有关系统调用的更多详细信息,系统调用剖析第 1 部分和系统调用剖析第 2 部分。不同的拱门在不同的文件中定义了不同的系统调用号
每个架构的系统调用号都不同,例如:
x86_64:
arch/x86/entry/syscalls/syscall_64.tbl
: 读取为 0x86:
arch/x86/entry/syscalls/syscall_32.tbl
: 读取为 3arm64:
include/uapi/asm-generic/unistd.h
: 读取为 63,另见:https ://reverseengineering.stackexchange.com/questions/16917/arm64-syscalls-table/18834#18834arm:
arch/arm/tools/syscall.tbl
, 读取为 3include/uapi/asm-generic/unistd.h
与arch/*
定义我认为这
include/uapi/asm-generic/unistd.h
是统一所有拱门的系统调用编号的新尝试。但由于系统调用编号无法更改以不破坏系统调用 API,因此在统一努力之前的旧架构(包括 x86、x86_64 和 arm)保留了在
arch/
. arm64 较新,unistd.h
但获得了新的 API。这个相关问题要求自动获取完整的系统调用列表,包括参数: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
的拱不可知论者。64/syscallent.h
这些表包含参数的数量,但不包含实际的参数类型,我想知道
strace
它们在哪里编码。glibc
源代码我有一个页面列出了每个 Linux 支持的体系结构的所有系统调用:
https://marcin.juszkiewicz.com.pl/download/tables/syscalls.html
为了补充所有出色的答案,有一个实用程序
ausyscall
可用于列出特定体系结构的所有系统调用及其整数映射。例如:
此答案不会涉及 的
asm-generic
版本unistd.h
,因为没有任何内容包含它。1如中所述
syscalls(2)
:也就是说,正确的系统调用号将在
/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因为我不知道它是干什么用的。