Fork系统调用失败后,rax的返回值是多少?

问题描述:

我知道在C中调用fork()将返回-1如果有错误,但我想知道当您在汇编中调用sys_fork时返回值是什么。Fork系统调用失败后,rax的返回值是多少?

我通常可能会认为它也返回-1,但我已经处理了sys_brk,并且程序集中的原始系统调用返回了与C Brk()包装不同的东西。

有谁知道fork错误返回值将在汇编中?

(我做Linux上的64位NASM组装)

+3

至少在ia32和x86_64中,IIRC通常是一个Linux系统调用,在失败时返回一个“errno”值的负值(然后glibc包装再次否定并存储到“errno”中)。 –

+0

根据[x86_64](https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI)ABI,返回值在'EAX'或'RAX'中。另请参阅[X86-64 ABI在哪里记录?](https://stackoverflow.com/q/18133812/608639) – jww

+0

他知道根据ABI @jww,返回值在'RAX'中。这是在问题中说明的。问题是如何解释* RAX中的值。换句话说,这是什么意思? –

首先需要注意的是C库包装fork(2)调用sys_clone而不是sys_fork

C库/内核差异

由于2.3.3版本,而不是调用内核的fork()系统
呼叫,glibc的叉()包装,其作为NPTL的一部分提供
线程实现调用克隆(2)的标志提供了与传统系统调用相同的效果。


introduction to the section 2 of the Linux manual说明了如何解释在一般情况下的系统调用的返回值:

返回值

上的错误,大多数系统调用返回负的错误编号(即,
否定了所述常数之一的值在errno(3))。与c
库包装隐藏来自呼叫者这一细节:当一个系统调用
返回负值,包装拷贝绝对值成
errno变量,并返回-1
作为
的返回值 包装。

所以对于系统调用,EAX/RAX持有-ESOMETHING上的错误,或成功一个非负的结果。 libc包装器对此进行解码以实现在第2节手册页中描述的errno-setting和返回-1行为,主要记录包装器;有时会在Linux手册页的Notes部分找到“C库/内核差异”细节。

重要的是要注意,这适用于大多数系统调用,但不是所有的系统调用,如第一段所述。 sys_fork在这方面并不特别。一对有趣的特殊情况是getpriority,如errno(3)开头所述,更多地低于mmap。 (有效指针可以设置其高位,因此区分错误与成功需要其他技巧,like checking the low bits since a successful mmap always returns a page-aligned address。)这些ABI细节未在手册页中记录。


对于找出如果sys_fork调用成功的目的,测试负值是不够的:

test eax, eax 
jl _error_handler    ;See Peter Cordes's comments below 

我已经包含对C库的包装像fork(2)的一部分,因为它给出了找出错误数字的实用方法。
否定的errno的值是系统调用可能返回的错误值。

EAGAIN
ENOMEM
ENOSYS
ERESTARTNOINTR

一般情况下,C库包装可以添加,删除或写入它们变成errno之前转码的返回值,所以这是failable。

找出可能的返回值的确切方法是查看源代码。
例如,由sys_fork调用的do_fork除了上面列出的值之外,还可以返回EINVALEPERM
其他值是可能的,我没有挖掘到所有的嵌套函数调用。

sys_clone还援引do_fork,所以我会假设, clone(2)可以返回的所有错误数字,用于fork(2)即可。


调查的评论上述sys_getpriority的情况下想出了

/* 
* 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系统调用上的错误总是返回负值,C库包装相比,在试图将这些值标准化为errno,引入额外的复杂层。

正如我们从mmap的情况看到的那样,设置符号位并不总是意味着它是错误值。 根据this answer(优点参见下面的Peter Cordes评论),[-4095,-1]范围内的值总是表示错误,但其他负值不应该。

+0

'test/jl'会比'test/js'更高效,因为它可以在Intel SnB系列上进行宏观融合。在比较零之后,行为是相同的,因为测试小于零与测试符号位相同。 –

+0

你确定你需要测试完整的'rax',而不仅仅是'eax'吗? 'pid_t'是一个32位的类型,所以我认为在这里避免使用REX前缀是安全的。 (实际上,你确定返回值是符号扩展在所有出到64位?) –

+0

@PeterCordes老实说,我不知道,我相信这个问题下的意见认为在最坏的PID应该签署扩展样句柄在Windows中。我会根据您的意见更正答案。谢谢! –