2016-01-23 55 views
1

我期待了解程序集級別的printf()語句。然而,大部分彙編程序都會執行一些操作,例如調用外部打印函數,這些函數的依賴性由鏈接器添加的其他對象文件滿足。我想知道打印函數內部的系統調用和非常基本的彙編代碼。對於printf,我需要一個彙編代碼,其中唯一的外部調用是系統調用。我在想像一個de組裝的對象文件。我在哪裏可以得到類似的東西?只有系統調用才能在程序集中獲得printf?

+1

在大多數情況下,printf()代碼通過putchar()調用操作系統write()。 –

+0

但是,我怎麼可能反彙編我的Linux上的東西,看看它是怎麼做到的????所以putchar()只是一個write()?? – user2277550

回答

5

我建議改爲先留在C級,然後研究一下Linux上一些現有的C標準庫free software實現的源代碼。查看musl-libcGNU libc(又名glibc)的源代碼。你會明白,在printf和基本系統調用(在syscalls(2) ...中列出)之間有幾個中間(通常是內部)函數是有用的。對printf(例如,通常的hello-world示例)的樣本C程序也使用strace(1)

特別是,musl-libc有一個非常可讀的stdio/printf.c實現,但在到達write(2)系統調用之前,您需要遵循其他幾個C函數。請注意,有些涉及buffering。另見setvbuf(3) & fflush(3)。幾個答案(例如thisthat一)解釋功能之間的鏈,如printf和系統調用(直到內核代碼)。

我想一段彙編代碼,唯一的外線呼叫系統呼叫,printf

如果你想正是這一點,你可以從MUSL-libc中stdio/printf.c開始,從musl-libc添加任何額外的源文件,直到你沒有更多的外部未定義的符號,並編譯所有的gcc -flto -O2或許也-S,你可能會以對象(或彙編)形式完成大部分musl-libc b因爲printf可能會呼叫malloc和許多其他功能!)...我不知道這是值得的痛苦。

您還可以靜態鏈接您的libc(例如libc.a)。然後鏈接器將鏈接printf(以及您調用的任何其他函數)所需的靜態庫成員。


挑剔,system calls實際上並沒有外線電話(你的libc write函數實際上是圍繞着原始的系統調用一個小包裝)。您可以使用SYSENTER機器指令來製作它們(但使用vdso(7)更可取:更便攜,也許更快),並且甚至不需要有效的堆棧指針(在x86_64上)來進行系統調用。

您可以編寫Linux用戶級程序,甚至不需要使用libc; Scheme的bones實現就是這樣一個程序(你會找到其他的)。

3

函數printf()位於標準C庫中,所以它被鏈接到您的程序中並且不會複製到它中。動態鏈接庫可節省內存,因爲每個使用它的程序都沒有在常駐內存中複製完全相同的代碼。

想想printf()的功能。解釋格式化的字符串並生成正確的輸出相當複雜。 printf()所屬的一系列函數也緩衝輸出。你可能並不是真的想在彙編中重新實現所有這些。標準的C庫是無所不在的,並且可能爲您提供。

也許你正在尋找write(2),這是系統調用只緩衝寫入文件描述符的字節。您必須生成預先打印的字符串並自行設置格式。 (也open(2)打開文件見。)

拆解二進制文件,你可以使用objdump

objdump -d binary 

其中binary是一些編譯好的二進制。這給出了操作碼和人類可讀指令。你可能想重定向到一個文件並在別處讀取。

您可以在您的系統上反彙編標準C二進制文件,並嘗試解釋它,如果你想(強烈不推薦)。問題在於它太複雜而難以理解。像printf()這樣的東西是用C編寫的,然後編譯和彙編。你不能(在合理的幾十年內)從編譯(非平凡)程序的彙編中恢復高級結構。如果你真的想試試這個,祝你好運。

更簡單的做法是查看printf()本身的C源代碼。真正的工作實際上是在vfprintf()中完成的,它位於GNU C庫source codestdio-common/vfprintf.c中。

+0

我不想重新實現它,我知道它爲什麼這樣做。我只想看看它是如何實現的...... – user2277550

+1

*「在標準的C庫中,所以它被鏈接到你的程序中,而不是複製到它」*不一定是真的。許多較舊的系統將整個運行時間庫鏈接到生成可執行文件。可共享的動態鏈接庫是一個相對較新的創新。由於OP沒有指定任何特定的環境,因此假定現代高效的環境是不準確的。 – wallyk

相關問題