在 x86 程序集中手动设置 errno 时,perror() 打印“未知错误-编号”而不是“消息”

问题描述

我正在编写汇编代码以在文件描述符中写入字节,在 Linux 中使用 nasmgcc。我想重新创建 C 函数 write 的行为。如果fd错误,或者写入的地址为NULL,我通过调用extern __errno_location(Linux定义)到代码错误号来设置errno值,然后返回(rax)到-1,作为write 函数可以。

            section .text
            global  ft_my_write
            extern  __errno_location

ft_my_write:
        mov     rax,1      ;syscall write,rax = 1,rdi = fd,rsi = char*,rdx = num bytes
        syscall
        cmp     rax,0
        jl      error
        ret
error:
        push    rax
        call    __errno_location wrt ..plt  ;wrt..pl avoids overflow in R_X86_64_PC32 relocation
        mov     rdi,rax
        pop     rax
        mov     [rdi],rax
        mov     rax,-1
        ret

现在,如果我将它与错误的示例一起使用,例如错误的 fd 或 NULL 地址,我会看到我得到了正确的 errno 编号(从 rax写入系统调用):-9 和 -14,但 perror() 消息打印未知错误,而不是 Bad file descriptorBad address 消息原始 write 函数打印的内容。

int i,j;
i = ft_my_write(-1,"hello\n",5);
perror("errno");       -------------------> prints 'errno: Unknown error -9'
j = write(-1,5);
perror("errno");       -------------------> prints 'errno: Bad file descriptor'     
printf ("num bytes = %d (%d)\n",i,j); --> prints 'num bytes = -1 (-1)'

同样

int i,j;
i = ft_my_write(11,NULL,5);
perror("errno");       -------------------> prints 'errno: Unknown error -14' 
j = write(1,5);
perror("errno");       -------------------> prints 'errno: Bad address'     
printf ("num bytes = %d (%d)\n",j); --> prints 'num bytes = -1 (-1)'

这种差异从何而来?为什么 perror() 似乎没有正确解释错误代码,尽管 errno 显然设置为正确的值?

解决方法

这是因为errno的值(你使用errno_location后修改的值)需要为正数。内核 ABI 在出错时返回 -errno; -4095 .. -1 中的值,只是为了区分错误和成功。

您可以使用 neg eax 使其为正。

(请注意,它是 int errno,您应该只将 dword 而不是 qword 存储到您从 __errno_location 获得的指针中)

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...