SYSCALL - Linux手册页
Linux程序员手册 第2部分
更新日期: 2020-06-09
名称
syscall-间接系统调用
语法
#include <unistd.h> #include <sys/syscall.h> /* For SYS_xxx definitions */ long syscall(long number, ...);
glibc的功能测试宏要求(请参阅feature_test_macros(7)):syscall():
- Since glibc 2.19:
- _DEFAULT_SOURCE
- Before glibc 2.19:
- _BSD_SOURCE || _SVID_SOURCE
说明
syscall()是一个小的库函数,它将调用其汇编语言接口具有指定编号和指定参数的系统调用。例如,当调用C库中没有包装函数的系统调用时,使用syscall()很有用。
syscall()在进行系统调用之前保存CPU寄存器,在从系统调用返回时恢复寄存器,并将系统调用返回的任何错误存储在errno(3)中。
在头文件中可以找到系统调用号的符号常量。
返回值
返回值由正在调用的系统调用定义。通常,返回值为0表示成功。返回值-1表示错误,并且错误号存储在errno中。
备注
syscall()最早出现在4BSD中。
Architecture-specific requirements
对于将系统调用参数传递到内核的方式,每种体系结构ABI都有其自己的要求。对于具有glibc包装器的系统调用(例如,大多数系统调用),glibc以适合于体系结构的方式处理将参数复制到正确的寄存器的细节。但是,当使用syscall()进行系统调用时,调用者可能需要处理与体系结构有关的详细信息。在某些32位体系结构上最经常遇到此要求。
例如,在ARM体系结构嵌入式ABI(EABI)上,必须将64位值(例如long long)对准偶数寄存器对。因此,使用syscall()而不是glibc提供的包装器,将在ARM架构上以小端模式在EABI上按以下方式调用readahead(2)系统调用:
syscall(SYS_readahead, fd, 0, (unsigned int) (offset & 0xFFFFFFFF), (unsigned int) (offset >> 32), count);
由于offset参数是64位,并且第一个参数(fd)在r0中传递,因此调用方必须手动拆分和对齐64位值,以便将其在r2 / r3寄存器对中传递。这意味着将一个虚拟值插入r1(第二个参数为0)。还必须小心,以使拆分遵循字节序约定(根据平台的C ABI)。
在带有O32 ABI的MIPS,在PowerPC和带有32位ABI的parisc以及在Xtensa上,可能会发生类似的问题。
请注意,虽然parisc C ABI也使用对齐的寄存器对,但它使用垫片层将问题隐藏在用户空间之外。
受影响的系统调用为fadvise64_64(2),ftruncate64(2),posix_fadvise(2),pread64(2),pwrite64(2),readahead(2),sync_file_range(2)和truncate64(2)。
这不会影响手动拆分和组合64位值的syscall,例如_llseek(2),preadv(2),preadv2(2),pwritev(2)和pwritev2(2)。欢迎来到历史包wonderful的奇妙世界。
Architecture calling conventions
每个体系结构都有其自己的调用方法并将参数传递给内核。下表两个表中列出了各种体系结构的详细信息。
第一张表列出了用于过渡到内核模式的指令(这可能不是最快或最佳的过渡到内核方式,因此您可能必须参考vdso(7)),该寄存器用于指示系统调用号,用于返回系统调用结果的寄存器以及用于指示错误的寄存器。
单元格不一致
笔记:
- [1]
- 在某些体系结构上,寄存器用作布尔值(0表示无错误,而-1表示错误)表示系统调用失败。实际错误值仍包含在返回寄存器中。在sparc上,使用处理器状态寄存器(psr)中的进位位(csr)代替完整寄存器。在powerpc64上,使用条件寄存器(cr0)的字段0中的汇总溢出位(SO)。
- [2]
- NR是系统呼叫号码。
- [3]
- 对于s390和s390x,如果NR(系统调用号)小于256,则可以直接与svcNR一起传递。
- [4]
- 在SuperH上,陷阱号控制传递的最大参数数。陷阱#0x10只能与0参数的系统调用一起使用,陷阱#0x11可以与0或1参数的系统调用一起使用,依此类推,直到陷阱#0x17可以用于7参数的系统调用。
- [5]
- The x32 ABI shares syscall table with x86-64 ABI, but there are some
nuances:
- *
- 为了指示在x32 ABI下调用了系统调用,将附加位__X32_SYSCALL_BIT与系统调用号按位或。流程使用的ABI影响某些流程行为,包括信号处理或系统调用重新启动。
- *
- 由于x32对于long类型和指针类型具有不同的大小,因此某些(但不是全部; struct timeval或struct rlimit是64位)的布局是不同的。为了解决此问题,从编号512(不带__X32_SYSCALL_BIT)开始,将其他系统调用添加到系统调用表中。例如,对于x86-64 ABI,__ NR_readv定义为19,对于__X32_SYSCALL_BIT |定义为__NR_readv。 x32 ABI为515。这些附加系统调用中的大多数实际上与用于提供i386兼容性的系统调用相同。但是,有一些值得注意的例外,例如preadv2(2),它使用具有4字节指针和大小的struct iovec实体(内核术语为" compat_iovec"),但是在单个寄存器中传递8字节pos参数,而不是第二,就像其他所有ABI一样。
- [6]
- 某些体系结构(即Alpha,IA-64,MIPS,SuperH,sparc / 32和sparc / 64)使用附加寄存器(上表中的" Retval2")从管道(2)传回第二个返回值系统调用; Alpha在特定于体系结构的getxpid(2),getxuid(2)和getxgid(2)系统调用中也使用了此技术。其他体系结构即使在System V ABI中定义了第二个返回值寄存器,也不会在系统调用接口中使用它。
第二张表显示了用于传递系统调用参数的寄存器。
单元格不一致
笔记:
- [1]
- mips / o32系统调用约定在用户堆栈上传递参数5到8。
请注意,这些表并未涵盖整个调用约定-某些架构可能会不加选择地破坏此处未列出的其他寄存器。
示例
#define _GNU_SOURCE #include <unistd.h> #include <sys/syscall.h> #include <sys/types.h> #include <signal.h> int main(int argc, char *argv[]) { pid_t tid; tid = syscall(SYS_gettid); syscall(SYS_tgkill, getpid(), tid, SIGHUP); }
出版信息
这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/。