一步步编写操作系统 46 用c语言编写内核3
再把上節(jié)代碼貼出來,
1 //int main(void) { 2 int _start(void) { 3 while(1); 4 return 0; 5 }有沒有同學(xué)想過,這里寫一個_start函數(shù),讓其調(diào)用main函數(shù)如何?其實(shí)這是可以的,main函數(shù)并不是第一個函數(shù),它實(shí)際上也是被別人調(diào)用的,不過這是編譯器背后的策略啦,好奇心大的同學(xué)自己嘗試下吧。
雖然把函數(shù)名改成_start可以解決問題,但我們習(xí)慣于main函數(shù)做為主函數(shù),不習(xí)慣函數(shù)用_start,于是用了-e來指定起始的函數(shù)名為main,所以代碼才鏈接正常。
也許有同學(xué)想過,哎?我平時寫的程序也沒有_start啊,直接用gcc編譯后就能運(yùn)行,沒出過問題啊。是啊,確實(shí)如您所說,由于我也沒深入研究過,但咱們通過比較的方式,讓您自己悟出這里面的秘密。還是用上述代碼為例,gcc –o /tmp/test.bin kernel/main.c編譯鏈接,由于未加-c參數(shù),生成的test.bin不再是目標(biāo)文件而是可執(zhí)行文件。然后再用先編譯成目標(biāo)文件再鏈接成可執(zhí)行文件的方式,對比這兩個文件的區(qū)別。見圖
您看,test.bin是gcc直接生成的可執(zhí)行文件,它的大小是4586字節(jié)。而kernel.bin是經(jīng)過手動編譯、鏈接這兩個步驟完成的,其文件大小是1777字節(jié)。這兩個文件的體積可是差了幾乎2倍呢。再看看這兩個文件中的符號信息,還是用nm命令,如圖
test.bin中共有34個符號(wc –l命令是用來統(tǒng)計輸出的行數(shù),一個符號占用一行,故34個符號),由于輸出太長了,我們只截取了關(guān)鍵的部分,不過您看那些frame_dummy、data_start等,這并不是咱們代碼中存在的符號,這說明在編譯器在編譯過程中為咱們引用了別的代碼,這就是c運(yùn)行庫的功勞,目的是在調(diào)用main函數(shù)前做初始化環(huán)境等工作。您看,用白色方框圈出來的_start,這就是默認(rèn)的入口符號,鏈接器還是用到了它,它不是咱們提供的代碼,依然是運(yùn)行庫提供的,這也說明main函數(shù)不是第一個執(zhí)行的代碼,它一定是被其它代碼調(diào)用的,main函數(shù)在運(yùn)行庫代碼初始化完環(huán)境后才被調(diào)用。
咱們繼續(xù)看kernel.bin中的符號,一共就4行,盡管其中也包含了咱們不認(rèn)識的符號,但畢竟少得多,我們的程序更短小精干,而且確實(shí)沒有_start函數(shù)。這里添加了3個類型為A的符號,這表示它們的值是不變的。T表示是該符號是位于代碼段中,更多符號的意義請參考man nm。
其實(shí)上述代碼中要是換成匯編代碼的話,就是個jmp $,其大小不過是2字節(jié)的機(jī)器碼ebfe。除了編譯器自動添加的代碼外,一般情況下c語言編譯出來的程序也比匯編語言生成的程序體積大。可見,人們常說的匯編語言比c語言快,并不是匯編語言本身有多快(它也要變成機(jī)器指令后才能上cpu運(yùn)行),而是匯編語言對應(yīng)的機(jī)器指令是一對一,簡單直接可依賴,而c語言生成的機(jī)器指令是一對多,復(fù)雜間接略冗余。
好啦,關(guān)于內(nèi)核的部分咱們就此先打住,其實(shí)說這話我有點(diǎn)不好意思,您也看到啦,內(nèi)核代碼中就一個死循環(huán)而已,我們的內(nèi)核還沒有開始。咱們的內(nèi)核雖然離真正的內(nèi)核差得十萬八千里,但它目的是兩個:
后面我們將結(jié)合此簡單至極的c程序來學(xué)習(xí)有關(guān)elf方面的知識。
總結(jié)
以上是生活随笔為你收集整理的一步步编写操作系统 46 用c语言编写内核3的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 又一款高收益稳健理财要消失!想要收益率超
- 下一篇: 一步步编写操作系统 17 显存,显卡,显