当我尝试研究内核的系统调用的返回值时,我找到了描述它们的表,以及我需要将它放在不同的寄存器中以使它们工作。但是,我没有找到任何文档说明什么是我从系统调用获得的返回值。我只是在不同的地方发现我收到的内容将出现在EAX注册表中。
结果通常在EAX寄存器中返回。
汇编语言循序渐进:使用Linux编程由Jeff Duntemann编写的书籍多次出现在他的程序中:
查看sys_read在EAX中的返回值
复制sys_read返回值以便安全保存
我没有解释任何有关此返回值的网站。有没有互联网资源?或者有人能解释一下这个价值观吗?
答案 0 :(得分:7)
另请参阅假设C知识的this excellent LWN article about system calls。
另外:The Definitive Guide to Linux System Calls (on x86)和相关:What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code?
C是Unix系统编程的语言,因此所有文档都是用C语言编写的。然后是关于任何给定平台上C接口和asm之间微小差异的文档,通常在Notes中手册部分。
sys_read
表示原始系统调用(与libc包装函数相对)。 read
系统调用的内核实现是一个名为sys_read()
的内核函数。您无法使用call
指令调用它,因为它在内核中,而不是库中。但人们仍在谈论"呼叫sys_read
"区别于libc函数调用。但是,即使您的意思是原始系统调用(特别是当libc包装器没有做任何特殊操作时),也可以说read
,就像我在这个答案中所做的那样。
另请注意,syscall.h
使用实际系统调用号定义SYS_read
之类的常量。 (在int 0x80
或syscall
指令之前放入EAX的值。
Linux系统调用返回值(在x86上的EAX
/ RAX
中)是成功的非负值,或a negative error code。例如如果传递无效指针,则为-EFAULT
。
syscalls(2)
手册页中记录了此行为。
实际上, -1到-4095意味着错误,其他任何意味着成功。 glibc的generic syscall(2)
wrapper使用了这个序列:cmp rax, -4095
/ jae SYSCALL_ERROR_LABEL
,对于所有Linux系统调用显然都是guaranteed to be future-proof。有趣的案例包括mmap
,其中有效地址can have the sign bit set, but must be page aligned和getpriority
,其中内核ABI将-20..19返回值范围映射到1..40,并且libc对其进行解码。 a related answer about decoding syscall error return values中的更多详细信息。
更新,是的,所有系统调用肯定都能保证-4095
.. -1
是Linux运行的所有体系结构上的错误范围。有关详细信息,请参阅AOSP non-obvious syscall() implementation。 (将来,不同的架构可能会为MAX_ERRNO使用不同的值,但是像x86-64这样的现有拱门的值保证与Linux的不间断用户空间策略保持一致保持内核ABI稳定。)
要查找特定平台的常量的实际数值,您需要找到它们在#define
d的C头文件。有关详细信息,请参阅my answer on a question about that。
每个sys调用的返回值的含义记录在第2节手册页中,如read(2)
。 (sys_read
是原始系统调用,glibc read()
函数是一个非常薄的包装器。)大多数手册页都有一个返回值的整个部分。例如
返回值
成功时,返回读取的字节数(零表示 文件结束),文件位置按此编号前进。它 如果此数字小于字节数,则不是错误 要求;这可能发生在例如因为较少的字节 实际上现在可用(也许是因为我们接近结束了 文件,或者因为我们正在从管道或终端读取)或者 因为read()被信号打断了。另见注释。
出错时,返回-1,并正确设置errno。在这 例如,文件位置(如果有的话)是否未指定 变化。
请注意,最后一段描述了glibc包装器如何解码值,如果原始系统调用的返回值为负,则sets errno解析为-EAX
,因此errno=EFAULT
并返回如果原始系统调用返回-1
,则-EFAULT
。
并且整个部分列出了read()
被允许返回的所有可能错误代码,以及它们对read()
的具体含义。 (POSIX标准化了大部分此行为。)
我不确定glibc解码返回值mmap(2)
的确切位置,其中返回值不是有符号类型。它可能使用与通用系统调用包装器相同的方法(检查无符号值> -4096UL
),但每个系统调用的特定包装器都没有实际改组寄存器之间的args并调用该函数的开销。
我没有看到in the glibc source tree;据推测,它被埋在某些宏层之下。例如in the x86-64 macro