2010-03-30 114 views
42

我想編譯我的C代碼而沒有(g)libc。我如何禁用它以及哪些功能依賴於它?沒有libc編譯

我試過-nostdlib,但它沒有幫助:代碼是可編譯的並且運行,但我仍然可以在我的可執行文件的hexdump中找到libc的名稱。

+1

'-nostdlib'應該這樣做,您使用什麼平臺/編譯器版本? – 2010-03-30 20:36:23

+0

「沒有幫助」,因爲在那裏沒有禁用庫,或者你不能用該標誌編譯任何東西? – 2010-03-30 20:47:28

+3

你可能也想要-nostartupfiles。 – 2010-03-30 22:03:23

回答

53

如果你用-nostdlib編譯你的代碼,你將無法調用任何C庫函數(當然),但你也不會得到常規的C引導代碼。特別是,Linux上程序的真正入口點不是main(),而是一個名爲_start()的函數。標準庫通常提供一個運行一些初始化代碼的版本,然後調用main()。

嘗試用gcc編譯-nostdlib此:

void _start() { 

    /* main body of program: call main(), etc */ 

    /* exit system call */ 
    asm("movl $1,%eax;" 
     "xorl %ebx,%ebx;" 
     "int $0x80" 
    ); 
} 

的_start()函數應始終以一個呼叫結束退出(或其他非返回系統調用如exec)。上面的示例直接調用了內聯彙編的系統調用,因爲通常的exit()不可用。

+3

對於64位,彙編代碼如下所示:'asm(「mov rax,60; mov rdi,0; syscall」)'。 – sigalor 2016-05-03 18:03:27

+3

添加到@ sigalor的評論中,要用'gcc'編譯,你需要使用AT&T語法,所以它應該如下所示:'asm(mov $ 60,%rax; mov $ 0,%rdi; syscall)' – lanoxx 2016-05-11 11:59:22

+0

@ataylor:爲什麼_start()函數應該總是以調用exit()結束?如果我不在start()函數中寫入exit()會怎麼樣? – Destructor 2017-05-25 05:52:27

6

將C代碼編譯爲目標文件(gcc -c以獲得*.o文件)並將其直接鏈接到鏈接器(ld)的最簡單方法。您必須將目標文件與一些額外的目標文件(如/usr/lib/crt1.o)鏈接起來,才能獲得可執行的可執行文件(在內核看到的入口點和main()函數之間,有一些工作要做) 。要知道要鏈接什麼,請嘗試使用gcc -v與glibc鏈接:這應該顯示通常進入可執行文件的內容。

你會發現gcc生成的代碼可能對一些隱藏的函數有一些依賴關係。他們大多數在libgcc.a。可能還有隱藏的電話memcpy()memmove()memset()memcmp(),它們位於libc中,因此您可能需要提供自己的版本(這並不困難,至少只要您對性能不太挑剔)。

東西可能如果您查看生產的組件(使用-S標誌),有時會更清晰。

+0

我必須使用_start而不是main,但是當我嘗試調用libc函數時,gcc不會發出抱怨。如果我刪除所有libc-calls,libc-link會消失嗎? – dkreuter 2010-04-01 07:50:51

+2

不是直接。如果你嘗試'gcc -v',你會看到'gcc'給連接器('* .o')提供了一些目標文件。鏈接器包含所有的對象文件。 「消失」只發生在圖書館('*。a'),因爲它們是鏈接器可以使用或不使用的對象文件的存儲庫。 – 2010-04-01 13:37:16