本文介绍了linux x86汇编语言sys_read调用的第一个参数应为0(stdin)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个简单的汇编程序以从stdin中读取(例如scanf).这是我的代码.

I was writing a simple assembly program to read from stdin, (like scanf).Here is my code.


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

现在,它可以正常工作了,它可以读取并打印.

Now this works normally, it reads and prints.

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

So, I tried changing file descriptor value in sys_read call to 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.

This code also works fine.
My question is , even after changing file descriptor from 0 to 1, Why this code is working normally.sys_read should take 0 as fd.

推荐答案

在测试该程序时,您正在将stdin,stdout和stderr全部连​​接到终端的情况下运行该程序.碰巧文件 description 所引用的所有三个文件描述符都是读/写的.

When you tested it, you were running the program with stdin, stdout, and stderr all connected to your terminal. It just happens that the file description all 3 of those file descriptors referred to was a read/write.

使用fd 0阻止读取/写入文件描述符并没有什么魔力.

There's nothing magic about being fd 0 that stops a file descriptor from being read/write.

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

I think a shell could separately open the terminal for read-only and for write-only, instead of running programs with all 3 standard file descriptors being duplicates of the same read-write file description. (set up with dup2). But that's not how bash (or the terminal emulator that started bash) is designed.

尝试运行您的sys_read(1, ...)版本,其中stdin是绝对仅用于读取而打开的管道或文件,而stdout是仅用于写入而打开的fd.

Try running your sys_read(1, ...) version with stdin being a pipe or file which is definitely opened only for reading, and stdout being an fd that's opened only for writing.

$ 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,在此过程派生/执行之前由外壳程序打开. write(1, ...)仍然发生,因为您的程序未执行任何错误检查. (很好;我们有类似strace的工具,因此在尝试系统调用时可以变得很懒.)

So read(1, num, 5) returned -EBADF (bad file descriptor), because fd 1 is a write-only fd, opened by the shell before fork/execve of this process. write(1, ...) still happened because your program doesn't do any error checking. (That's fine; we have tools like strace so we can be lazy when experimenting with system calls).

但是请注意,重定向标准输入并没有任何作用;您的程序永远不会使用fd 0!

But note that redirecting stdin doesn't make any difference; your program never uses fd 0!

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

When fd 1 is connected to the tty, reading from it reads from the terminal regardless of input redirection.

$ 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()返回:

In another terminal while read1 was paused waiting for read() to return:

$ 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.

Note the RWX on fd 1: the permissions on that symlink reflect whether it's a read, write, or read+write fd.

这篇关于linux x86汇编语言sys_read调用的第一个参数应为0(stdin)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-17 15:58