首先也是最重要的一点是,C 库包装器fork(2) http://man7.org/linux/man-pages/man2/fork.2.html调用sys_clone http://elixir.free-electrons.com/linux/v3.3/source/arch/x86/kernel/process.c#L257并不是sys_fork http://elixir.free-electrons.com/linux/v3.3/source/arch/x86/kernel/process.c#L235.
C 库/内核差异
从2.3.3版本开始,不再调用内核的fork()系统
调用,作为 NPTL 一部分提供的 glibc fork() 包装器
线程实现调用clone(2),其标志提供了
与传统的系统调用效果相同。
The Linux手册第2部分简介 http://man7.org/linux/man-pages/man2/intro.2.html解释如何在一般上下文中解释系统调用的返回值:
返回值
出错时,大多数系统调用都会返回负错误数(即
errno(3) 中描述的常量之一的负值。 C
库包装器向调用者隐藏此详细信息:当系统调用时
返回负值,包装器将绝对值复制到
errno 变量,并返回 -1作为返回值
包装纸。
So for most系统调用,EAX/RAX 保持-ESOMETHING
错误时,或成功时非负结果。 libc 包装器对其进行解码以实现第 2 节手册页中描述的 errno 设置并返回 -1 行为,该手册页主要记录了包装器; “C 库/内核差异”的详细信息有时可以在 Linux 手册页的注释部分找到。
It's important to note that this applies to most but not all system calls, as the first paragraph says. sys_fork
is not special in this regard. A couple interesting special cases are getpriority
as mentioned in the beginning of errno(3) http://man7.org/linux/man-pages/man3/errno.3.htmlmore below, and mmap
. (Valid pointers can have their high bit set, so distinguishing error from success requires other tricks, like checking the low bits since a successful mmap always returns a page-aligned address http://nullprogram.com/blog/2016/09/23/.) These ABI details are not documented in the man pages.
为了查明是否sys_fork
调用成功,测试负值就足够了:
test eax, eax
jl _error_handler ;See Peter Cordes's comments below
我已经包含了有关 C 库包装器的部分,例如fork(2) http://man7.org/linux/man-pages/man2/fork.2.html因为它提供了一种找出错误号的实用方法。
的价值errno
,取反,是系统调用可能返回的可能错误值。
EAGAIN
伊诺梅
伊诺西斯
ERESTARTNOINTR
一般来说,C 库包装器可以在将返回值写入之前添加、删除或转码errno
,所以这是失败的。
找出可能的返回值的最终方法是查看源代码。
例如,do_fork http://elixir.free-electrons.com/linux/v3.3/source/kernel/fork.c#L1515,由调用sys_fork
, 可以返回EINVAL
and EPERM
除了上面列出的值之外。
其他值也是可能的,我没有深入研究所有嵌套函数调用。
sys_clone
还调用do_fork
所以我假设clone(2) http://man7.org/linux/man-pages/man2/clone.2.html#ERRORS可以返回所有的错误号fork(2)
can.
调查案件sys_getpriority http://elixir.free-electrons.com/linux/latest/source/kernel/sys.c#L252上面提到了一条评论
/*
* Ugh. To avoid negative return values, "getpriority()" will
* not return the normal nice-value, but a negated value that
* has been offset by 20 (ie it returns 40..1 instead of -20..19)
* to stay compatible.
*/
看来Linux系统调用always发生错误时返回负值,C 库包装器尝试将这些值规范化为errno
,引入额外的复杂性层。
正如我们从mmap
在这种情况下,设置符号位并不总是意味着它是错误值。
根据这个答案 https://stackoverflow.com/questions/18996410/linux-kernel-system-call-returns-1-instead-of-1-256/18998521#18998521(下面的 Peter Cordes 评论值得称赞),值在该范围内[-4095,-1]总是意味着错误,但其他负值不应该。