当我尝试研究内核系统调用的返回值时,我find描述它们的表格,以及我需要在不同的寄存器中放置什么来让它们工作。 但是,我没有find任何文件,它说明什么是我从系统调用返回的值。 我只是在不同的地方发现,我收到的将是EAX寄存器。
教程点 :
结果通常在EAX寄存器中返回。
汇编语言循序渐进:使用Linux进行编程 Jeff Duntemann在他的程序中多次声明:
查看EAX中sys_read的返回值
复制sys_read返回值以保持安全
我有任何网站没有解释这个返回值。 有没有互联网的来源? 或者可以有人解释我对这个价值?
另请参阅这篇关于系统调用的LWN优秀文章,其中假设C知识。
另外: Linux系统调用权限指南(在x86上)以及相关内容: 如果在64位代码中使用32位int 0x80 Linux ABI,会发生什么?
C是Unix系统编程的语言,因此所有的文档都是以C语言编写的。然后在任何给定的平台上,通常在手册页的Notes部分,都有关于C接口和asm之间细微区别的文档。
sys_read
表示原始系统调用(与libc包装函数相反)。 read
系统调用的内核实现是一个名为sys_read()
的内核函数。 你不能用call
指令调用它,因为它在内核中,而不是在库中。 但是人们仍然在谈论“调用sys_read
”来区分它与libc函数调用。 然而,甚至当你指的是原始的系统调用时(特别是当libc包装器没有做任何特别的事情时),也可以这么说,就像我在这个答案中一样。
还要注意, syscall.h
定义了像SYS_read
这样的SYS_read
和实际的系统调用号码。 (在int 0x80
或syscall
指令之前放入EAX的值)。
Linux系统调用返回值(在x86上的EAX
/ RAX
中)是成功的非负值或负的错误代码 。 例如,如果你传递了一个无效的指针,则为-EFAULT
。
此行为在syscalls(2)
手册页中进行了介绍。
实际上-1到-4095意味着错误,其他的意味着成功 。 glibc的通用syscall(2)
包装器使用这个序列: cmp rax, -4095
/ jae SYSCALL_ERROR_LABEL
,显然保证所有的Linux系统调用都是面向未来的 。 有趣的案例包括mmap
,有效地址可以设置符号位,但必须页面对齐 , getpriority
内核ABI将-20..19的返回值范围映射到1..40,libc对其进行解码。 有关解码syscall错误返回值的相关答案中的更多详细信息。
更新,是的,它绝对保证所有系统调用, -4095
.. -1
是Linux上运行的所有体系结构的错误范围。 有关更多详细信息,请参阅AOSP非显而易见的syscall()实现 。 (将来,不同的体系结构可能会为MAX_ERRNO使用不同的值,但现有的像x86-64这样的拱的值保证不变,这是Linux保持内核ABI稳定的不中断用户空间策略的一部分。 )
要找到特定平台常量的实际数值,您需要找到它们是#define
d的C头文件。 有关详情,请参阅我的回答 。
每个sys调用的返回值的含义在第2节手册页中有说明,如read(2)
。 ( sys_read
是原始的系统调用,glibc的read()
函数是一个很薄的包装器。)大多数手册页都有一个完整的返回值部分。 例如
返回值
成功时返回读取的字节数(零表示文件结束),文件位置按此编号提前。 如果这个数字小于请求的字节数就不是错误; 这可能发生,例如因为更少的字节
实际上现在可用(也许是因为我们已经接近结束了,
文件,或者因为我们正在从管道读取数据,或者从终端读取数据),或者
因为read()被一个信号中断。 另见注释。出错时,返回-1,并适当地设置errno。 在这种情况下,未指定文件位置(如果有的话)
变化。
请注意,最后一段描述了如果原始系统调用的返回值是负值,glibc包装器如何解码值并将errno设置为-EAX
则errno=EFAULT
,如果原始系统调用返回-1
则返回-1
-EFAULT
。
还有一个整节列出了read()
允许返回的所有可能的错误代码,以及它们专门用于read()
含义。 (POSIX将这种行为的大部分标准化。)
我不确定在哪里glibc解码mmap(2)
的返回值,其中返回值不是一个签名类型。 它可能使用与通用的系统调用封装(检查无符号值> -4096UL
)相同的方法,但是每个系统调用的具体封装没有实际上在寄存器之间混洗参数和调用该函数的开销。
我没有在glibc源代码树中看到它; 据推测它被埋在了一些宏的层次之下。 例如在x86-64宏中