Linux下x86汇编中系统调用的错误处理

时间:2018-07-06 18:48:27

标签: assembly x86 nasm x86-64

在Linux下,我找不到关于如何正确实现x86程序集中的系统调用错误处理的明确答案。

Shows,从系统调用返回的寄存器rax包含系统调用的结果。 -4095到-1之间的值表示错误。

从逻辑上讲,如果我们“查看” rax中的返回值,并且该值在此范围内,则可以得出结论:发生了错误,并且可以对该信息采取适当措施。

但是,我们如何知道返回值确实是负值?这实际上是我提出问题的基础,因为我的理解是,如果我们这样对待给定的二进制模式,则其值仅是负值。

例如,为便于说明,我们假设系统调用的返回值为“ -4000”。现在,传递给rax的实际返回值实际上不是-4000,而是可以这样解释的二进制模式。在从系统调用解释返回值的情况下,我们如何区分这种二进制模式的一种可能解释和另一种解释?换句话说,我们如何知道返回值(二进制模式)不代表无符号等效项?

诚然,这将是一个相对较大的数字。但是,这不是合理的情况吗?毕竟,rax仅包含位,我们是否将这些位视为代表负数取决于解释/实现?

到目前为止,我发现了两个示例,这些示例说明了x86 asm(one , two)中系统调用的错误处理以类似的方式解决了该问题。首先,他们执行“幻像”操作,例如or eax,eax,以设置适当的flags,接着,他们测试符号标志(SF)的条件,以查看符号位是否已设置,以及采取相应行动。

同样,我不明白我们如何从科学基金会确定该数字实际上为负。它仅表示符号位(最高有效位)已被设置。

作为示例,假设我们的代码实现了系统调用,返回值为0x8000 0000 0000 0000h:

    mov rax,8000000000000000h   ; The illustrative return value from our syscall
    test rax,rax                ; Perform 'test' to set flags accordingly 
    jns Exit                    ; If SF set, 'fall-through' to 'Error'

; Write error message to stdout:
Error:
    mov rax,4                  ; sys_write 
    mov rbx,1                  ; File descriptor 1, stdout
    mov rcx,ErrorMsg           ; Pass offset of message
    mov rdx,ERRORLEN           ; Length of error message
    int 80h                    ; Kernel call

; Exit program:
Exit:
    mov rax,1                  ; exit system call
    mov rbx,0                  ; return a code of zero
    int 80h                    ; make kernel call

在这种情况下,我们会(错误地)假设发生了错误,将错误消息写入stdout并退出程序。我赞赏这种情况不太可能发生。但是,我将其声明为可能的错误是错误的吗?如果是这样,为什么?

或者,简单地讲,答案是,鉴于Linux下的所有系统调用,都没有可能的返回值,该返回值会返回足以将符号位设置为64位数字的值;还是32位数字?

如何在Linux下实现对系统调用的错误处理,从而避免出现上述情况。

在Linux下,x86 asm中错误处理系统调用的标准约定是什么?

............................................... .....

NASM 2.11.08版x86架构| Ubuntu 16.04

1 个答案:

答案 0 :(得分:4)

系统调用的合法返回值始终为正(有符号)整数或地址。当它们为正整数时,负值可以用作错误代码,因此任何负值都是错误。

因此,唯一棘手的情况是返回值是地址。事实证明,与-4096 ..- 1范围内的整数对应的地址全部在内核保留的页面中,内核永远不会返回-因此该范围内的任何位模式都只会作为错误返回代码,而不是有效地址。

此外,与x86_64中的负整数相对应的所有地址都为内核保留或无效-用户地址将始终在0..2 47 -1范围内。因此,对于x86_64,您只需要检查%rax的符号位(最高位)-如果将其设置,则出现错误。

test %rax, %rax
js   error

不是32位x86代码,情况并非如此-一些有效地址为负数。因此,在这种情况下,您需要显式检查错误范围,这实际上是最简单的无符号比较

cmpl  %eax, 0xfffff000   # unsigned 2^32 - 4096, aka signed -4096
ja    error              # -4095 .. -1 is an error, anything else is non-error