问题描述
我正在编写汇编代码以在文件描述符中写入字节,在 Linux 中使用 nasm 和 gcc。我想重新创建 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 descriptor 或 Bad 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
获得的指针中)