2012-11-06 25 views
0

他們說,main()是一個像任何其他函數的功能,但「標記」作爲二進制內的入口點,操作系統可能會找到(不知道如何)並從那裏啓動程序。所以,我試圖找出更多關於這個功能。我做了什麼?我創建了這個代碼中一個簡單的.C文件:試圖瞭解與GCC和Windows的主要功能

int main(int argc, char **argv) { 
    return (0); 
} 

我保存的文件,安裝GCC編譯器(在Windows,MingW平臺環境),並創建一個批處理文件是這樣的:

gcc -c test.c -nostartfiles -nodefaultlibs -nostdlib -nostdinc -o test.o 
gcc -o test.exe -nostartfiles -nodefaultlibs -nostdlib -nostdinc -s -O2 test.o 
@%comspec% 

我這樣做是爲了獲得一個非常簡單的編譯器和鏈接器,沒有庫,沒有頭,只是編譯器。因此,編譯順利,但鏈接與此錯誤停止:

test.c:(.text+0xa): undefined reference to '___main' 
collect2.exe: error: Id returned 1 exit status 

我認爲,主要功能是通過鏈接器出口,但我相信,你並不需要與有關它的任何信息庫。但它看起來像它。在我的情況下,我認爲它必須是標準的GCC庫,所以我下載了它的源代碼並打開了這個文件:libgcc2.c 現在,我不知道這是否是主函數構建爲由GCC鏈接。事實上,我不明白海灣合作委員會如何使用主要功能。爲什麼鏈接器需要gcc標準庫? 要知道main?我希望這能讓我的問題更具體和明確。謝謝!

+0

你能從你的windows上運行'nm test.o'嗎?它會告訴你'test.o'中包含的符號 – Eregrith

+0

是的,有一個'___main'和'_main'符號(這很奇怪) – ali

回答

5

當GCC放在一起的所有對象文件(名爲test的名字。 o)和庫來組成一個二進制文件,它也預先設置一個小對象(通常是crt0.o或crt1.o),它負責調用你的main()。你可以看到GCC在做什麼,當你在命令行上添加-v

$ gcc -v -o test.exe test.o

信息crt0/CRT1做一些設置,然後調用到主。但鏈接器最終負責根據操作系統構建可執行文件。通過-v,您可以看到目標系統的一個選項。在我的情況下,它適用於Linux 64位:-m elf_x86_64。對於您的系統,這將是類似-m windows-m mingw

+0

謝謝,這真的很有幫助。 – ali

+0

O.K.因此crt0.o包含附加到可執行文件的平臺相關信息,以便Windows或任何其他O.S.可以根據自己的規則找到入口點,不是嗎? – ali

+0

@all請看我的更新。 –

1

的錯誤是因爲你使用這兩個選項:-nodefaultlibs -nostdlib

這些告訴GCC,它不應該對包含這實際上調用main()代碼libc.a/c.lib鏈接代碼。簡而言之,每個操作系統都略有不同,其中大多數人不關心C和main()。每種方法都有自己特殊的方式來啓動一個進程,並且其中大多數與C API不兼容。

因此,C開發人員的解決方案是將「膠水代碼」放入包含OS預期接口的C標準庫libc.a中,創建標準C環境(設置內存分配結構,使malloc()將映射操作系統的內存管理功能,建立了標準輸入輸出等),並最終調用main()

對於C開發人員來說,這意味着他們獲得了libc.a在他們的操作系統(與編譯器的二進制文件一起),他們並不需要關心如何安裝工程。

混淆的另一個來源是參考的名稱。在大多數系統中,main()符號名是_main(即一個下劃線),而__main是一個內部功能,通過設置代碼最終調用真正的main()

+0

謝謝,這是很多有用的信息。 – ali