从 NASM 中的非阻塞标准输入读取
Reading from non-blocking stdin in NASM
将 stdin 设置为非阻塞,然后进行读取系统调用的示例代码。
section .text
global _start
_start:
mov eax, 55 ; __NR_fcntl
mov ebx, 0
mov ecx, 4 ; F_SETFL
mov edx, 2048 ; O_RDONLY|O_NONBLOCK
int 0x80
mov eax, 3 ; __NR_read
mov ebx, 0
mov ecx, buf
mov edx, 1024
int 0x80
mov [br], eax
mov eax, 4 ; __NR_write
mov ebx, 1
mov ecx, buf
mov edx, [br]
int 0x80
mov eax, 1 ; __NR_exit
mov ebx, 0
int 0x80
section .bss
buf resb 1024
br resd 1
预期行为:程序退出时不打印任何内容,因为我希望在 EAX 中 read
到 return 0
当没有任何内容可读时(在终端上)。
当前行为:程序打印 4 个随机字节作为 read
returns -11
当没有传递给标准输入时。
$ strace ./nonblocking
execve("./nonblocking", ["./nonblocking"], 0x7fff196fcb40 /* 53 vars */) = 0
strace: [ Process PID=4112759 runs in 32 bit mode. ]
fcntl(0, F_SETFL, O_RDONLY|O_NONBLOCK) = 0
read(0, 0x804a000, 1024) = -1 EAGAIN (Resource temporarily unavailable)
write(1, "[=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=]"..., 4294967285����) = 4096
exit(0) = ?
(编者注:[=17=]
在终端上打印为零宽度,但问题所讨论的 4 非零 字节是 -11
br
中的双字,开始输出 1024 个字节。)
Linux 系统调用 return -errno
错误值。 read
是 returning -EAGAIN
在没有字节 "ready" 的设备上记录的非阻塞 I/O,因此 EAX = -11
在其位模式中有 4 个非零字节。
您实际上并没有打印 4 个字节,您正在向 write
传递一个巨大的值。它一直写到页尾。它不是 returning -EFAULT
,而是 return 它实际从缓冲区复制到文件描述符的字节数,即使它因为遇到未映射的页面而停止。
将输出写入终端会降低其可见性,除非您查看 strace 输出。 ASCII NUL([=16=]
,一个零字节)在标准 VT100 式终端上打印为零宽度,但在其他上下文中,这与不写任何内容非常 not 相同. 运行
./nonblocking | hexdump -C --no-squeezing
查看您写入标准输出的 4kB 零字节。
顺便说一句,将 EAX 存储到内存只是为了再次加载它是没有意义的。就 mov edx, eax
.
当用户键入 control-D 时,您只会在 TTY 上收到 EOF。 (假设 "cooked" 模式和默认 stty
设置)。
非阻塞不会将无数据就绪变为 EOF;那将无法区分文件的实际结尾! (常规文件上的非阻塞 I/O 会在文件末尾给你 EOF,或者 -EAGAIN
如果文件还没有从磁盘中获取,所以你必须阻塞 I/O.)
read
returns 0
(意思是EOF)的情况对于阻塞和非阻塞是一样的read
.
如果阻塞 read
会坐在那里等待用户键入内容(并且 "submit" 它在行缓冲熟化模式下使用 return 或 control-D),非阻止 read
将 return -EAGAIN
.
来自 Linux read(2)
手册页:
EAGAIN
The file descriptor fd refers to a file other than a socket
and has been marked nonblocking (O_NONBLOCK), and the read
would block. See open(2) for further details on the
O_NONBLOCK flag.
将 stdin 设置为非阻塞,然后进行读取系统调用的示例代码。
section .text
global _start
_start:
mov eax, 55 ; __NR_fcntl
mov ebx, 0
mov ecx, 4 ; F_SETFL
mov edx, 2048 ; O_RDONLY|O_NONBLOCK
int 0x80
mov eax, 3 ; __NR_read
mov ebx, 0
mov ecx, buf
mov edx, 1024
int 0x80
mov [br], eax
mov eax, 4 ; __NR_write
mov ebx, 1
mov ecx, buf
mov edx, [br]
int 0x80
mov eax, 1 ; __NR_exit
mov ebx, 0
int 0x80
section .bss
buf resb 1024
br resd 1
预期行为:程序退出时不打印任何内容,因为我希望在 EAX 中 read
到 return 0
当没有任何内容可读时(在终端上)。
当前行为:程序打印 4 个随机字节作为 read
returns -11
当没有传递给标准输入时。
$ strace ./nonblocking
execve("./nonblocking", ["./nonblocking"], 0x7fff196fcb40 /* 53 vars */) = 0
strace: [ Process PID=4112759 runs in 32 bit mode. ]
fcntl(0, F_SETFL, O_RDONLY|O_NONBLOCK) = 0
read(0, 0x804a000, 1024) = -1 EAGAIN (Resource temporarily unavailable)
write(1, "[=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=]"..., 4294967285����) = 4096
exit(0) = ?
(编者注:[=17=]
在终端上打印为零宽度,但问题所讨论的 4 非零 字节是 -11
br
中的双字,开始输出 1024 个字节。)
Linux 系统调用 return -errno
错误值。 read
是 returning -EAGAIN
在没有字节 "ready" 的设备上记录的非阻塞 I/O,因此 EAX = -11
在其位模式中有 4 个非零字节。
您实际上并没有打印 4 个字节,您正在向 write
传递一个巨大的值。它一直写到页尾。它不是 returning -EFAULT
,而是 return 它实际从缓冲区复制到文件描述符的字节数,即使它因为遇到未映射的页面而停止。
将输出写入终端会降低其可见性,除非您查看 strace 输出。 ASCII NUL([=16=]
,一个零字节)在标准 VT100 式终端上打印为零宽度,但在其他上下文中,这与不写任何内容非常 not 相同. 运行
./nonblocking | hexdump -C --no-squeezing
查看您写入标准输出的 4kB 零字节。
顺便说一句,将 EAX 存储到内存只是为了再次加载它是没有意义的。就 mov edx, eax
.
当用户键入 control-D 时,您只会在 TTY 上收到 EOF。 (假设 "cooked" 模式和默认 stty
设置)。
非阻塞不会将无数据就绪变为 EOF;那将无法区分文件的实际结尾! (常规文件上的非阻塞 I/O 会在文件末尾给你 EOF,或者 -EAGAIN
如果文件还没有从磁盘中获取,所以你必须阻塞 I/O.)
read
returns 0
(意思是EOF)的情况对于阻塞和非阻塞是一样的read
.
如果阻塞 read
会坐在那里等待用户键入内容(并且 "submit" 它在行缓冲熟化模式下使用 return 或 control-D),非阻止 read
将 return -EAGAIN
.
来自 Linux read(2)
手册页:
EAGAIN
The file descriptor fd refers to a file other than a socket and has been marked nonblocking (O_NONBLOCK), and the read would block. See open(2) for further details on the O_NONBLOCK flag.