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

时间:2017-06-28 18:50:53

标签: linux assembly x86-64 system-calls

我知道如果出现错误,在C中调用fork()将返回-1,但我想知道在程序集中调用sys_fork时错误返回值是什么。

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

有没有人知道汇编中的fork错误返回值是什么?

(我在Linux上进行64位NASM汇编)

1 个答案:

答案 0 :(得分:3)

首先请注意,C库包装器fork(2)调用sys_clone而非sys_fork

  

C库/内核差异

     

从版本2.3.3开始,而不是调用内核的fork()系统
  调用,作为NPTL的一部分提供的glibc fork()包装器   线程实现使用提供
的标志调用clone(2)   与传统系统调用相同的效果。

introduction to the section 2 of the Linux manual解释了如何在一般上下文中解释系统调用的返回值:

  

返回值

     

出错时,大多数系统调用都会返回负数错误号(即,   否定了errno(3)中描述的常量之一的值。 C
  库包装器从调用者隐藏这个细节:当系统调用时   返回负值,包装将绝对值复制到
  errno变量,并返回-1
作为
的返回值   包装

因此,对于大多数系统调用,EAX / RAX在出错时保持-ESOMETHING,或在成功时保持非负结果。 libc包装器对此进行解码,以实现第2节手册页中描述的errno设置和返回-1行为,该手册主要记录包装器; " C库/内核差异"有时会在Linux手册页的Notes部分找到详细信息。

重要的是要注意,这适用于大多数但不是所有系统调用,如第一段所述。 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

我已经包含了关于像fork(2)这样的C库包装器的部分,因为它提供了一种找出错误编号的实用方法。
errno的值,否定,是系统调用可以返回的可能错误值。

  

EAGAIN
  ENOMEM
  ENOSYS
  ERESTARTNOINTR

通常,C库包装器可以在将返回值写入errno之前添加,删除或转码它们,因此这是可用的。

找出可能的回报值的明确方法是查看来源 例如,由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案例中看到的那样,设置符号位并不总是意味着它是一个错误值。 根据{{​​3}}(下面的Peter Cordes评论的优点), [ - 4095,-1] 范围内的值始终表示错误,但其他负值不应该。