Linux 为什么退出(0)(通过系统调用退出)会阻止我接收任何标准输出内容?
我有一个Linux x86-32气体组装程序,终止方式如下:Linux 为什么退出(0)(通过系统调用退出)会阻止我接收任何标准输出内容?,linux,assembly,interrupt,system-calls,gnu-assembler,Linux,Assembly,Interrupt,System Calls,Gnu Assembler,我有一个Linux x86-32气体组装程序,终止方式如下: movl $1, %eax movl $0, %ebx # argument for _exit int $0x80 当我像这样退出时,程序正常运行,但是如果我尝试读取标准输出,我将一无所获(使用less或wc) 我试着编译一个最小的C程序并比较strace的输出。我发现的唯一区别是,GCC使C程序(intmain(){printf(“ad驴”;})在strace输出中隐式地退出exit_组(0) 我试图修改我的ASM程序以退出ca
movl $1, %eax
movl $0, %ebx # argument for _exit
int $0x80
当我像这样退出时,程序正常运行,但是如果我尝试读取标准输出,我将一无所获(使用less或wc)
我试着编译一个最小的C程序并比较strace的输出。我发现的唯一区别是,GCC使C程序(intmain(){printf(“ad驴”;}
)在strace输出中隐式地退出exit_组(0)
我试图修改我的ASM程序以退出callexit
,而不是原始系统调用。标准输出现在可以正常读取了
测试用例
.data
douout: .string "monkey\n"
.text
.globl main
main:
pushl $douout
call printf
# Exit
movl $1, %eax
movl $0, %ebx
int $0x80
编译并运行:
$ yasm -g dwarf2 -f elf -p gas t.asm && gcc -g -melf_i386 -o t t.o && ./t | wc -c
0
预期:
7
编辑:
我尝试调用tcflush
和fflush
,但仍然存在问题。使用fflush
时,我甚至出现了一个segfault
0xb7e9e7c9 in _IO_fflush (fp=0x804a018) at iofflush.c:42
42 iofflush.c: No such file or directory.
in iofflush.c
(gdb) bt
#0 0xb7e9e7c9 in _IO_fflush (fp=0x804a018) at iofflush.c:42
#1 0x08048434 in main () at t.asm:12
(gdb) frame 1
#1 0x08048434 in main () at t.asm:12
12 call fflush
(gdb) list
7
8 pushl $douout
9 call printf
10 # Exit
11 movl $0, %eax
12 call fflush
13 movl $1, %eax
14 movl $0, %ebx
15 int $0x80
编辑2:
好了,大家都知道了。我使用了从这里复制的错误呼叫约定:
与往常一样,fflush
的参数应该在堆栈上
$ cat t.asm
.data
douout: .string "monkey\n"
.text
.globl main
main:
pushl $douout
call printf
# Exit
pushl $0
call fflush
movl $1, %eax
movl $0, %ebx
int $0x80
$ yasm -g dwarf2 -f elf -p gas t.asm && gcc -g -melf_i386 -o t t.o && ./t | wc -c
7
$
谢谢大家,尤其是nos。发送到标准输出的输出通常是缓冲的。如果在调用
\u exit
之前调用fflush(stdout)
,您应该会得到输出
exit
起作用的原因是,在调用\u exit
本身以实际终止程序之前,该函数保证关闭并刷新任何打开的流(如stdout)。将stdout传输到wc时,stdout将被完全缓冲
_exit立即终止进程,并且不运行atexit()和其他清理处理程序。运行时将注册这样的处理程序,以便在刷新打开的文件*的出口(如stdout)上运行。当这些处理程序在退出时未执行时,缓冲数据将丢失
如果在printf调用之后调用
fflush(stdout)
,或者如果您只是在控制台中运行程序而没有将输出传输到另一个程序,则应该看到输出-在这种情况下,stdout通常是行缓冲的,因此根据\u exit(2)
是否刷新标准I/O缓冲区并删除临时文件
使用tmpfile(3)创建的依赖于实现。另一方面
另一方面,_exit()会关闭打开的文件描述符,这可能会导致
未知延迟,正在等待挂起的输出完成。如果延迟是
不希望的是,在之前调用tcflush(3)之类的函数可能会很有用
正在调用_exit()。是否取消任何挂起的I/O,以及
挂起的I/O可能会在_exit()时取消,具体取决于实现
因此,除非您刷新了stdout,否则它可能会被丢弃。但如果不使用管道,我确实会得到输出。另外,
man\u exit
注意到我可以使用tcflush
。我试过了,但没用。如何调用fflush(stdout)
<代码>pushl$1;调用fflush?我在unistd.h
中找到了stdout文件号。另外,我刚刚用堆栈中的1和%eax
中的1尝试了它,它们都是SEGFULT。回答自己:它需要一个文件*,而不是一个文件描述符。我尝试调用tcflush
,它似乎没有什么区别。tcflush在终端设备上工作。您需要调用fflush(stdout)。(stdout是由libc管理的全局文件*,不能使用filedescriptor)。如果您在这方面遇到问题,请调用fflush(NULL),这将刷新所有文件*。如果您没有按照通常的调用约定将正确的参数传递给fflush,参数应该在堆栈上,而不是在%eax中,您将如何调用fflush(stdout)
?根据unistd.h
文件号是1,但根据,它是0。在这个上下文中,stdout是名为stdout的全局文件*(默认情况下连接到文件描述符1,标准输出)。不能将文件描述符0或1用作期望文件*的函数的参数。您可以使用NULL作为参数调用fflush(),以刷新所有打开的文件*。但我认为程序集中没有NULL?在C中,NULL==0。它怎么会知道区别呢?你不会的。您只需使用与指针大小相同的0。但这并不意味着文件描述符为0,尽管它们的值相同。请注意,它当然会知道区别,因为它需要一个文件*而不是一个文件描述符。