当我尝试研究内核的系统调用的返回值时,我会找到描述它们的表,以及需要放入不同的寄存器中才能使它们工作的表。但是,我找不到任何文档说明它从系统调用中获得的返回值是 什么 。我只是在不同的地方发现我收到的将在EAX寄存器中。
TutorialsPoint:
结果通常在EAX寄存器中返回。
汇编语言循序渐进:使用Linux编程 Jeff Duntemann的书在其程序中多次陈述:
查看EAX中sys_read的返回值 复制sys_read返回值以安全保存
查看EAX中sys_read的返回值
复制sys_read返回值以安全保存
我没有任何网站解释此返回值。有互联网资源吗?或者有人可以向我解释这个价值观?
C是Unix系统编程的语言,因此所有文档均以C表示。然后,在任何给定平台上都有C接口与asm之间细微差异的文档,通常在手册页的Notes部分中。
sys_read表示原始系统调用(与libc包装器函数相对)。read系统调用的内核实现是称为的内核函数sys_read()。您不能使用call指令来调用它,因为它在内核中,而不是库中。但是人们仍然在谈论“调用sys_read”以区别于libc函数调用。但是,read即使您指的是原始系统调用(特别是当libc包装器没有执行任何特殊操作时),也可以说出来,就像我在此答案中所做的那样。
sys_read
read
sys_read()
call
还要注意,syscall.h定义常量时应SYS_read使用实际的系统调用号码。(您在EAX int 0x80或syscall指令前输入的值)。
syscall.h
SYS_read
int 0x80
syscall
Linux系统调用的返回值(在EAX/RAXx86上)或者是成功的非负值,或一个负的错误代码。例如,-EFAULT如果您传递了无效的指针。
EAX
RAX
-EFAULT
syscalls(2)手册页中记录了此行为。
syscalls(2)
实际上, -1到-4095表示错误,其他表示成功。glibc的通用syscall(2)包装器使用以下序列: cmp rax, -4095/jaeSYSCALL_ERROR_LABEL,显然可以保证所有Linux系统调用都符合未来的要求。有趣的情况包括:mmap有效地址[可以设置符号位,但必须进行页面对齐];getpriority内核ABI将-20..19返回值范围映射到1..40,然后libc对其进行解码。有关解码系统调用错误返回值的相关答案中的更多详细信息。
syscall(2)
cmp rax, -4095
jaeSYSCALL_ERROR_LABEL
mmap
getpriority
更新,是的,对于所有的系统调用,都可以保证在Linux运行的所有体系结构上的错误范围都是-4095.. -1有关更多详细信息,请参见[AOSP非显而易见的syscall()实现。(将来,不同的体系结构可能会为MAX_ERRNO使用不同的值,但可以保证现有拱门(如x86-64)的值与Linux保持内核ABI稳定的不中断用户空间策略的一部分相同。
-4095
-1
要查找特定平台常数的实际数值,您需要在#defined所在的位置找到C头文件。有关详细信息,
#define
每个sys调用的返回值的含义在第2节的手册页中都有介绍,例如read(2)。(sys_read这是glibc read()函数非常薄的包装程序的原始系统调用。)大多数手册页都有用于返回值的整个部分。例如
read(2)
read()
返回值 成功后,将返回读取的字节数(零表示文件末尾),并且文件位置以该数字前移。如果此数目小于请求的字节数,这不是错误;例如,这可能是因为当前 实际可用的字节较少(可能是因为我们接近 文件末尾,或者因为我们正在从管道或终端 读取),或者因为read()被a中断了。信号。另请参阅注释。 如果出错,则返回-1,并正确设置errno。在这种情况下,未指定文件位置(如果有)是否 更改。
返回值
成功后,将返回读取的字节数(零表示文件末尾),并且文件位置以该数字前移。如果此数目小于请求的字节数,这不是错误;例如,这可能是因为当前 实际可用的字节较少(可能是因为我们接近 文件末尾,或者因为我们正在从管道或终端 读取),或者因为read()被a中断了。信号。另请参阅注释。
如果出错,则返回-1,并正确设置errno。在这种情况下,未指定文件位置(如果有)是否 更改。
需要注意的是最后一段描述glibc的包装如何解码值,并设置errno到-EAX如果原始系统调用的返回值是负的,所以errno=EFAULT和返回-1如果原始系统调用返回-EFAULT。
-EAX
errno=EFAULT
整个章节列出了所有可能read()返回的错误代码,以及它们的特殊含义read()。(POSIX标准化了大多数这种行为。)
我不确定glibc到底在哪里解码的返回值mmap(2),而返回值不是带符号的类型。它可能使用与通用syscall包装器相同的方法(检查unsigned value > -4096UL),但是每个系统调用的特定包装器没有实际在寄存器之间对arg进行改组并调用该函数的开销。
mmap(2)
> -4096UL
我在glibc源代码树中没有看到它;大概它埋在某些宏层下。