1. 程式人生 > >《oranges一個作業系統的實現》閱讀筆記三

《oranges一個作業系統的實現》閱讀筆記三

第三章工具的使用

1.如何除錯超過一個扇區的程式?

在這裡總結以下從第一章到第四章,書上所用各種工具的意義。 1)第一章直接用軟盤,用bochs載入軟盤,程式寫到軟盤的第一個扇區,bochs相當於一個實體機器,從軟盤第一個扇區讀取程式到0x7c00h,並跳轉到此處執行。(具體開機流程可以參考第一篇筆記) 2)第二章用軟盤的映象檔案充當虛擬的軟盤,並沒有突破引導扇區一個扇區容量的限制 3)第三章由於引導扇區512位元組的限制,限制了實驗程式的大小,而又暫時不想進入引導扇區載入其他程式進記憶體比如Loader的步驟,所以就暫時利用freedos這個作業系統,bochs通過利用freedos.img的第一個扇區當做引導扇區,先把CPU控制權交給freedos,freedos格式化我們實驗程式寫入的b.img為dos檔案系統格式,我們將自己的實驗程式拷貝到b.img(就是向檔案系統中拷貝個檔案)中,然後在freedos通過指令載入執行我們的實驗程式,利用了dos的檔案系統
4).第四章我們自己寫引導扇區,載入自己的Loader,要突破第一扇區,就得靠自己載入了,因為bios程式只負責將引導扇區的程式讀到0x7c00h中,然後就將控制權交給了引導扇區的程式。但如果我們自己去讀取程式的話,只能靠硬體軟盤,硬碟的物理劃分來讀取,一個扇區一個扇區的載入到程式,這限制了我們程式邊界的靈活性,要讀多個檔案的話也很複雜,這個時候就需要檔案系統的幫忙了,但鑑於我們還沒有自己的檔案系統,我們可以先用一個成熟的檔案系統FAT12,這樣我們就可以方便的將自己的Loader寫到軟盤的檔案系統FAT12裡,並在引導扇區程式裡方便靈活的找到它。 我本來是按照書上所說使用freedos來執行編譯的程式,但是想除錯32位彙編程式,並沒有找到好工具,根據網上所說我找到了TDdebug.exe,但是執行起來有問題(費了老大的勁又是重灌bochs又是找各種版本),結果最後還是不行,後來用了個Debug32.exe但是不知道如何現實X86架構下的各個暫存器,所以最後放棄了。(其實想想很有可能是freedos根本不支援X86下的東西,或者版本不對,反正搞得很不爽,所以就停了)。最後就用bochs除錯了,但是畢竟由於扇區限制和又還沒寫自己的Loader那。我的解決方案就是刪程式。在這裡我也建議大家如果沒有更好的除錯方法可以通過刪程式將程式精簡到512位元組內直接用bochs除錯。第一比較直觀沒有其他系統或者檔案系統的干擾,第二在前幾章還沒有很複雜的程式出現,只需要保留自己想實驗的程式碼,把沒用的刪除了,第三這樣更能考察對於書中程式碼的理解,如果只是把書上的原始碼原封不動的拿來除錯,會忽視很多問題,只有出現問題,才能解決問題,如果沒有出現任何問題也就證明沒有解決任何問題。

2. 為什麼用COM,ELF檔案?

COM, ELF檔案都只是中檔案格式,就是除了檔案內容有一些標識檔案型別的資訊,用來被解釋者讀取使用。COM是dos下可執行檔案格式,ELF是Linux下可執行檔案格式。前三章一直用com格式是因為一直在用dos載入執行程式,而後續我們要自己載入執行ELF檔案。可執行檔案除了程式碼外還會有其他的執行相關資訊,比如程式碼,資料的分段,將程式碼載入到記憶體什麼位置,這些資訊在編譯連結的時候寫進可執行檔案,載入的時候被載入程式讀取用來做相應處理。所以說載入程式和可執行檔案是配對的。採用ELF檔案是因為我們會在Linux開發自己的作業系統,所以生成的執行檔案就是ELF格式的,我們自己同樣要開發載入程式去讀取ELF檔案中的資訊。

3.什麼時候使用匯編語言什麼時候用C語言?

這個問題應該從技術發展的歷史角度看。剛開始程式設計師用匯編寫作業系統,但後來發現開發效率非常低下,所以發明了高階語言C語言,高階語言是為了開發通用軟體時的效率。但是高階語言受限於編譯器,主流的編譯器只能將C語言轉化為有限的彙編也就是彙編的一個子集,所以必然有一部分指令是沒辦法通過C語言實現的,這個時候就需要彙編了。

4.boot, loader, kernel都實現了什麼?

Boot是引導扇區程式碼,受限於512位元組大小限制,負責根據FAT12檔案系統找到Loader所在軟盤扇區位置,並將它載入到記憶體,將CPU控制權交給Loader。實現的是MBR程式的功能。但是使用了FAT12檔案系統這個現有的功能並未自己實現。 Loader是負責載入kernel進記憶體,並且進入保護模式,然後將kernel根據ELF program資訊將kernel載入不同的段,並且實現了分頁,最後將CPU控制權交給Kernel。所以Loader實現了程式載入器的功能。 Kernel就是我們的核心,作業系統的核心,程序管理,記憶體管理,磁碟管理等的實現處。

5.既然需要用到FAT12檔案系統還需要自己定義引導盤的盤頭資訊嗎?

這個問題的意思是既然我們需要將自己的軟盤格式化為FAT12格式,我們還需要定義下圖的FAT盤頭資訊嗎? 其實不需要了,因為反正我們都要將整個軟盤格式化成FAT12,因為我們沒有自己的檔案系統,格式化的時候,引導扇區就已經被寫入了上圖定義的那些資料了。
可以看到前面62個位元組就是所謂的軟盤BP頭資訊,所以boot.asm其實沒有必須定義這些資料,所以將 BS_OEMNameDB 'ForrestY'; OEM String, 必須 8 個位元組
改成Off_BS_OEMNAME  equ 3,其他資訊一樣的處理,這樣變數定義變成了常量,可以節省62個位元組的記憶體,這對於引導扇區512位元組可是很珍貴的,相應的使用語句 addbx, [BPB_BytsPerSec]需要變成addbx, [Off_BPB_BytsPerSec+7c00h],因為編譯器不會再幫我們計算偏移地址了,經測試程式可以正常執行。

6. 編譯,連結,載入,執行流程?

編譯器主要負責程式的翻譯,以及記憶體佈局等指導資訊和一些連結需要的符號表資訊。我們現在主要通過nasm編譯彙編程式,用gcc編譯C程式 連結主要是將多個獨立編譯的由編譯器生成的目標檔案和一些已經預編譯好的公共庫檔案,根據各自提供的符號表資訊合成最終的可執行檔案,我們現在連結過程用ld  載入主要是記憶體中負責將外部儲存裝置上的可執行檔案挪到記憶體中,並根據可執行檔案中的資訊,將不同的資料搬到不同的記憶體段中,我們現在載入靠自己寫的Loader屬於作業系統的一部分 作業系統載入完程式後,跳轉執行可執行檔案的第一條指令,CPU控制權交給可執行檔案