隨著 OS 功能增加,代碼量迅速膨脹。今天的目標是將混亂的根目錄結構進行模組化重組,並引入 Makefile。這能確保編譯過程的一致性,並精確控制核心代碼在記憶體中的排列順序。
一個專業的 OS 專案需要清晰的層次感。我們將代碼劃分為「啟動區(Boot)」與「內核區(Kernel)」。
SmallOS/ ├── src/ # 原始碼目錄 │ ├── boot/ # 啟動相關 (boot.asm, gdt.asm, kernel_entry.asm, etc.) │ └── kernel/ # 內核相關 │ ├── cpu/ # CPU 底層 (IDT, GDT, Interrupts) │ ├── drivers/ # 硬體驅動 (VGA, Keyboard) │ └── kernel.c # 核心主程式 ├── build/ # 編譯輸出的中間物件 (.o) 與二進位檔 (.bin) ├── Makefile # 編譯控制文件 └── os-image.bin # 最終合成的磁碟鏡像
在 Day 6,我們手動執行了多條 gcc 與 ld 指令。當檔案變成 10 個、20 個時,手動操作極易出錯。Makefile 幫我們解決:
kernel_entry.o 永遠排在 kernel.bin 的最前面。make run 指令,自動完成編譯、拼接、啟動 QEMU。在這次更新的 Makefile 中,我們加入了一些 OS 開發專用的參數,這些參數能防止編譯器「自作聰明」:
m32: 強制產生 32 位元代碼,因為我們的核心目前運行在 32-bit 保護模式。ffreestanding: 告知編譯器「沒有標準庫」,不要試圖鏈結 stdio.h 等文件。fno-pic: 禁用位置無關代碼。內核需要絕對地址定位。fno-stack-protector: 禁用堆疊保護機制。這能避免編譯器要求連結到我們尚未實作的安全性函式庫。Ttext 0x1000: (Linker 參數) 這是最關鍵的,它告訴鏈結器:核心將被加載到記憶體 0x1000 處。