2012-03-18 35 views
3

我有一個Linux的x86-32 GAS的彙編程序終止這樣的:如何將_exit(0)(通過系統調用退出)阻止我接收任何標準輸出內容?

movl $1, %eax 
movl $0, %ebx # argument for _exit 
int $0x80 

當我退出這個樣子,該程序的功能,如正常,但如果我嘗試讀取標準輸出的輸出,我什麼也沒得到(使用即少或wc)。

我試着編譯一個最小的C程序並比較strace輸出。我發現唯一的區別是,GCC在strace輸出中使C程序(int main() { printf("donkey\n"); })隱含退出exit_group(0)

我試着修改我的ASM程序退出call exit而不是原始的系統調用。標準輸出現在可以正常讀取。

測試用例

.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 

編輯:

我試過CAL凌tcflushfflush,我仍然有問題。隨着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 
$ 

謝謝大家,特別是nos。

回答

1

當您將stdout管道傳輸到wc時,標準輸出將完全緩衝。

_exit立即終止進程,不運行atexit()和其他清理處理程序。運行時將註冊這樣的處理程序,以便在退出時運行,以刷新打開的FILE *,如stdout。當這些處理程序沒有在退出時執行時,緩衝的數據將會丟失。

應該能看到輸出,如果你的printf調用之後調用fflush(stdout),或者如果你只是運行在一個統一公債程序而不輸出管道到另一個程序 - 在這種情況下,標準輸出通常會行緩衝,所以stdout是刷新時你寫一個\ n

+0

你會怎麼稱呼''fflush(stdout)''?根據''unistd.h'',fileno是1,但根據http://stackoverflow.com/questions/8502945/printf-without-newline-in-assembly,它是0. – 2012-03-18 00:58:39

+1

stdout在這個上下文中是全局FILE *命名爲stdout(默認情況下連接到文件描述符1,標準輸出)。您不能使用文件描述符(0或1)作爲需要FILE *的函數的參數。你可以用NULL作爲參數調用fflush()來刷新所有打開的FILE *。 – nos 2012-03-18 01:10:59

+0

但我不認爲程序集中有NULL?在C中,NULL == 0.它如何知道它的區別? – 2012-03-18 01:16:08

1

輸出發送到標準輸出通常是緩衝。如果您在致電_exit之前致電fflush(stdout),則應該獲得輸出結果。

原因exit的工作原理是因爲在調用_exit本身來實際終止程序之前,該函數保證關閉並刷新任何打開的流(如stdout)。

+0

但是如果我不管它,我會得到輸出。另外,'man_exit''注意我可以使用''tcflush''。我試過了,但沒有奏效。我如何調用''fflush(stdout)''? ''pushl $ 1;打電話給fflush''? – 2012-03-18 00:46:30

+0

我在''unistd.h''中找到了stdout fileno。另外,我只是用堆棧中的1和''%eax''來嘗試它們,它們都是段錯誤。 – 2012-03-18 00:50:36

+1

回覆自己:這需要一個FILE *,而不是文件描述符。 – 2012-03-18 01:34:44

1

按照手冊頁_exit(2)

無論是刷新標準I/O緩衝區,刪除tmpfile建立(3)是實現相關的臨時文件 。在另一個 手中,_exit()會關閉打開的文件描述符,並且這可能會導致未知的延遲,等待未完成的輸出完成。如果延遲是 不希望的,在調用_exit()之前調用諸如tcflush(3)之類的函數可能很有用。是否任何待處理的I/O被取消,以及哪個 待處理的I/O可能在_exit()後被取消,取決於實現。

所以,除非你刷新標準輸出,它可能會被丟棄。

+0

我試着調用''tcflush'',它似乎沒有什麼區別。 – 2012-03-18 00:52:20

+1

tcflush在終端設備上工作。你需要調用fflush(stdout)。 (標準輸出是由libc管理的全局文件*,不能使用文件描述符)。如果你遇到麻煩,請調用fflush(NULL),它將刷新所有文件*的 – nos 2012-03-18 01:05:27

+0

請參閱編輯的問題。 – 2012-03-18 01:09:09

相關問題