我有一个Linux x86-32 GAS汇编程序,终止如下:
movl $1, %eax
movl $0, %ebx # argument for _exit
int $0x80
当我像这样退出时,程序正常运行,但如果我尝试读取stdout输出,我什么也得不到(使用ie less或wc)。
我尝试编译一个最小的C程序并比较strace输出。我发现的唯一区别是,GCC使得C程序(int main() { printf("donkey\n"); }
)在strace输出中隐含地退出exit_group(0)
。
我尝试修改我的ASM程序以退出call exit
而不是原始系统调用。 stdout现在可以正常阅读。
测试用例
.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
我甚至会遇到段错误。
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
EDIT2:
好的,它现在适用于所有人。我使用了从这里复制的错误的调用约定:Printf without newline in assembly
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
$
谢谢大家,特别是没有。
答案 0 :(得分:3)
当你将stdout传递给wc时,stdout变得完全缓冲。
_exit立即终止进程,不运行atexit()和其他清理处理程序。运行时将注册这些处理程序,以便在退出时运行,以刷新打开的FILE *,例如stdout。当这些处理程序在退出时没有执行时,缓冲的数据将会丢失。
如果在printf调用之后调用fflush(stdout)
,或者如果你只是在一个consol中运行程序而没有将输出传递给另一个程序,你应该看到输出 - 在这种情况下,stdout通常是行缓冲的,所以stdout每当你写一个\ n
答案 1 :(得分:2)
发送到标准输出的输出通常是缓冲的。如果您在致电fflush(stdout)
之前致电_exit
,则应获得输出。
exit
工作的原因是因为在调用_exit
本身实际终止程序之前,该函数保证关闭并刷新任何打开的流(例如stdout)。
答案 2 :(得分:1)
根据_exit(2)
是否刷新标准I / O缓冲区并删除临时文件 使用tmpfile(3)创建的是依赖于实现的。在另一 手,_exit()确实关闭打开的文件描述符,这可能会导致 未知延迟,等待待处理输出完成。如果延迟是 不希望的,之前调用tcflush(3)之类的函数可能很有用 调用_exit()。是否有任何挂起的I / O被取消,以及哪些 挂起的I / O可能会在_exit()时被取消,与实现有关。
因此除非你刷新了stdout,否则它可能会被丢弃。