另见this excellent LWN article about system calls,它假定为C知识.
C是Unix系统编程的语言,所以所有文档都是用C语言编写的.然后是文档,说明任何给定平台上C接口和asm之间的细微差别,通常在手册页的Notes部分.
sys_read表示原始系统调用(与libc包装函数相对). read系统调用的内核实现是一个名为sys_read()的内核函数.你不能用调用指令调用它,因为它在内核中,而不是库中.但人们仍然在谈论“调用sys_read”以区别于libc函数调用.但是,即使您的意思是原始系统调用(特别是当libc包装器没有做任何特殊操作时),也可以说读取,就像我在这个答案中所做的那样.
另请注意,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.有趣的案例包括有效地址为can have the sign bit set, but must be page aligned的mmap,以及内核ABI将-20..19返回值范围映射到1..40的getpriority,以及libc对其进行解码.更多细节在a related answer about decoding syscall error return values.
更新,是的,所有系统调用肯定都保证-4095 .. -1是Linux运行的所有体系结构上的错误范围.有关详细信息,请参阅AOSP non-obvious syscall() implementation. (将来,不同的体系结构可以为MAX_ERRNO使用不同的值,但是像x86-64这样的现有arches的值保证与Linux保持内核ABI稳定的非破坏用户空间策略的一部分相同. )
要查找特定平台的常量的实际数值,您需要找到它们是#defined的C头文件.有关详细信息,请参见my answer on a question about that.
每个sys调用的返回值的含义记录在第2节手册页中,如read(2).(sys_read是原始系统调用,glibc read()函数是一个非常薄的包装器.)大多数手册页都有一个完整的部分为了返回值.例如
RETURN VALUE
On success, the number of bytes read is returned (zero indicates
end of file), and the file position is advanced by this number. It
is not an error if this number is smaller than the number of bytes
requested; this may happen for example because fewer bytes are
actually available right now (maybe because we were close to end-of-
file, or because we are reading from a pipe, or from a terminal), or
because read() was interrupted by a signal. See also NOTES.
On error, -1 is returned, and errno is set appropriately. In this
case, it is left unspecified whether the file position (if any)
changes.
请注意,最后一段描述了glibc包装器如何解码值,如果原始系统调用的返回值为负,则描述sets errno到-EAX,因此errno = EFAULT,如果原始系统调用返回-EFAULT,则返回-1.
还有一个完整的部分列出了read()允许返回的所有可能的错误代码,以及它们对read()的具体含义. (POSIX标准化了大多数此行为.)
我不确定glibc在哪里解码mmap(2)的返回值,其中返回值不是有符号类型.它可能使用与通用系统调用包装器相同的方法(检查无符号值> -4096UL),但每个系统调用的特定包装器没有实际调整寄存器之间的args并调用该函数的开销.