linux x86 汇编语言 sys_read 调用的第一个参数应该为 0 (stdin)

标签 linux assembly x86 file-descriptor

我正在编写一个简单的汇编程序来读取标准输入(如 scanf)。 这是我的代码。


section .bss
num resb 5

section .txt
global _start

_start:

mov eax,3   ;sys_read
mov ebx,0   ;fd 0
mov ecx,num
mov edx,5
int 0x80

mov eax,4   ;sys_write
mov ebx,1   ;fd 1
mov ecx,num
mov edx,5
int 0x80

mov eax,1   ;sys_exit
mov ebx,0   ;return 0
int 0x80

现在它可以正常工作了,它可以读取和打印。

因此,我尝试将 sys_read 调用中的文件描述符值更改为 1(stdout)、2(syserr)。

代码。


section .bss
num resb 5

section .txt
global _start

_start:

mov eax,3   ;sys_read
mov ebx,1   ;fd 1
mov ecx,num
mov edx,5
int 0x80

mov eax,4   ;sys_write
mov ebx,1   ;fd 1
mov ecx,num
mov edx,5
int 0x80

mov eax,1   ;sys_exit
mov ebx,0   ;return 0
int 0x80

此代码也可以正常工作。
我的问题是,即使在将文件描述符从 0 更改为 1 之后,为什么这段代码仍能正常工作。 sys_read 应该取 0 作为 fd。

最佳答案

当你测试它时,你正在运行程序,标准输入、标准输出和标准错误都连接到你的终端。碰巧的是,所有 3 个文件描述符所引用的文件描述 都是可读/可写的。

fd 0 可以阻止文件描述符被读/写,这没什么神奇的。

我认为 shell 可以分别打开只读和只写终端,而不是运行所有 3 个标准文件描述符都是相同读写文件描述的副本的程序。 (设置为 dup2 )。但这不是 bash(或启动 bash 的终端仿真器)的设计方式。


尝试运行您的 sys_read(1, ...) 版本,其中 stdin 是一个管道或文件,绝对只为读取而打开,而 stdout 是一个 fd,它只为写入而打开。

$ echo foo | strace ./read1 > foo.out
execve("./read1", ["./read1"], 0x7fff68953560 /* 52 vars */) = 0
strace: [ Process PID=31555 runs in 32 bit mode. ]
read(1, 0x80490ac, 5)                   = -1 EBADF (Bad file descriptor)
write(1, "\0\0\0\0\0", 5)               = 5
exit(0)                                 = ?
+++ exited with 0 +++

所以 read(1, num, 5) 返回了 -EBADF (错误的文件描述符),因为 fd 1 是一个只写的 fd,之前由 shell 打开这个过程的fork/execve。 write(1, ...) 仍然发生,因为您的程序没有进行任何错误检查。 (没关系;我们有像 strace 这样的工具,所以我们可以在试验系统调用时偷懒)。


但是请注意,重定向标准输入没有任何区别;你的程序从不使用 fd 0!

当 fd 1 连接到 tty 时,无论输入重定向如何,从它读取都是从终端读取。

$ echo test | strace ./read1
execve("./read1", ["./read1"], 0x7ffc3c42d620 /* 52 vars */) = 0
strace: [ Process PID=31462 runs in 32 bit mode. ]
read(1,                                   # it blocked here until I pressed return
"\n", 5)                        = 1
write(1, "\n\0\0\0\0", 5
)               = 5
exit(0)                                 = ?
+++ exited with 0 +++

在另一个终端中,当 read1 暂停等待 read() 返回时:

$ ll /proc/$(pidof read1)/fd 
total 0
lr-x------ 1 peter peter 64 Feb 22 18:17 0 -> pipe:[13443590]
lrwx------ 1 peter peter 64 Feb 22 18:17 1 -> /dev/pts/17
lrwx------ 1 peter peter 64 Feb 22 18:17 2 -> /dev/pts/17
lrwx------ 1 peter peter 64 Feb 22 18:17 49 -> socket:[405352]
lrwx------ 1 peter peter 64 Feb 22 18:17 53 -> socket:[405353]

注意 fd 1 上的 RWX:该符号链接(symbolic link)的权限反射(reflect)了它是读、写还是读+写 fd。

关于linux x86 汇编语言 sys_read 调用的第一个参数应该为 0 (stdin),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48937938/

相关文章:

c - LEAL 汇编指令有什么作用?

assembly - 如何在 x86_64 asm 中调用 malloc

c++ - 使用 pre-SSE4 计算 vector2 double 的 floor & ceil

linux - 尽管使用 gcc 链接器,但获取对汇编代码的 "_printf"错误的 undefined reference

linux - 羊群锁定顺序?

xml - 如何从 ec2 实例中的用户数据编辑 xml 行?

linux - 如何在发出 Bash 命令时将参数/输入传递给它

linux - 生成具有相同结构的多个文件

c++ - 关于反汇编输出的问题

optimization - 添加 vs mul (IA32-Assembly)