AOSP非显而易见的syscall()实现

时间:2017-11-29 11:39:22

标签: assembly linux-kernel arm libc

据我所知,ARM ABI for ARM声明syscall返回值是通过r0传递的,如果它是负数,则它应该被线程化为errno值否定。即系统调用最终出现了一些错误。 AOSP does this check以某种奇特的方式:

ENTRY(syscall)
    mov     ip, sp
    stmfd   sp!, {r4, r5, r6, r7}
    .cfi_def_cfa_offset 16
    .cfi_rel_offset r4, 0
    .cfi_rel_offset r5, 4
    .cfi_rel_offset r6, 8
    .cfi_rel_offset r7, 12
    mov     r7, r0
    mov     r0, r1
    mov     r1, r2
    mov     r2, r3
    ldmfd   ip, {r3, r4, r5, r6}
    swi     #0
    ldmfd   sp!, {r4, r5, r6, r7}
    .cfi_def_cfa_offset 0
    cmn     r0, #(MAX_ERRNO + 1) /* Set C flag if r0 is between -4095 and -1, set Z flag if r0 == -4096 */
    bxls    lr                   /* return if Z is set or C is clear */
    neg     r0, r0
    b       __set_errno_internal
END(syscall)

看起来这个函数不会成为威胁r0 < -4096的错误条件。虽然它应该。当然,真正的errno将适合允许的差距,但无论如何,以这种方式执行检查的理由是什么,而不是仅仅测试r0的否定性?

P.S。如果我错过了某些内容或只是我的分析不正确 - 任何评论都会受到赞赏。

3 个答案:

答案 0 :(得分:3)

如果解释为带符号的数字,*ngIf="item === 'somevalue'"的返回值通常为负。

答案 1 :(得分:3)

这是Linux的系统调用ABI / API的设计方式,以避免在一小组错误代码中使用一半可能的返回值。 (没有人需要超过4095个errno代码?)

正如@Timothy指出的那样,mmap是一个很好的例子:它需要返回一个指针。 mmap的返回值始终是页面对齐的,因此对于具有4k页或更大页面的系统(即几乎(?)所有内容),-4095是您可以使用的最高幅度负数,而不是有效的页面地址。

在32位2的补码系统中,

-4095 = 2^32 - 4095。最高的网页起始地址为2^32-4096 。这是明确选择范围的明显动机,即那些意味着“错误”的范围。

意味着错误的值的范围在理论上是平台依赖的并且是系统调用ABI的一部分,但AFAIK Linux在它支持的每个平台上使用[-4095..-1]。 MUSL libc实现在C源文件中硬编码-4096UL,该文件不是x86或特定于ARM的:/src/internal/syscall_ret.c。正如@Tsyvarev指出的那样,Linux将MAX_ERRNO定义为4095 in include/linux/err.h,而不是特定于arch的标头。 (注释指出,如果需要它可以使它成为特定于arch的,并且由于内核指针的工作方式而特别选择它。)

x86-64 System V ABI确实有一个关于Linux系统调用的信息性(非规范性)部分,其中指定了-4095-1范围。 (Search for -4095)。

有趣的事实:sys_getpriority无法直接返回nice级别。而是it returns 20-nice, which maps the -20..19 range of nice values to 40..1。通用包装器可以使用retval > -4096UL检查错误,因为所有系统调用都避免返回该范围内的非错误值,即使它们必须通过环形跳转来执行此操作。

相关:

答案 2 :(得分:2)

对于errno值的Apper限制4095是有意的,并且在代码中使用这些知识是可以的。实际上,这会修改值的模型,通过系统调用和其他一些内核函数返回到:

  • [-4095 ... -1] - 错误
  • 其他值 - 结果

此模型允许更多可能的结果值。例如,如果将结果解释为无符号长整数,则结果的值范围从[0... (MAX/2)]扩展到[0 ... (MAX - 4096)]。这很有用,例如当结果是指针时,请参阅IS_ERR宏的implementation