【问题标题】:linux x86 assembly language sys_read call should have first argument as 0 (stdin)linux x86 汇编语言 sys_read 调用的第一个参数应为 0 (stdin)
【发布时间】:2018-02-23 06:28:25
【问题描述】:

我正在编写一个简单的汇编程序以从标准输入中读取(如 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。

【问题讨论】:

    标签: linux assembly x86 file-descriptor


    【解决方案1】:

    当您测试它时,您正在运行程序,其中 stdin、stdout 和 stderr 都连接到您的终端。碰巧文件 description 引用的所有 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:该符号链接上的权限反映了它是读、写还是读+写 fd。

    【讨论】:

    • 对问题的出色而准确的答案。谢谢。
    猜你喜欢
    • 2019-02-13
    • 2013-04-21
    • 1970-01-01
    • 1970-01-01
    • 2023-03-25
    • 1970-01-01
    • 2015-04-05
    • 1970-01-01
    • 2017-01-03
    相关资源
    最近更新 更多